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;
43 using System.Security.AccessControl;
46 namespace Microsoft.Win32
49 /// Wrapper class for Windows Registry Entry.
54 public sealed class RegistryKey : MarshalByRefObject, IDisposable
57 // This represents the backend data, used when creating the
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.
113 void IDisposable.Dispose ()
115 GC.SuppressFinalize (this);
121 /// Final cleanup of registry key object. Close the
122 /// key if it's still open.
131 /// Get the fully qualified registry key name.
134 get { return qname; }
139 /// Flush the current registry state to disk.
143 RegistryApi.Flush (this);
148 /// Close the current registry key and flushes the state of the registry
155 // a handle to a remote hive must be closed, while one to a local
156 // hive should not be closed
157 if (!isRemoteRoot && IsRoot)
160 RegistryApi.Close (this);
166 /// get the number of sub-keys for this key
168 public int SubKeyCount {
170 AssertKeyStillValid ();
172 return RegistryApi.SubKeyCount (this);
178 /// get the number of values for this key
180 public int ValueCount {
182 AssertKeyStillValid ();
184 return RegistryApi.ValueCount (this);
190 /// Set a registry value.
192 public void SetValue (string name, object value)
194 AssertKeyStillValid ();
197 throw new ArgumentNullException ("value");
200 AssertKeyNameLength (name);
203 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
205 RegistryApi.SetValue (this, name, value);
210 public void SetValue (string name, object value, RegistryValueKind valueKind)
212 AssertKeyStillValid ();
215 throw new ArgumentNullException ("value");
218 AssertKeyNameLength (name);
221 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
223 RegistryApi.SetValue (this, name, value, valueKind);
228 /// Open the sub key specified, for read access.
230 public RegistryKey OpenSubKey (string name)
232 return OpenSubKey (name, false);
237 /// Open the sub key specified.
239 public RegistryKey OpenSubKey (string name, bool writable)
241 AssertKeyStillValid ();
244 throw new ArgumentNullException ("name");
246 AssertKeyNameLength (name);
248 return RegistryApi.OpenSubKey (this, name, writable);
253 /// Get a registry value.
255 public object GetValue (string name)
257 return GetValue (name, null);
262 /// Get a registry value.
264 public object GetValue (string name, object defaultValue)
266 AssertKeyStillValid ();
268 return RegistryApi.GetValue (this, name, defaultValue,
269 RegistryValueOptions.None);
274 public object GetValue (string name, object defaultValue, RegistryValueOptions options)
276 AssertKeyStillValid ();
278 return RegistryApi.GetValue (this, name, defaultValue, options);
282 public RegistryValueKind GetValueKind (string name)
284 throw new NotImplementedException ();
289 /// Create a sub key.
291 public RegistryKey CreateSubKey (string subkey)
293 AssertKeyStillValid ();
294 AssertKeyNameNotNull (subkey);
295 AssertKeyNameLength (subkey);
298 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
299 return RegistryApi.CreateSubKey (this, subkey);
304 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck)
306 throw new NotImplementedException ();
310 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistrySecurity registrySecurity)
312 throw new NotImplementedException ();
317 /// Delete the specified subkey.
319 public void DeleteSubKey(string subkey)
321 DeleteSubKey (subkey, true);
326 /// Delete the specified subkey.
328 public void DeleteSubKey(string subkey, bool throwOnMissingSubKey)
330 AssertKeyStillValid ();
331 AssertKeyNameNotNull (subkey);
332 AssertKeyNameLength (subkey);
335 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
337 RegistryKey child = OpenSubKey (subkey);
340 if (throwOnMissingSubKey)
341 throw new ArgumentException ("Cannot delete a subkey tree"
342 + " because the subkey does not exist.");
346 if (child.SubKeyCount > 0){
347 throw new InvalidOperationException ("Registry key has subkeys"
348 + " and recursive removes are not supported by this method.");
353 RegistryApi.DeleteKey (this, subkey, throwOnMissingSubKey);
358 /// Delete a sub tree (node, and values alike).
360 public void DeleteSubKeyTree(string subkey)
362 // Note: this is done by deleting sub-nodes recursively.
363 // The preformance is not very good. There may be a
364 // better way to implement this.
366 AssertKeyStillValid ();
367 AssertKeyNameNotNull (subkey);
368 AssertKeyNameLength (subkey);
370 RegistryKey child = OpenSubKey (subkey, true);
372 throw new ArgumentException ("Cannot delete a subkey tree"
373 + " because the subkey does not exist.");
375 child.DeleteChildKeysAndValues ();
377 DeleteSubKey (subkey, false);
382 /// Delete a value from the registry.
384 public void DeleteValue(string name)
386 DeleteValue (name, true);
391 /// Delete a value from the registry.
393 public void DeleteValue(string name, bool throwOnMissingValue)
395 AssertKeyStillValid ();
398 throw new ArgumentNullException ("name");
401 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
403 RegistryApi.DeleteValue (this, name, throwOnMissingValue);
407 public RegistrySecurity GetAccessControl ()
409 throw new NotImplementedException ();
412 public RegistrySecurity GetAccessControl (AccessControlSections includeSections)
414 throw new NotImplementedException ();
420 /// Get the names of the sub keys.
422 public string[] GetSubKeyNames()
424 AssertKeyStillValid ();
426 return RegistryApi.GetSubKeyNames (this);
431 /// Get the names of values contained in this key.
433 public string[] GetValueNames()
435 AssertKeyStillValid ();
436 return RegistryApi.GetValueNames (this);
440 [MonoTODO ("Not implemented on unix")]
441 public static RegistryKey OpenRemoteBaseKey(RegistryHive hKey,string machineName)
443 if (machineName == null)
444 throw new ArgumentNullException ("machineName");
445 return RegistryApi.OpenRemoteBaseKey (hKey, machineName);
450 public RegistryKey OpenSubKey (string name, RegistryKeyPermissionCheck permissionCheck)
452 throw new NotImplementedException ();
456 public RegistryKey OpenSubKey (string name, RegistryKeyPermissionCheck permissionCheck, RegistryRights rights)
458 throw new NotImplementedException ();
461 public void SetAccessControl (RegistrySecurity registrySecurity)
463 throw new NotImplementedException ();
469 /// Build a string representation of the registry key.
470 /// Conatins the fully qualified key name, and the Hex
471 /// representation of the registry key handle.
473 public override string ToString()
475 AssertKeyStillValid ();
477 return RegistryApi.ToString (this);
480 #endregion // PublicAPI
482 internal bool IsRoot {
483 get { return hive != null; }
486 private bool IsWritable {
487 get { return isWritable; }
490 internal RegistryHive Hive {
493 throw new NotSupportedException ();
494 return (RegistryHive) hive;
498 // returns the key handle for the win32 implementation and the
499 // KeyHandler for the unix implementation
500 internal object Handle {
501 get { return handle; }
505 /// validate that the registry key handle is still usable.
507 private void AssertKeyStillValid ()
510 throw new ObjectDisposedException ("Microsoft.Win32.RegistryKey");
515 /// validate that the registry key handle is still usable, and
516 /// that the 'subKeyName' is not null.
518 private void AssertKeyNameNotNull (string subKeyName)
520 if (subKeyName == null)
522 throw new ArgumentNullException ("name");
524 throw new ArgumentNullException ("subkey");
528 private void AssertKeyNameLength (string name)
531 if (name.Length > 255)
532 throw new ArgumentException ("Name of registry key cannot be greater than 255 characters");
534 if (name.Length >= 255)
535 throw new ArgumentException ("Name of registry key cannot be greater than or equal to 255 characters");
540 /// Utility method to delelte a key's sub keys and values.
541 /// This method removes a level of indirection when deleting
544 private void DeleteChildKeysAndValues ()
549 string[] subKeys = GetSubKeyNames ();
550 foreach (string subKey in subKeys)
552 RegistryKey sub = OpenSubKey (subKey, true);
553 sub.DeleteChildKeysAndValues ();
555 DeleteSubKey (subKey, false);
558 string[] values = GetValueNames ();
559 foreach (string value in values) {
560 DeleteValue (value, false);
565 /// decode a byte array as a string, and strip trailing nulls
567 static internal string DecodeString (byte[] data)
569 string stringRep = Encoding.Unicode.GetString (data);
570 int idx = stringRep.IndexOf ('\0');
572 stringRep = stringRep.TrimEnd ('\0');
576 static internal IOException CreateMarkedForDeletionException ()
578 throw new IOException ("Illegal operation attempted on a"
579 + " registry key that has been marked for deletion.");
582 static string GetHiveName (RegistryHive hive)
585 case RegistryHive.ClassesRoot:
586 return "HKEY_CLASSES_ROOT";
587 case RegistryHive.CurrentConfig:
588 return "HKEY_CURRENT_CONFIG";
589 case RegistryHive.CurrentUser:
590 return "HKEY_CURRENT_USER";
591 case RegistryHive.DynData:
592 return "HKEY_DYN_DATA";
593 case RegistryHive.LocalMachine:
594 return "HKEY_LOCAL_MACHINE";
595 case RegistryHive.PerformanceData:
596 return "HKEY_PERFORMANCE_DATA";
597 case RegistryHive.Users:
601 throw new NotImplementedException (string.Format (
602 "Registry hive '{0}' is not implemented.", hive.ToString ()));