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;
43 namespace Microsoft.Win32
46 /// Wrapper class for Windows Registry Entry.
49 public sealed class RegistryKey : MarshalByRefObject, IDisposable
52 // This represents the backend data, used when creating the
57 object hive; // the RegistryHive if the key represents a base key
58 readonly string qname; // the fully qualified registry key name
59 readonly bool isRemoteRoot; // is an instance of a remote root key?
60 readonly bool isWritable; // is the key openen in writable mode
62 static readonly IRegistryApi RegistryApi;
66 if (Path.DirectorySeparatorChar == '\\')
67 RegistryApi = new Win32RegistryApi ();
69 RegistryApi = new UnixRegistryApi ();
73 /// Construct an instance of a root registry key entry.
75 internal RegistryKey (RegistryHive hiveId) : this (hiveId,
76 new IntPtr ((int) hiveId), false)
81 /// Construct an instance of a root registry key entry.
83 internal RegistryKey (RegistryHive hiveId, IntPtr keyHandle, bool remoteRoot)
87 qname = GetHiveName (hiveId);
88 isRemoteRoot = remoteRoot;
89 isWritable = true; // always consider root writable
93 /// Construct an instance of a registry key entry.
95 internal RegistryKey (object data, string keyName, bool writable)
99 isWritable = writable;
105 /// Dispose of registry key object. Close the
106 /// key if it's still open.
108 void IDisposable.Dispose ()
110 GC.SuppressFinalize (this);
116 /// Final cleanup of registry key object. Close the
117 /// key if it's still open.
126 /// Get the fully qualified registry key name.
129 get { return qname; }
134 /// Flush the current registry state to disk.
138 RegistryApi.Flush (this);
143 /// Close the current registry key and flushes the state of the registry
150 // a handle to a remote hive must be closed, while one to a local
151 // hive should not be closed
152 if (!isRemoteRoot && IsRoot)
155 RegistryApi.Close (this);
161 /// get the number of sub-keys for this key
163 public int SubKeyCount {
165 AssertKeyStillValid ();
167 return RegistryApi.SubKeyCount (this);
173 /// get the number of values for this key
175 public int ValueCount {
177 AssertKeyStillValid ();
179 return RegistryApi.ValueCount (this);
185 /// Set a registry value.
187 public void SetValue (string name, object value)
189 AssertKeyStillValid ();
192 throw new ArgumentNullException ("value");
195 AssertKeyNameLength (name);
198 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
200 RegistryApi.SetValue (this, name, value);
204 public void SetValue (string name, object value, RegistryValueKind valueKind)
206 AssertKeyStillValid ();
209 throw new ArgumentNullException ("value");
212 AssertKeyNameLength (name);
215 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
217 RegistryApi.SetValue (this, name, value, valueKind);
221 /// Open the sub key specified, for read access.
223 public RegistryKey OpenSubKey (string name)
225 return OpenSubKey (name, false);
230 /// Open the sub key specified.
232 public RegistryKey OpenSubKey (string name, bool writable)
234 AssertKeyStillValid ();
237 throw new ArgumentNullException ("name");
239 AssertKeyNameLength (name);
241 return RegistryApi.OpenSubKey (this, name, writable);
246 /// Get a registry value.
248 public object GetValue (string name)
250 return GetValue (name, null);
255 /// Get a registry value.
257 public object GetValue (string name, object defaultValue)
259 AssertKeyStillValid ();
261 return RegistryApi.GetValue (this, name, defaultValue,
262 RegistryValueOptions.None);
266 public object GetValue (string name, object defaultValue, RegistryValueOptions options)
268 AssertKeyStillValid ();
270 return RegistryApi.GetValue (this, name, defaultValue, options);
274 public RegistryValueKind GetValueKind (string name)
276 return RegistryApi.GetValueKind (this, name);
280 /// Create a sub key.
282 public RegistryKey CreateSubKey (string subkey)
284 AssertKeyStillValid ();
285 AssertKeyNameNotNull (subkey);
286 AssertKeyNameLength (subkey);
289 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
290 return RegistryApi.CreateSubKey (this, subkey);
294 [MonoLimitation ("permissionCheck is ignored in Mono")]
295 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck)
297 return CreateSubKey (subkey);
301 [MonoLimitation ("permissionCheck and registrySecurity are ignored in Mono")]
302 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistrySecurity registrySecurity)
304 return CreateSubKey (subkey);
308 /// Delete the specified subkey.
310 public void DeleteSubKey(string subkey)
312 DeleteSubKey (subkey, true);
317 /// Delete the specified subkey.
319 public void DeleteSubKey(string subkey, bool throwOnMissingSubKey)
321 AssertKeyStillValid ();
322 AssertKeyNameNotNull (subkey);
323 AssertKeyNameLength (subkey);
326 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
328 RegistryKey child = OpenSubKey (subkey);
331 if (throwOnMissingSubKey)
332 throw new ArgumentException ("Cannot delete a subkey tree"
333 + " because the subkey does not exist.");
337 if (child.SubKeyCount > 0){
338 throw new InvalidOperationException ("Registry key has subkeys"
339 + " and recursive removes are not supported by this method.");
344 RegistryApi.DeleteKey (this, subkey, throwOnMissingSubKey);
349 /// Delete a sub tree (node, and values alike).
351 public void DeleteSubKeyTree(string subkey)
353 // Note: this is done by deleting sub-nodes recursively.
354 // The preformance is not very good. There may be a
355 // better way to implement this.
357 AssertKeyStillValid ();
358 AssertKeyNameNotNull (subkey);
359 AssertKeyNameLength (subkey);
361 RegistryKey child = OpenSubKey (subkey, true);
363 throw new ArgumentException ("Cannot delete a subkey tree"
364 + " because the subkey does not exist.");
366 child.DeleteChildKeysAndValues ();
368 DeleteSubKey (subkey, false);
373 /// Delete a value from the registry.
375 public void DeleteValue(string name)
377 DeleteValue (name, true);
382 /// Delete a value from the registry.
384 public void DeleteValue(string name, bool throwOnMissingValue)
386 AssertKeyStillValid ();
389 throw new ArgumentNullException ("name");
392 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
394 RegistryApi.DeleteValue (this, name, throwOnMissingValue);
397 public RegistrySecurity GetAccessControl ()
399 throw new NotImplementedException ();
402 public RegistrySecurity GetAccessControl (AccessControlSections includeSections)
404 throw new NotImplementedException ();
409 /// Get the names of the sub keys.
411 public string[] GetSubKeyNames()
413 AssertKeyStillValid ();
415 return RegistryApi.GetSubKeyNames (this);
420 /// Get the names of values contained in this key.
422 public string[] GetValueNames()
424 AssertKeyStillValid ();
425 return RegistryApi.GetValueNames (this);
429 [MonoTODO ("Not implemented on unix")]
430 public static RegistryKey OpenRemoteBaseKey(RegistryHive hKey,string machineName)
432 if (machineName == null)
433 throw new ArgumentNullException ("machineName");
434 return RegistryApi.OpenRemoteBaseKey (hKey, machineName);
438 [MonoLimitation ("permissionCheck is ignored in Mono")]
439 public RegistryKey OpenSubKey (string name, RegistryKeyPermissionCheck permissionCheck)
441 return OpenSubKey (name);
445 [MonoLimitation ("permissionCheck and rights are ignored in Mono")]
446 public RegistryKey OpenSubKey (string name, RegistryKeyPermissionCheck permissionCheck, RegistryRights rights)
448 return OpenSubKey (name);
451 public void SetAccessControl (RegistrySecurity registrySecurity)
453 throw new NotImplementedException ();
458 /// Build a string representation of the registry key.
459 /// Conatins the fully qualified key name, and the Hex
460 /// representation of the registry key handle.
462 public override string ToString()
464 AssertKeyStillValid ();
466 return RegistryApi.ToString (this);
469 #endregion // PublicAPI
471 internal bool IsRoot {
472 get { return hive != null; }
475 private bool IsWritable {
476 get { return isWritable; }
479 internal RegistryHive Hive {
482 throw new NotSupportedException ();
483 return (RegistryHive) hive;
487 // returns the key handle for the win32 implementation and the
488 // KeyHandler for the unix implementation
489 internal object Handle {
490 get { return handle; }
494 /// validate that the registry key handle is still usable.
496 private void AssertKeyStillValid ()
499 throw new ObjectDisposedException ("Microsoft.Win32.RegistryKey");
504 /// validate that the registry key handle is still usable, and
505 /// that the 'subKeyName' is not null.
507 private void AssertKeyNameNotNull (string subKeyName)
509 if (subKeyName == null)
510 throw new ArgumentNullException ("name");
513 private void AssertKeyNameLength (string name)
515 if (name.Length > 255)
516 throw new ArgumentException ("Name of registry key cannot be greater than 255 characters");
520 /// Utility method to delelte a key's sub keys and values.
521 /// This method removes a level of indirection when deleting
524 private void DeleteChildKeysAndValues ()
529 string[] subKeys = GetSubKeyNames ();
530 foreach (string subKey in subKeys)
532 RegistryKey sub = OpenSubKey (subKey, true);
533 sub.DeleteChildKeysAndValues ();
535 DeleteSubKey (subKey, false);
538 string[] values = GetValueNames ();
539 foreach (string value in values) {
540 DeleteValue (value, false);
545 /// decode a byte array as a string, and strip trailing nulls
547 static internal string DecodeString (byte[] data)
549 string stringRep = Encoding.Unicode.GetString (data);
550 int idx = stringRep.IndexOf ('\0');
552 stringRep = stringRep.TrimEnd ('\0');
556 static internal IOException CreateMarkedForDeletionException ()
558 throw new IOException ("Illegal operation attempted on a"
559 + " registry key that has been marked for deletion.");
562 static string GetHiveName (RegistryHive hive)
565 case RegistryHive.ClassesRoot:
566 return "HKEY_CLASSES_ROOT";
567 case RegistryHive.CurrentConfig:
568 return "HKEY_CURRENT_CONFIG";
569 case RegistryHive.CurrentUser:
570 return "HKEY_CURRENT_USER";
571 case RegistryHive.DynData:
572 return "HKEY_DYN_DATA";
573 case RegistryHive.LocalMachine:
574 return "HKEY_LOCAL_MACHINE";
575 case RegistryHive.PerformanceData:
576 return "HKEY_PERFORMANCE_DATA";
577 case RegistryHive.Users:
581 throw new NotImplementedException (string.Format (
582 "Registry hive '{0}' is not implemented.", hive.ToString ()));