2 // RegistryKey.cs: a single node in the Windows registry
5 // Miguel de Icaza (miguel@ximian.com)
6 // Erik LeBel (eriklebel@yahoo.ca)
7 // Gert Driesen (drieseng@users.sourceforge.net)
10 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System.Collections;
37 using System.Diagnostics;
38 using System.Runtime.InteropServices;
39 using System.Security;
41 using System.Security.AccessControl;
42 using System.Security.Permissions;
43 using Microsoft.Win32.SafeHandles;
45 namespace Microsoft.Win32
48 /// Wrapper class for Windows Registry Entry.
51 public sealed class RegistryKey : MarshalByRefObject, IDisposable
54 // This represents the backend data, used when creating the
59 SafeRegistryHandle safe_handle;
62 object hive; // the RegistryHive if the key represents a base key
63 readonly string qname; // the fully qualified registry key name
64 readonly bool isRemoteRoot; // is an instance of a remote root key?
65 readonly bool isWritable; // is the key openen in writable mode
67 static readonly IRegistryApi RegistryApi;
71 if (Path.DirectorySeparatorChar == '\\')
72 RegistryApi = new Win32RegistryApi ();
74 RegistryApi = new UnixRegistryApi ();
78 /// Construct an instance of a root registry key entry.
80 internal RegistryKey (RegistryHive hiveId) : this (hiveId,
81 new IntPtr ((int) hiveId), false)
86 /// Construct an instance of a root registry key entry.
88 internal RegistryKey (RegistryHive hiveId, IntPtr keyHandle, bool remoteRoot)
92 qname = GetHiveName (hiveId);
93 isRemoteRoot = remoteRoot;
94 isWritable = true; // always consider root writable
98 /// Construct an instance of a registry key entry.
100 internal RegistryKey (object data, string keyName, bool writable)
104 isWritable = writable;
110 /// Dispose of registry key object. Close the
111 /// key if it's still open.
114 public void Dispose ()
116 void IDisposable.Dispose ()
119 GC.SuppressFinalize (this);
125 /// Final cleanup of registry key object. Close the
126 /// key if it's still open.
135 /// Get the fully qualified registry key name.
138 get { return qname; }
143 /// Flush the current registry state to disk.
147 RegistryApi.Flush (this);
152 /// Close the current registry key and flushes the state of the registry
159 // a handle to a remote hive must be closed, while one to a local
160 // hive should not be closed
161 if (!isRemoteRoot && IsRoot)
164 RegistryApi.Close (this);
173 /// get the number of sub-keys for this key
175 public int SubKeyCount {
177 AssertKeyStillValid ();
179 return RegistryApi.SubKeyCount (this);
185 /// get the number of values for this key
187 public int ValueCount {
189 AssertKeyStillValid ();
191 return RegistryApi.ValueCount (this);
197 [MonoTODO ("Not implemented in Unix")]
198 public SafeRegistryHandle Handle {
200 AssertKeyStillValid ();
202 if (safe_handle == null) {
203 IntPtr h = RegistryApi.GetHandle (this);
204 safe_handle = new SafeRegistryHandle (h, true);
212 [MonoLimitation ("View is ignored in Mono.")]
213 public RegistryView View {
215 return RegistryView.Default;
222 /// Set a registry value.
224 public void SetValue (string name, object value)
226 AssertKeyStillValid ();
229 throw new ArgumentNullException ("value");
232 AssertKeyNameLength (name);
235 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
237 RegistryApi.SetValue (this, name, value);
241 public void SetValue (string name, object value, RegistryValueKind valueKind)
243 AssertKeyStillValid ();
246 throw new ArgumentNullException ("value");
249 AssertKeyNameLength (name);
252 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
254 RegistryApi.SetValue (this, name, value, valueKind);
258 /// Open the sub key specified, for read access.
260 public RegistryKey OpenSubKey (string name)
262 return OpenSubKey (name, false);
267 /// Open the sub key specified.
269 public RegistryKey OpenSubKey (string name, bool writable)
271 AssertKeyStillValid ();
274 throw new ArgumentNullException ("name");
276 AssertKeyNameLength (name);
278 return RegistryApi.OpenSubKey (this, name, writable);
283 /// Get a registry value.
285 public object GetValue (string name)
287 return GetValue (name, null);
292 /// Get a registry value.
294 public object GetValue (string name, object defaultValue)
296 AssertKeyStillValid ();
298 return RegistryApi.GetValue (this, name, defaultValue,
299 RegistryValueOptions.None);
303 public object GetValue (string name, object defaultValue, RegistryValueOptions options)
305 AssertKeyStillValid ();
307 return RegistryApi.GetValue (this, name, defaultValue, options);
311 public RegistryValueKind GetValueKind (string name)
313 return RegistryApi.GetValueKind (this, name);
317 /// Create a sub key.
319 public RegistryKey CreateSubKey (string subkey)
321 AssertKeyStillValid ();
322 AssertKeyNameNotNull (subkey);
323 AssertKeyNameLength (subkey);
326 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
327 return RegistryApi.CreateSubKey (this, subkey);
331 [MonoLimitation ("permissionCheck is ignored in Mono")]
332 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck)
334 return CreateSubKey (subkey);
338 [MonoLimitation ("permissionCheck and registrySecurity are ignored in Mono")]
339 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistrySecurity registrySecurity)
341 return CreateSubKey (subkey);
346 [MonoLimitation ("permissionCheck is ignored in Mono")]
347 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistryOptions options)
349 AssertKeyStillValid ();
350 AssertKeyNameNotNull (subkey);
351 AssertKeyNameLength (subkey);
354 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
356 return RegistryApi.CreateSubKey (this, subkey, options);
360 [MonoLimitation ("permissionCheck and registrySecurity are ignored in Mono")]
361 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistryOptions registryOptions,
362 RegistrySecurity registrySecurity)
364 return CreateSubKey (subkey, permissionCheck, registryOptions);
370 /// Delete the specified subkey.
372 public void DeleteSubKey(string subkey)
374 DeleteSubKey (subkey, true);
379 /// Delete the specified subkey.
381 public void DeleteSubKey(string subkey, bool throwOnMissingSubKey)
383 AssertKeyStillValid ();
384 AssertKeyNameNotNull (subkey);
385 AssertKeyNameLength (subkey);
388 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
390 RegistryKey child = OpenSubKey (subkey);
393 if (throwOnMissingSubKey)
394 throw new ArgumentException ("Cannot delete a subkey tree"
395 + " because the subkey does not exist.");
399 if (child.SubKeyCount > 0){
400 throw new InvalidOperationException ("Registry key has subkeys"
401 + " and recursive removes are not supported by this method.");
406 RegistryApi.DeleteKey (this, subkey, throwOnMissingSubKey);
411 /// Delete a sub tree (node, and values alike).
413 public void DeleteSubKeyTree(string subkey)
415 DeleteSubKeyTree (subkey, true);
421 void DeleteSubKeyTree (string subkey, bool throwOnMissingSubKey)
423 // Note: this is done by deleting sub-nodes recursively.
424 // The preformance is not very good. There may be a
425 // better way to implement this.
427 AssertKeyStillValid ();
428 AssertKeyNameNotNull (subkey);
429 AssertKeyNameLength (subkey);
431 RegistryKey child = OpenSubKey (subkey, true);
433 if (!throwOnMissingSubKey)
436 throw new ArgumentException ("Cannot delete a subkey tree"
437 + " because the subkey does not exist.");
440 child.DeleteChildKeysAndValues ();
442 DeleteSubKey (subkey, false);
447 /// Delete a value from the registry.
449 public void DeleteValue(string name)
451 DeleteValue (name, true);
456 /// Delete a value from the registry.
458 public void DeleteValue(string name, bool throwOnMissingValue)
460 AssertKeyStillValid ();
463 throw new ArgumentNullException ("name");
466 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
468 RegistryApi.DeleteValue (this, name, throwOnMissingValue);
471 public RegistrySecurity GetAccessControl ()
473 return GetAccessControl (AccessControlSections.Owner |
474 AccessControlSections.Group |
475 AccessControlSections.Access);
478 public RegistrySecurity GetAccessControl (AccessControlSections includeSections)
480 return new RegistrySecurity (Name, includeSections);
485 /// Get the names of the sub keys.
487 public string[] GetSubKeyNames()
489 AssertKeyStillValid ();
491 return RegistryApi.GetSubKeyNames (this);
496 /// Get the names of values contained in this key.
498 public string[] GetValueNames()
500 AssertKeyStillValid ();
501 return RegistryApi.GetValueNames (this);
506 [SecurityPermission (SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
507 [MonoTODO ("Not implemented on unix")]
508 public static RegistryKey FromHandle (SafeRegistryHandle handle)
511 throw new ArgumentNullException ("handle");
513 return RegistryApi.FromHandle (handle);
517 [SecurityPermission (SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
518 [MonoTODO ("Not implemented on unix")]
519 public static RegistryKey FromHandle (SafeRegistryHandle handle, RegistryView view)
521 return FromHandle (handle);
526 [MonoTODO ("Not implemented on unix")]
527 public static RegistryKey OpenRemoteBaseKey(RegistryHive hKey,string machineName)
529 if (machineName == null)
530 throw new ArgumentNullException ("machineName");
531 return RegistryApi.OpenRemoteBaseKey (hKey, machineName);
536 [MonoTODO ("Not implemented on unix")]
537 public static RegistryKey OpenRemoteBaseKey (RegistryHive hKey, string machineName, RegistryView view)
539 if (machineName == null)
540 throw new ArgumentNullException ("machineName");
541 return RegistryApi.OpenRemoteBaseKey (hKey, machineName);
545 [MonoLimitation ("View is ignored in Mono")]
546 public static RegistryKey OpenBaseKey (RegistryHive hKey, RegistryView view)
549 case RegistryHive.ClassesRoot:
550 return Registry.ClassesRoot;
551 case RegistryHive.CurrentConfig:
552 return Registry.CurrentConfig;
553 case RegistryHive.CurrentUser:
554 return Registry.CurrentUser;
555 case RegistryHive.DynData:
556 return Registry.DynData;
557 case RegistryHive.LocalMachine:
558 return Registry.LocalMachine;
559 case RegistryHive.PerformanceData:
560 return Registry.PerformanceData;
561 case RegistryHive.Users:
562 return Registry.Users;
565 throw new ArgumentException ("hKey");
570 public RegistryKey OpenSubKey (string name, RegistryKeyPermissionCheck permissionCheck)
572 return OpenSubKey (name, permissionCheck == RegistryKeyPermissionCheck.ReadWriteSubTree);
576 [MonoLimitation ("rights are ignored in Mono")]
577 public RegistryKey OpenSubKey (string name, RegistryKeyPermissionCheck permissionCheck, RegistryRights rights)
579 return OpenSubKey (name, permissionCheck == RegistryKeyPermissionCheck.ReadWriteSubTree);
582 public void SetAccessControl (RegistrySecurity registrySecurity)
584 if (null == registrySecurity)
585 throw new ArgumentNullException ("registrySecurity");
587 registrySecurity.PersistModifications (Name);
592 /// Build a string representation of the registry key.
593 /// Conatins the fully qualified key name, and the Hex
594 /// representation of the registry key handle.
596 public override string ToString()
598 AssertKeyStillValid ();
600 return RegistryApi.ToString (this);
603 #endregion // PublicAPI
605 internal bool IsRoot {
606 get { return hive != null; }
609 private bool IsWritable {
610 get { return isWritable; }
613 internal RegistryHive Hive {
616 throw new NotSupportedException ();
617 return (RegistryHive) hive;
621 // returns the key handle for the win32 implementation and the
622 // KeyHandler for the unix implementation
623 internal object InternalHandle {
624 get { return handle; }
628 /// validate that the registry key handle is still usable.
630 private void AssertKeyStillValid ()
633 throw new ObjectDisposedException ("Microsoft.Win32.RegistryKey");
638 /// validate that the registry key handle is still usable, and
639 /// that the 'subKeyName' is not null.
641 private void AssertKeyNameNotNull (string subKeyName)
643 if (subKeyName == null)
644 throw new ArgumentNullException ("name");
647 private void AssertKeyNameLength (string name)
649 if (name.Length > 255)
650 throw new ArgumentException ("Name of registry key cannot be greater than 255 characters");
654 /// Utility method to delelte a key's sub keys and values.
655 /// This method removes a level of indirection when deleting
658 private void DeleteChildKeysAndValues ()
663 string[] subKeys = GetSubKeyNames ();
664 foreach (string subKey in subKeys)
666 RegistryKey sub = OpenSubKey (subKey, true);
667 sub.DeleteChildKeysAndValues ();
669 DeleteSubKey (subKey, false);
672 string[] values = GetValueNames ();
673 foreach (string value in values) {
674 DeleteValue (value, false);
679 /// decode a byte array as a string, and strip trailing nulls
681 static internal string DecodeString (byte[] data)
683 string stringRep = Encoding.Unicode.GetString (data);
684 int idx = stringRep.IndexOf ('\0');
686 stringRep = stringRep.TrimEnd ('\0');
690 static internal IOException CreateMarkedForDeletionException ()
692 throw new IOException ("Illegal operation attempted on a"
693 + " registry key that has been marked for deletion.");
696 static string GetHiveName (RegistryHive hive)
699 case RegistryHive.ClassesRoot:
700 return "HKEY_CLASSES_ROOT";
701 case RegistryHive.CurrentConfig:
702 return "HKEY_CURRENT_CONFIG";
703 case RegistryHive.CurrentUser:
704 return "HKEY_CURRENT_USER";
705 case RegistryHive.DynData:
706 return "HKEY_DYN_DATA";
707 case RegistryHive.LocalMachine:
708 return "HKEY_LOCAL_MACHINE";
709 case RegistryHive.PerformanceData:
710 return "HKEY_PERFORMANCE_DATA";
711 case RegistryHive.Users:
715 throw new NotImplementedException (string.Format (
716 "Registry hive '{0}' is not implemented.", hive.ToString ()));