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 ()
212 if (Path.DirectorySeparatorChar == '\\')
213 RegistryApi = new Win32RegistryApi ();
215 RegistryApi = new UnixRegistryApi ();
219 /// Construct an instance of a root registry key entry.
221 internal RegistryKey (RegistryHive hiveId) : this (hiveId,
222 new IntPtr ((int) hiveId), false)
227 /// Construct an instance of a root registry key entry.
229 internal RegistryKey (RegistryHive hiveId, IntPtr keyHandle, bool remoteRoot)
233 qname = GetHiveName (hiveId);
234 isRemoteRoot = remoteRoot;
235 isWritable = true; // always consider root writable
239 /// Construct an instance of a registry key entry.
241 internal RegistryKey (object data, string keyName, bool writable)
245 isWritable = writable;
248 static internal bool IsEquals (RegistryKey a, RegistryKey b)
250 return a.hive == b.hive && a.handle == b.handle && a.qname == b.qname && a.isRemoteRoot == b.isRemoteRoot && a.isWritable == b.isWritable;
256 /// Dispose of registry key object. Close the
257 /// key if it's still open.
259 public void Dispose ()
261 GC.SuppressFinalize (this);
266 /// Get the fully qualified registry key name.
269 get { return qname; }
274 /// Flush the current registry state to disk.
278 RegistryApi.Flush (this);
283 /// Close the current registry key and flushes the state of the registry
290 // a handle to a remote hive must be closed, while one to a local
291 // hive should not be closed
292 if (!isRemoteRoot && IsRoot)
295 RegistryApi.Close (this);
302 /// get the number of sub-keys for this key
304 public int SubKeyCount {
306 AssertKeyStillValid ();
308 return RegistryApi.SubKeyCount (this);
314 /// get the number of values for this key
316 public int ValueCount {
318 AssertKeyStillValid ();
320 return RegistryApi.ValueCount (this);
325 [MonoTODO ("Not implemented in Unix")]
326 public SafeRegistryHandle Handle {
328 AssertKeyStillValid ();
330 if (safe_handle == null) {
331 IntPtr h = RegistryApi.GetHandle (this);
332 safe_handle = new SafeRegistryHandle (h, true);
340 [MonoLimitation ("View is ignored in Mono.")]
341 public RegistryView View {
343 return RegistryView.Default;
349 /// Set a registry value.
351 public void SetValue (string name, object value)
353 AssertKeyStillValid ();
356 throw new ArgumentNullException ("value");
359 AssertKeyNameLength (name);
362 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
364 RegistryApi.SetValue (this, name, value);
368 public void SetValue (string name, object value, RegistryValueKind valueKind)
370 AssertKeyStillValid ();
373 throw new ArgumentNullException ("value");
376 AssertKeyNameLength (name);
379 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
381 RegistryApi.SetValue (this, name, value, valueKind);
385 /// Open the sub key specified, for read access.
387 public RegistryKey OpenSubKey (string name)
389 return OpenSubKey (name, false);
394 /// Open the sub key specified.
396 public RegistryKey OpenSubKey (string name, bool writable)
398 AssertKeyStillValid ();
401 throw new ArgumentNullException ("name");
403 AssertKeyNameLength (name);
405 return RegistryApi.OpenSubKey (this, name, writable);
410 /// Get a registry value.
412 public object GetValue (string name)
414 return GetValue (name, null);
419 /// Get a registry value.
421 public object GetValue (string name, object defaultValue)
423 AssertKeyStillValid ();
425 return RegistryApi.GetValue (this, name, defaultValue,
426 RegistryValueOptions.None);
430 public object GetValue (string name, object defaultValue, RegistryValueOptions options)
432 AssertKeyStillValid ();
434 return RegistryApi.GetValue (this, name, defaultValue, options);
438 public RegistryValueKind GetValueKind (string name)
440 return RegistryApi.GetValueKind (this, name);
444 /// Create a sub key.
446 public RegistryKey CreateSubKey (string subkey)
448 AssertKeyStillValid ();
449 AssertKeyNameNotNull (subkey);
450 AssertKeyNameLength (subkey);
453 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
454 return RegistryApi.CreateSubKey (this, subkey);
458 [MonoLimitation ("permissionCheck is ignored in Mono")]
459 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck)
461 return CreateSubKey (subkey);
465 [MonoLimitation ("permissionCheck and registrySecurity are ignored in Mono")]
466 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistrySecurity registrySecurity)
468 return CreateSubKey (subkey);
472 [MonoLimitation ("permissionCheck is ignored in Mono")]
473 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistryOptions options)
475 AssertKeyStillValid ();
476 AssertKeyNameNotNull (subkey);
477 AssertKeyNameLength (subkey);
480 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
482 return RegistryApi.CreateSubKey (this, subkey, options);
486 [MonoLimitation ("permissionCheck and registrySecurity are ignored in Mono")]
487 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistryOptions registryOptions,
488 RegistrySecurity registrySecurity)
490 return CreateSubKey (subkey, permissionCheck, registryOptions);
494 public RegistryKey CreateSubKey (string subkey, bool writable)
496 return CreateSubKey (subkey, writable ? RegistryKeyPermissionCheck.ReadWriteSubTree : RegistryKeyPermissionCheck.ReadSubTree);
500 public RegistryKey CreateSubKey (string subkey, bool writable, RegistryOptions options)
502 return CreateSubKey (subkey, writable ? RegistryKeyPermissionCheck.ReadWriteSubTree : RegistryKeyPermissionCheck.ReadSubTree, options);
506 /// Delete the specified subkey.
508 public void DeleteSubKey(string subkey)
510 DeleteSubKey (subkey, true);
515 /// Delete the specified subkey.
517 public void DeleteSubKey(string subkey, bool throwOnMissingSubKey)
519 AssertKeyStillValid ();
520 AssertKeyNameNotNull (subkey);
521 AssertKeyNameLength (subkey);
524 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
526 RegistryKey child = OpenSubKey (subkey);
529 if (throwOnMissingSubKey)
530 throw new ArgumentException ("Cannot delete a subkey tree"
531 + " because the subkey does not exist.");
535 if (child.SubKeyCount > 0){
536 throw new InvalidOperationException ("Registry key has subkeys"
537 + " and recursive removes are not supported by this method.");
542 RegistryApi.DeleteKey (this, subkey, throwOnMissingSubKey);
547 /// Delete a sub tree (node, and values alike).
549 public void DeleteSubKeyTree(string subkey)
551 DeleteSubKeyTree (subkey, true);
555 void DeleteSubKeyTree (string subkey, bool throwOnMissingSubKey)
557 // Note: this is done by deleting sub-nodes recursively.
558 // The preformance is not very good. There may be a
559 // better way to implement this.
561 AssertKeyStillValid ();
562 AssertKeyNameNotNull (subkey);
563 AssertKeyNameLength (subkey);
565 RegistryKey child = OpenSubKey (subkey, true);
567 if (!throwOnMissingSubKey)
570 throw new ArgumentException ("Cannot delete a subkey tree"
571 + " because the subkey does not exist.");
574 child.DeleteChildKeysAndValues ();
576 DeleteSubKey (subkey, false);
581 /// Delete a value from the registry.
583 public void DeleteValue(string name)
585 DeleteValue (name, true);
590 /// Delete a value from the registry.
592 public void DeleteValue(string name, bool throwOnMissingValue)
594 AssertKeyStillValid ();
597 throw new ArgumentNullException ("name");
600 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
602 RegistryApi.DeleteValue (this, name, throwOnMissingValue);
605 public RegistrySecurity GetAccessControl ()
607 return GetAccessControl (AccessControlSections.Owner |
608 AccessControlSections.Group |
609 AccessControlSections.Access);
612 public RegistrySecurity GetAccessControl (AccessControlSections includeSections)
614 return new RegistrySecurity (Name, includeSections);
619 /// Get the names of the sub keys.
621 public string[] GetSubKeyNames()
623 AssertKeyStillValid ();
625 return RegistryApi.GetSubKeyNames (this);
630 /// Get the names of values contained in this key.
632 public string[] GetValueNames()
634 AssertKeyStillValid ();
635 return RegistryApi.GetValueNames (this);
639 [SecurityPermission (SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
640 [MonoTODO ("Not implemented on unix")]
641 public static RegistryKey FromHandle (SafeRegistryHandle handle)
644 throw new ArgumentNullException ("handle");
646 return RegistryApi.FromHandle (handle);
650 [SecurityPermission (SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
651 [MonoTODO ("Not implemented on unix")]
652 public static RegistryKey FromHandle (SafeRegistryHandle handle, RegistryView view)
654 return FromHandle (handle);
658 [MonoTODO ("Not implemented on unix")]
659 public static RegistryKey OpenRemoteBaseKey(RegistryHive hKey,string machineName)
661 if (machineName == null)
662 throw new ArgumentNullException ("machineName");
663 return RegistryApi.OpenRemoteBaseKey (hKey, machineName);
667 [MonoTODO ("Not implemented on unix")]
668 public static RegistryKey OpenRemoteBaseKey (RegistryHive hKey, string machineName, RegistryView view)
670 if (machineName == null)
671 throw new ArgumentNullException ("machineName");
672 return RegistryApi.OpenRemoteBaseKey (hKey, machineName);
676 [MonoLimitation ("View is ignored in Mono")]
677 public static RegistryKey OpenBaseKey (RegistryHive hKey, RegistryView view)
680 case RegistryHive.ClassesRoot:
681 return Registry.ClassesRoot;
682 case RegistryHive.CurrentConfig:
683 return Registry.CurrentConfig;
684 case RegistryHive.CurrentUser:
685 return Registry.CurrentUser;
686 case RegistryHive.DynData:
687 return Registry.DynData;
688 case RegistryHive.LocalMachine:
689 return Registry.LocalMachine;
690 case RegistryHive.PerformanceData:
691 return Registry.PerformanceData;
692 case RegistryHive.Users:
693 return Registry.Users;
696 throw new ArgumentException ("hKey");
700 public RegistryKey OpenSubKey (string name, RegistryKeyPermissionCheck permissionCheck)
702 return OpenSubKey (name, permissionCheck == RegistryKeyPermissionCheck.ReadWriteSubTree);
706 [MonoLimitation ("rights are ignored in Mono")]
707 public RegistryKey OpenSubKey (string name, RegistryRights rights)
709 return OpenSubKey (name);
713 [MonoLimitation ("rights are ignored in Mono")]
714 public RegistryKey OpenSubKey (string name, RegistryKeyPermissionCheck permissionCheck, RegistryRights rights)
716 return OpenSubKey (name, permissionCheck == RegistryKeyPermissionCheck.ReadWriteSubTree);
719 public void SetAccessControl (RegistrySecurity registrySecurity)
721 if (null == registrySecurity)
722 throw new ArgumentNullException ("registrySecurity");
724 registrySecurity.PersistModifications (Name);
729 /// Build a string representation of the registry key.
730 /// Conatins the fully qualified key name, and the Hex
731 /// representation of the registry key handle.
733 public override string ToString()
735 AssertKeyStillValid ();
737 return RegistryApi.ToString (this);
740 #endregion // PublicAPI
742 internal bool IsRoot {
743 get { return hive != null; }
746 private bool IsWritable {
747 get { return isWritable; }
750 internal RegistryHive Hive {
753 throw new NotSupportedException ();
754 return (RegistryHive) hive;
758 // returns the key handle for the win32 implementation and the
759 // KeyHandler for the unix implementation
760 internal object InternalHandle {
761 get { return handle; }
765 /// validate that the registry key handle is still usable.
767 private void AssertKeyStillValid ()
770 throw new ObjectDisposedException ("Microsoft.Win32.RegistryKey");
775 /// validate that the registry key handle is still usable, and
776 /// that the 'subKeyName' is not null.
778 private void AssertKeyNameNotNull (string subKeyName)
780 if (subKeyName == null)
781 throw new ArgumentNullException ("name");
784 private void AssertKeyNameLength (string name)
786 if (name.Length > 255)
787 throw new ArgumentException ("Name of registry key cannot be greater than 255 characters");
791 /// Utility method to delelte a key's sub keys and values.
792 /// This method removes a level of indirection when deleting
795 private void DeleteChildKeysAndValues ()
800 string[] subKeys = GetSubKeyNames ();
801 foreach (string subKey in subKeys)
803 RegistryKey sub = OpenSubKey (subKey, true);
804 sub.DeleteChildKeysAndValues ();
806 DeleteSubKey (subKey, false);
809 string[] values = GetValueNames ();
810 foreach (string value in values) {
811 DeleteValue (value, false);
816 /// decode a byte array as a string, and strip trailing nulls
818 static internal string DecodeString (byte[] data)
820 string stringRep = Encoding.Unicode.GetString (data);
821 int idx = stringRep.IndexOf ('\0');
823 stringRep = stringRep.TrimEnd ('\0');
827 static internal IOException CreateMarkedForDeletionException ()
829 throw new IOException ("Illegal operation attempted on a"
830 + " registry key that has been marked for deletion.");
833 static string GetHiveName (RegistryHive hive)
836 case RegistryHive.ClassesRoot:
837 return "HKEY_CLASSES_ROOT";
838 case RegistryHive.CurrentConfig:
839 return "HKEY_CURRENT_CONFIG";
840 case RegistryHive.CurrentUser:
841 return "HKEY_CURRENT_USER";
842 case RegistryHive.DynData:
843 return "HKEY_DYN_DATA";
844 case RegistryHive.LocalMachine:
845 return "HKEY_LOCAL_MACHINE";
846 case RegistryHive.PerformanceData:
847 return "HKEY_PERFORMANCE_DATA";
848 case RegistryHive.Users:
852 throw new NotImplementedException (string.Format (
853 "Registry hive '{0}' is not implemented.", hive.ToString ()));