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.
34 using System.Collections;
35 using System.Diagnostics;
36 using System.Runtime.InteropServices;
37 using System.Security;
39 using System.Security.AccessControl;
40 using System.Security.Permissions;
41 using Microsoft.Win32.SafeHandles;
43 namespace Microsoft.Win32
46 #if MOBILE && !WIN_PLATFORM
47 public sealed class RegistryKey : IDisposable
49 internal RegistryKey (RegistryHive hiveId)
51 throw new PlatformNotSupportedException ();
54 public void Dispose ()
58 public RegistryKey CreateSubKey (string subkey)
60 throw new PlatformNotSupportedException ();
63 public RegistryKey CreateSubKey (String subkey, bool writable)
65 throw new PlatformNotSupportedException ();
68 public RegistryKey CreateSubKey (String subkey, bool writable, RegistryOptions options)
70 throw new PlatformNotSupportedException ();
73 public void DeleteSubKey (string subkey)
77 public void DeleteSubKey (string subkey, bool throwOnMissingSubKey)
81 public void DeleteSubKeyTree (string subkey)
85 public void DeleteSubKeyTree (string subkey, bool throwOnMissingSubKey)
89 public void DeleteValue (string name)
93 public void DeleteValue (string name, bool throwOnMissingValue)
101 public static RegistryKey FromHandle (SafeRegistryHandle handle)
103 throw new PlatformNotSupportedException ();
106 public static RegistryKey FromHandle (SafeRegistryHandle handle, RegistryView view)
108 throw new PlatformNotSupportedException ();
111 public string[] GetSubKeyNames ()
113 throw new PlatformNotSupportedException ();
116 public object GetValue (string name)
118 throw new PlatformNotSupportedException ();
121 public object GetValue (string name, object defaultValue)
123 throw new PlatformNotSupportedException ();
126 public object GetValue (string name, object defaultValue, RegistryValueOptions options)
128 throw new PlatformNotSupportedException ();
131 public RegistryValueKind GetValueKind (string name)
133 throw new PlatformNotSupportedException ();
136 public string[] GetValueNames ()
138 throw new PlatformNotSupportedException ();
141 public static RegistryKey OpenBaseKey (RegistryHive hKey, RegistryView view)
143 throw new PlatformNotSupportedException ();
146 public RegistryKey OpenSubKey (string name)
148 throw new PlatformNotSupportedException ();
151 public RegistryKey OpenSubKey (string name, bool writable)
153 throw new PlatformNotSupportedException ();
156 public RegistryKey OpenSubKey (string name, RegistryRights rights)
158 throw new PlatformNotSupportedException ();
161 public void SetValue (string name, object value)
165 public void SetValue (string name, object value, RegistryValueKind valueKind)
169 public SafeRegistryHandle Handle {
170 get { throw new PlatformNotSupportedException (); }
174 get { throw new PlatformNotSupportedException (); }
177 public int SubKeyCount {
178 get { throw new PlatformNotSupportedException (); }
181 public int ValueCount {
182 get { throw new PlatformNotSupportedException (); }
185 public RegistryView View {
186 get { throw new PlatformNotSupportedException (); }
191 /// Wrapper class for Windows Registry Entry.
194 public sealed class RegistryKey : MarshalByRefObject, IDisposable
197 // This represents the backend data, used when creating the
198 // RegistryKey object
201 SafeRegistryHandle safe_handle;
203 object hive; // the RegistryHive if the key represents a base key
204 readonly string qname; // the fully qualified registry key name
205 readonly bool isRemoteRoot; // is an instance of a remote root key?
206 readonly bool isWritable; // is the key openen in writable mode
208 static readonly IRegistryApi RegistryApi;
210 static RegistryKey ()
213 if (Path.DirectorySeparatorChar == '\\')
214 RegistryApi = new Win32RegistryApi ();
217 RegistryApi = new UnixRegistryApi ();
221 /// Construct an instance of a root registry key entry.
223 internal RegistryKey (RegistryHive hiveId) : this (hiveId,
224 new IntPtr ((int) hiveId), false)
229 /// Construct an instance of a root registry key entry.
231 internal RegistryKey (RegistryHive hiveId, IntPtr keyHandle, bool remoteRoot)
235 qname = GetHiveName (hiveId);
236 isRemoteRoot = remoteRoot;
237 isWritable = true; // always consider root writable
241 /// Construct an instance of a registry key entry.
243 internal RegistryKey (object data, string keyName, bool writable)
247 isWritable = writable;
250 static internal bool IsEquals (RegistryKey a, RegistryKey b)
252 return a.hive == b.hive && a.handle == b.handle && a.qname == b.qname && a.isRemoteRoot == b.isRemoteRoot && a.isWritable == b.isWritable;
258 /// Dispose of registry key object. Close the
259 /// key if it's still open.
261 public void Dispose ()
263 GC.SuppressFinalize (this);
268 /// Get the fully qualified registry key name.
271 get { return qname; }
276 /// Flush the current registry state to disk.
280 RegistryApi.Flush (this);
285 /// Close the current registry key and flushes the state of the registry
292 // a handle to a remote hive must be closed, while one to a local
293 // hive should not be closed
294 if (!isRemoteRoot && IsRoot)
297 RegistryApi.Close (this);
304 /// get the number of sub-keys for this key
306 public int SubKeyCount {
308 AssertKeyStillValid ();
310 return RegistryApi.SubKeyCount (this);
316 /// get the number of values for this key
318 public int ValueCount {
320 AssertKeyStillValid ();
322 return RegistryApi.ValueCount (this);
327 [MonoTODO ("Not implemented in Unix")]
328 public SafeRegistryHandle Handle {
330 AssertKeyStillValid ();
332 if (safe_handle == null) {
333 IntPtr h = RegistryApi.GetHandle (this);
334 safe_handle = new SafeRegistryHandle (h, true);
342 [MonoLimitation ("View is ignored in Mono.")]
343 public RegistryView View {
345 return RegistryView.Default;
351 /// Set a registry value.
353 public void SetValue (string name, object value)
355 AssertKeyStillValid ();
358 throw new ArgumentNullException ("value");
361 AssertKeyNameLength (name);
364 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
366 RegistryApi.SetValue (this, name, value);
370 public void SetValue (string name, object value, RegistryValueKind valueKind)
372 AssertKeyStillValid ();
375 throw new ArgumentNullException ("value");
378 AssertKeyNameLength (name);
381 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
383 RegistryApi.SetValue (this, name, value, valueKind);
387 /// Open the sub key specified, for read access.
389 public RegistryKey OpenSubKey (string name)
391 return OpenSubKey (name, false);
396 /// Open the sub key specified.
398 public RegistryKey OpenSubKey (string name, bool writable)
400 AssertKeyStillValid ();
403 throw new ArgumentNullException ("name");
405 AssertKeyNameLength (name);
407 return RegistryApi.OpenSubKey (this, name, writable);
412 /// Get a registry value.
414 public object GetValue (string name)
416 return GetValue (name, null);
421 /// Get a registry value.
423 public object GetValue (string name, object defaultValue)
425 AssertKeyStillValid ();
427 return RegistryApi.GetValue (this, name, defaultValue,
428 RegistryValueOptions.None);
432 public object GetValue (string name, object defaultValue, RegistryValueOptions options)
434 AssertKeyStillValid ();
436 return RegistryApi.GetValue (this, name, defaultValue, options);
440 public RegistryValueKind GetValueKind (string name)
442 return RegistryApi.GetValueKind (this, name);
446 /// Create a sub key.
448 public RegistryKey CreateSubKey (string subkey)
450 AssertKeyStillValid ();
451 AssertKeyNameNotNull (subkey);
452 AssertKeyNameLength (subkey);
455 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
456 return RegistryApi.CreateSubKey (this, subkey);
460 [MonoLimitation ("permissionCheck is ignored in Mono")]
461 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck)
463 return CreateSubKey (subkey);
467 [MonoLimitation ("permissionCheck and registrySecurity are ignored in Mono")]
468 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistrySecurity registrySecurity)
470 return CreateSubKey (subkey);
474 [MonoLimitation ("permissionCheck is ignored in Mono")]
475 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistryOptions options)
477 AssertKeyStillValid ();
478 AssertKeyNameNotNull (subkey);
479 AssertKeyNameLength (subkey);
482 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
484 return RegistryApi.CreateSubKey (this, subkey, options);
488 [MonoLimitation ("permissionCheck and registrySecurity are ignored in Mono")]
489 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistryOptions registryOptions,
490 RegistrySecurity registrySecurity)
492 return CreateSubKey (subkey, permissionCheck, registryOptions);
496 public RegistryKey CreateSubKey (string subkey, bool writable)
498 return CreateSubKey (subkey, writable ? RegistryKeyPermissionCheck.ReadWriteSubTree : RegistryKeyPermissionCheck.ReadSubTree);
502 public RegistryKey CreateSubKey (string subkey, bool writable, RegistryOptions options)
504 return CreateSubKey (subkey, writable ? RegistryKeyPermissionCheck.ReadWriteSubTree : RegistryKeyPermissionCheck.ReadSubTree, options);
508 /// Delete the specified subkey.
510 public void DeleteSubKey(string subkey)
512 DeleteSubKey (subkey, true);
517 /// Delete the specified subkey.
519 public void DeleteSubKey(string subkey, bool throwOnMissingSubKey)
521 AssertKeyStillValid ();
522 AssertKeyNameNotNull (subkey);
523 AssertKeyNameLength (subkey);
526 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
528 RegistryKey child = OpenSubKey (subkey);
531 if (throwOnMissingSubKey)
532 throw new ArgumentException ("Cannot delete a subkey tree"
533 + " because the subkey does not exist.");
537 if (child.SubKeyCount > 0){
538 throw new InvalidOperationException ("Registry key has subkeys"
539 + " and recursive removes are not supported by this method.");
544 RegistryApi.DeleteKey (this, subkey, throwOnMissingSubKey);
549 /// Delete a sub tree (node, and values alike).
551 public void DeleteSubKeyTree(string subkey)
553 DeleteSubKeyTree (subkey, true);
557 void DeleteSubKeyTree (string subkey, bool throwOnMissingSubKey)
559 // Note: this is done by deleting sub-nodes recursively.
560 // The preformance is not very good. There may be a
561 // better way to implement this.
563 AssertKeyStillValid ();
564 AssertKeyNameNotNull (subkey);
565 AssertKeyNameLength (subkey);
567 RegistryKey child = OpenSubKey (subkey, true);
569 if (!throwOnMissingSubKey)
572 throw new ArgumentException ("Cannot delete a subkey tree"
573 + " because the subkey does not exist.");
576 child.DeleteChildKeysAndValues ();
578 DeleteSubKey (subkey, false);
583 /// Delete a value from the registry.
585 public void DeleteValue(string name)
587 DeleteValue (name, true);
592 /// Delete a value from the registry.
594 public void DeleteValue(string name, bool throwOnMissingValue)
596 AssertKeyStillValid ();
599 throw new ArgumentNullException ("name");
602 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
604 RegistryApi.DeleteValue (this, name, throwOnMissingValue);
607 public RegistrySecurity GetAccessControl ()
609 return GetAccessControl (AccessControlSections.Owner |
610 AccessControlSections.Group |
611 AccessControlSections.Access);
614 public RegistrySecurity GetAccessControl (AccessControlSections includeSections)
616 return new RegistrySecurity (Name, includeSections);
621 /// Get the names of the sub keys.
623 public string[] GetSubKeyNames()
625 AssertKeyStillValid ();
627 return RegistryApi.GetSubKeyNames (this);
632 /// Get the names of values contained in this key.
634 public string[] GetValueNames()
636 AssertKeyStillValid ();
637 return RegistryApi.GetValueNames (this);
641 [SecurityPermission (SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
642 [MonoTODO ("Not implemented on unix")]
643 public static RegistryKey FromHandle (SafeRegistryHandle handle)
646 throw new ArgumentNullException ("handle");
648 return RegistryApi.FromHandle (handle);
652 [SecurityPermission (SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
653 [MonoTODO ("Not implemented on unix")]
654 public static RegistryKey FromHandle (SafeRegistryHandle handle, RegistryView view)
656 return FromHandle (handle);
660 [MonoTODO ("Not implemented on unix")]
661 public static RegistryKey OpenRemoteBaseKey(RegistryHive hKey,string machineName)
663 if (machineName == null)
664 throw new ArgumentNullException ("machineName");
665 return RegistryApi.OpenRemoteBaseKey (hKey, machineName);
669 [MonoTODO ("Not implemented on unix")]
670 public static RegistryKey OpenRemoteBaseKey (RegistryHive hKey, string machineName, RegistryView view)
672 if (machineName == null)
673 throw new ArgumentNullException ("machineName");
674 return RegistryApi.OpenRemoteBaseKey (hKey, machineName);
678 [MonoLimitation ("View is ignored in Mono")]
679 public static RegistryKey OpenBaseKey (RegistryHive hKey, RegistryView view)
682 case RegistryHive.ClassesRoot:
683 return Registry.ClassesRoot;
684 case RegistryHive.CurrentConfig:
685 return Registry.CurrentConfig;
686 case RegistryHive.CurrentUser:
687 return Registry.CurrentUser;
688 case RegistryHive.DynData:
689 return Registry.DynData;
690 case RegistryHive.LocalMachine:
691 return Registry.LocalMachine;
692 case RegistryHive.PerformanceData:
693 return Registry.PerformanceData;
694 case RegistryHive.Users:
695 return Registry.Users;
698 throw new ArgumentException ("hKey");
702 public RegistryKey OpenSubKey (string name, RegistryKeyPermissionCheck permissionCheck)
704 return OpenSubKey (name, permissionCheck == RegistryKeyPermissionCheck.ReadWriteSubTree);
708 [MonoLimitation ("rights are ignored in Mono")]
709 public RegistryKey OpenSubKey (string name, RegistryRights rights)
711 return OpenSubKey (name);
715 [MonoLimitation ("rights are ignored in Mono")]
716 public RegistryKey OpenSubKey (string name, RegistryKeyPermissionCheck permissionCheck, RegistryRights rights)
718 return OpenSubKey (name, permissionCheck == RegistryKeyPermissionCheck.ReadWriteSubTree);
721 public void SetAccessControl (RegistrySecurity registrySecurity)
723 if (null == registrySecurity)
724 throw new ArgumentNullException ("registrySecurity");
726 registrySecurity.PersistModifications (Name);
731 /// Build a string representation of the registry key.
732 /// Conatins the fully qualified key name, and the Hex
733 /// representation of the registry key handle.
735 public override string ToString()
737 AssertKeyStillValid ();
739 return RegistryApi.ToString (this);
742 #endregion // PublicAPI
744 internal bool IsRoot {
745 get { return hive != null; }
748 private bool IsWritable {
749 get { return isWritable; }
752 internal RegistryHive Hive {
755 throw new NotSupportedException ();
756 return (RegistryHive) hive;
760 // returns the key handle for the win32 implementation and the
761 // KeyHandler for the unix implementation
762 internal object InternalHandle {
763 get { return handle; }
767 /// validate that the registry key handle is still usable.
769 private void AssertKeyStillValid ()
772 throw new ObjectDisposedException ("Microsoft.Win32.RegistryKey");
777 /// validate that the registry key handle is still usable, and
778 /// that the 'subKeyName' is not null.
780 private void AssertKeyNameNotNull (string subKeyName)
782 if (subKeyName == null)
783 throw new ArgumentNullException ("name");
786 private void AssertKeyNameLength (string name)
788 if (name.Length > 255)
789 throw new ArgumentException ("Name of registry key cannot be greater than 255 characters");
793 /// Utility method to delelte a key's sub keys and values.
794 /// This method removes a level of indirection when deleting
797 private void DeleteChildKeysAndValues ()
802 string[] subKeys = GetSubKeyNames ();
803 foreach (string subKey in subKeys)
805 RegistryKey sub = OpenSubKey (subKey, true);
806 sub.DeleteChildKeysAndValues ();
808 DeleteSubKey (subKey, false);
811 string[] values = GetValueNames ();
812 foreach (string value in values) {
813 DeleteValue (value, false);
818 /// decode a byte array as a string, and strip trailing nulls
820 static internal string DecodeString (byte[] data)
822 string stringRep = Encoding.Unicode.GetString (data);
823 int idx = stringRep.IndexOf ('\0');
825 stringRep = stringRep.TrimEnd ('\0');
829 static internal IOException CreateMarkedForDeletionException ()
831 throw new IOException ("Illegal operation attempted on a"
832 + " registry key that has been marked for deletion.");
835 static string GetHiveName (RegistryHive hive)
838 case RegistryHive.ClassesRoot:
839 return "HKEY_CLASSES_ROOT";
840 case RegistryHive.CurrentConfig:
841 return "HKEY_CURRENT_CONFIG";
842 case RegistryHive.CurrentUser:
843 return "HKEY_CURRENT_USER";
844 case RegistryHive.DynData:
845 return "HKEY_DYN_DATA";
846 case RegistryHive.LocalMachine:
847 return "HKEY_LOCAL_MACHINE";
848 case RegistryHive.PerformanceData:
849 return "HKEY_PERFORMANCE_DATA";
850 case RegistryHive.Users:
854 throw new NotImplementedException (string.Format (
855 "Registry hive '{0}' is not implemented.", hive.ToString ()));