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
58 SafeRegistryHandle safe_handle;
60 object hive; // the RegistryHive if the key represents a base key
61 readonly string qname; // the fully qualified registry key name
62 readonly bool isRemoteRoot; // is an instance of a remote root key?
63 readonly bool isWritable; // is the key openen in writable mode
65 static readonly IRegistryApi RegistryApi;
69 if (Path.DirectorySeparatorChar == '\\')
70 RegistryApi = new Win32RegistryApi ();
72 RegistryApi = new UnixRegistryApi ();
76 /// Construct an instance of a root registry key entry.
78 internal RegistryKey (RegistryHive hiveId) : this (hiveId,
79 new IntPtr ((int) hiveId), false)
84 /// Construct an instance of a root registry key entry.
86 internal RegistryKey (RegistryHive hiveId, IntPtr keyHandle, bool remoteRoot)
90 qname = GetHiveName (hiveId);
91 isRemoteRoot = remoteRoot;
92 isWritable = true; // always consider root writable
96 /// Construct an instance of a registry key entry.
98 internal RegistryKey (object data, string keyName, bool writable)
102 isWritable = writable;
105 static internal bool IsEquals (RegistryKey a, RegistryKey b)
107 return a.hive == b.hive && a.handle == b.handle && a.qname == b.qname && a.isRemoteRoot == b.isRemoteRoot && a.isWritable == b.isWritable;
113 /// Dispose of registry key object. Close the
114 /// key if it's still open.
116 public void Dispose ()
118 GC.SuppressFinalize (this);
123 /// Get the fully qualified registry key name.
126 get { return qname; }
131 /// Flush the current registry state to disk.
135 RegistryApi.Flush (this);
140 /// Close the current registry key and flushes the state of the registry
147 // a handle to a remote hive must be closed, while one to a local
148 // hive should not be closed
149 if (!isRemoteRoot && IsRoot)
152 RegistryApi.Close (this);
159 /// get the number of sub-keys for this key
161 public int SubKeyCount {
163 AssertKeyStillValid ();
165 return RegistryApi.SubKeyCount (this);
171 /// get the number of values for this key
173 public int ValueCount {
175 AssertKeyStillValid ();
177 return RegistryApi.ValueCount (this);
182 [MonoTODO ("Not implemented in Unix")]
183 public SafeRegistryHandle Handle {
185 AssertKeyStillValid ();
187 if (safe_handle == null) {
188 IntPtr h = RegistryApi.GetHandle (this);
189 safe_handle = new SafeRegistryHandle (h, true);
197 [MonoLimitation ("View is ignored in Mono.")]
198 public RegistryView View {
200 return RegistryView.Default;
206 /// Set a registry value.
208 public void SetValue (string name, object value)
210 AssertKeyStillValid ();
213 throw new ArgumentNullException ("value");
216 AssertKeyNameLength (name);
219 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
221 RegistryApi.SetValue (this, name, value);
225 public void SetValue (string name, object value, RegistryValueKind valueKind)
227 AssertKeyStillValid ();
230 throw new ArgumentNullException ("value");
233 AssertKeyNameLength (name);
236 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
238 RegistryApi.SetValue (this, name, value, valueKind);
242 /// Open the sub key specified, for read access.
244 public RegistryKey OpenSubKey (string name)
246 return OpenSubKey (name, false);
251 /// Open the sub key specified.
253 public RegistryKey OpenSubKey (string name, bool writable)
255 AssertKeyStillValid ();
258 throw new ArgumentNullException ("name");
260 AssertKeyNameLength (name);
262 return RegistryApi.OpenSubKey (this, name, writable);
267 /// Get a registry value.
269 public object GetValue (string name)
271 return GetValue (name, null);
276 /// Get a registry value.
278 public object GetValue (string name, object defaultValue)
280 AssertKeyStillValid ();
282 return RegistryApi.GetValue (this, name, defaultValue,
283 RegistryValueOptions.None);
287 public object GetValue (string name, object defaultValue, RegistryValueOptions options)
289 AssertKeyStillValid ();
291 return RegistryApi.GetValue (this, name, defaultValue, options);
295 public RegistryValueKind GetValueKind (string name)
297 return RegistryApi.GetValueKind (this, name);
301 /// Create a sub key.
303 public RegistryKey CreateSubKey (string subkey)
305 AssertKeyStillValid ();
306 AssertKeyNameNotNull (subkey);
307 AssertKeyNameLength (subkey);
310 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
311 return RegistryApi.CreateSubKey (this, subkey);
315 [MonoLimitation ("permissionCheck is ignored in Mono")]
316 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck)
318 return CreateSubKey (subkey);
322 [MonoLimitation ("permissionCheck and registrySecurity are ignored in Mono")]
323 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistrySecurity registrySecurity)
325 return CreateSubKey (subkey);
329 [MonoLimitation ("permissionCheck is ignored in Mono")]
330 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistryOptions options)
332 AssertKeyStillValid ();
333 AssertKeyNameNotNull (subkey);
334 AssertKeyNameLength (subkey);
337 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
339 return RegistryApi.CreateSubKey (this, subkey, options);
343 [MonoLimitation ("permissionCheck and registrySecurity are ignored in Mono")]
344 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistryOptions registryOptions,
345 RegistrySecurity registrySecurity)
347 return CreateSubKey (subkey, permissionCheck, registryOptions);
352 /// Delete the specified subkey.
354 public void DeleteSubKey(string subkey)
356 DeleteSubKey (subkey, true);
361 /// Delete the specified subkey.
363 public void DeleteSubKey(string subkey, bool throwOnMissingSubKey)
365 AssertKeyStillValid ();
366 AssertKeyNameNotNull (subkey);
367 AssertKeyNameLength (subkey);
370 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
372 RegistryKey child = OpenSubKey (subkey);
375 if (throwOnMissingSubKey)
376 throw new ArgumentException ("Cannot delete a subkey tree"
377 + " because the subkey does not exist.");
381 if (child.SubKeyCount > 0){
382 throw new InvalidOperationException ("Registry key has subkeys"
383 + " and recursive removes are not supported by this method.");
388 RegistryApi.DeleteKey (this, subkey, throwOnMissingSubKey);
393 /// Delete a sub tree (node, and values alike).
395 public void DeleteSubKeyTree(string subkey)
397 DeleteSubKeyTree (subkey, true);
401 void DeleteSubKeyTree (string subkey, bool throwOnMissingSubKey)
403 // Note: this is done by deleting sub-nodes recursively.
404 // The preformance is not very good. There may be a
405 // better way to implement this.
407 AssertKeyStillValid ();
408 AssertKeyNameNotNull (subkey);
409 AssertKeyNameLength (subkey);
411 RegistryKey child = OpenSubKey (subkey, true);
413 if (!throwOnMissingSubKey)
416 throw new ArgumentException ("Cannot delete a subkey tree"
417 + " because the subkey does not exist.");
420 child.DeleteChildKeysAndValues ();
422 DeleteSubKey (subkey, false);
427 /// Delete a value from the registry.
429 public void DeleteValue(string name)
431 DeleteValue (name, true);
436 /// Delete a value from the registry.
438 public void DeleteValue(string name, bool throwOnMissingValue)
440 AssertKeyStillValid ();
443 throw new ArgumentNullException ("name");
446 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
448 RegistryApi.DeleteValue (this, name, throwOnMissingValue);
451 public RegistrySecurity GetAccessControl ()
453 return GetAccessControl (AccessControlSections.Owner |
454 AccessControlSections.Group |
455 AccessControlSections.Access);
458 public RegistrySecurity GetAccessControl (AccessControlSections includeSections)
460 return new RegistrySecurity (Name, includeSections);
465 /// Get the names of the sub keys.
467 public string[] GetSubKeyNames()
469 AssertKeyStillValid ();
471 return RegistryApi.GetSubKeyNames (this);
476 /// Get the names of values contained in this key.
478 public string[] GetValueNames()
480 AssertKeyStillValid ();
481 return RegistryApi.GetValueNames (this);
485 [SecurityPermission (SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
486 [MonoTODO ("Not implemented on unix")]
487 public static RegistryKey FromHandle (SafeRegistryHandle handle)
490 throw new ArgumentNullException ("handle");
492 return RegistryApi.FromHandle (handle);
496 [SecurityPermission (SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
497 [MonoTODO ("Not implemented on unix")]
498 public static RegistryKey FromHandle (SafeRegistryHandle handle, RegistryView view)
500 return FromHandle (handle);
504 [MonoTODO ("Not implemented on unix")]
505 public static RegistryKey OpenRemoteBaseKey(RegistryHive hKey,string machineName)
507 if (machineName == null)
508 throw new ArgumentNullException ("machineName");
509 return RegistryApi.OpenRemoteBaseKey (hKey, machineName);
513 [MonoTODO ("Not implemented on unix")]
514 public static RegistryKey OpenRemoteBaseKey (RegistryHive hKey, string machineName, RegistryView view)
516 if (machineName == null)
517 throw new ArgumentNullException ("machineName");
518 return RegistryApi.OpenRemoteBaseKey (hKey, machineName);
522 [MonoLimitation ("View is ignored in Mono")]
523 public static RegistryKey OpenBaseKey (RegistryHive hKey, RegistryView view)
526 case RegistryHive.ClassesRoot:
527 return Registry.ClassesRoot;
528 case RegistryHive.CurrentConfig:
529 return Registry.CurrentConfig;
530 case RegistryHive.CurrentUser:
531 return Registry.CurrentUser;
532 case RegistryHive.DynData:
533 return Registry.DynData;
534 case RegistryHive.LocalMachine:
535 return Registry.LocalMachine;
536 case RegistryHive.PerformanceData:
537 return Registry.PerformanceData;
538 case RegistryHive.Users:
539 return Registry.Users;
542 throw new ArgumentException ("hKey");
546 public RegistryKey OpenSubKey (string name, RegistryKeyPermissionCheck permissionCheck)
548 return OpenSubKey (name, permissionCheck == RegistryKeyPermissionCheck.ReadWriteSubTree);
552 [MonoLimitation ("rights are ignored in Mono")]
553 public RegistryKey OpenSubKey (string name, RegistryKeyPermissionCheck permissionCheck, RegistryRights rights)
555 return OpenSubKey (name, permissionCheck == RegistryKeyPermissionCheck.ReadWriteSubTree);
558 public void SetAccessControl (RegistrySecurity registrySecurity)
560 if (null == registrySecurity)
561 throw new ArgumentNullException ("registrySecurity");
563 registrySecurity.PersistModifications (Name);
568 /// Build a string representation of the registry key.
569 /// Conatins the fully qualified key name, and the Hex
570 /// representation of the registry key handle.
572 public override string ToString()
574 AssertKeyStillValid ();
576 return RegistryApi.ToString (this);
579 #endregion // PublicAPI
581 internal bool IsRoot {
582 get { return hive != null; }
585 private bool IsWritable {
586 get { return isWritable; }
589 internal RegistryHive Hive {
592 throw new NotSupportedException ();
593 return (RegistryHive) hive;
597 // returns the key handle for the win32 implementation and the
598 // KeyHandler for the unix implementation
599 internal object InternalHandle {
600 get { return handle; }
604 /// validate that the registry key handle is still usable.
606 private void AssertKeyStillValid ()
609 throw new ObjectDisposedException ("Microsoft.Win32.RegistryKey");
614 /// validate that the registry key handle is still usable, and
615 /// that the 'subKeyName' is not null.
617 private void AssertKeyNameNotNull (string subKeyName)
619 if (subKeyName == null)
620 throw new ArgumentNullException ("name");
623 private void AssertKeyNameLength (string name)
625 if (name.Length > 255)
626 throw new ArgumentException ("Name of registry key cannot be greater than 255 characters");
630 /// Utility method to delelte a key's sub keys and values.
631 /// This method removes a level of indirection when deleting
634 private void DeleteChildKeysAndValues ()
639 string[] subKeys = GetSubKeyNames ();
640 foreach (string subKey in subKeys)
642 RegistryKey sub = OpenSubKey (subKey, true);
643 sub.DeleteChildKeysAndValues ();
645 DeleteSubKey (subKey, false);
648 string[] values = GetValueNames ();
649 foreach (string value in values) {
650 DeleteValue (value, false);
655 /// decode a byte array as a string, and strip trailing nulls
657 static internal string DecodeString (byte[] data)
659 string stringRep = Encoding.Unicode.GetString (data);
660 int idx = stringRep.IndexOf ('\0');
662 stringRep = stringRep.TrimEnd ('\0');
666 static internal IOException CreateMarkedForDeletionException ()
668 throw new IOException ("Illegal operation attempted on a"
669 + " registry key that has been marked for deletion.");
672 static string GetHiveName (RegistryHive hive)
675 case RegistryHive.ClassesRoot:
676 return "HKEY_CLASSES_ROOT";
677 case RegistryHive.CurrentConfig:
678 return "HKEY_CURRENT_CONFIG";
679 case RegistryHive.CurrentUser:
680 return "HKEY_CURRENT_USER";
681 case RegistryHive.DynData:
682 return "HKEY_DYN_DATA";
683 case RegistryHive.LocalMachine:
684 return "HKEY_LOCAL_MACHINE";
685 case RegistryHive.PerformanceData:
686 return "HKEY_PERFORMANCE_DATA";
687 case RegistryHive.Users:
691 throw new NotImplementedException (string.Format (
692 "Registry hive '{0}' is not implemented.", hive.ToString ()));