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;
41 using System.Security.AccessControl;
44 namespace Microsoft.Win32
47 /// Wrapper class for Windows Registry Entry.
52 public sealed class RegistryKey : MarshalByRefObject, IDisposable
55 // This represents the backend data, used when creating the
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;
108 /// Dispose of registry key object. Close the
109 /// key if it's still open.
111 void IDisposable.Dispose ()
113 GC.SuppressFinalize (this);
119 /// Final cleanup of registry key object. Close the
120 /// key if it's still open.
129 /// Get the fully qualified registry key name.
132 get { return qname; }
137 /// Flush the current registry state to disk.
141 RegistryApi.Flush (this);
146 /// Close the current registry key and flushes the state of the registry
153 // a handle to a remote hive must be closed, while one to a local
154 // hive should not be closed
155 if (!isRemoteRoot && IsRoot)
158 RegistryApi.Close (this);
164 /// get the number of sub-keys for this key
166 public int SubKeyCount {
168 AssertKeyStillValid ();
170 return RegistryApi.SubKeyCount (this);
176 /// get the number of values for this key
178 public int ValueCount {
180 AssertKeyStillValid ();
182 return RegistryApi.ValueCount (this);
188 /// Set a registry value.
190 public void SetValue (string name, object value)
192 AssertKeyStillValid ();
195 throw new ArgumentNullException ("value");
198 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
200 RegistryApi.SetValue (this, name, value);
205 public void SetValue (string name, object value, RegistryValueKind valueKind)
207 AssertKeyStillValid ();
210 throw new ArgumentNullException ();
213 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
215 RegistryApi.SetValue (this, name, value, valueKind);
220 /// Open the sub key specified, for read access.
222 public RegistryKey OpenSubKey (string keyName)
224 return OpenSubKey (keyName, false);
229 /// Open the sub key specified.
231 public RegistryKey OpenSubKey (string keyName, bool writtable)
233 AssertKeyStillValid ();
234 AssertKeyNameNotNull (keyName);
236 return RegistryApi.OpenSubKey (this, keyName, writtable);
241 /// Get a registry value.
243 public object GetValue (string name)
245 return GetValue (name, null);
250 /// Get a registry value.
252 public object GetValue (string name, object defaultValue)
254 AssertKeyStillValid ();
256 return RegistryApi.GetValue (this, name, defaultValue,
257 RegistryValueOptions.None);
262 public object GetValue (string name, object defaultValue, RegistryValueOptions options)
264 AssertKeyStillValid ();
266 return RegistryApi.GetValue (this, name, defaultValue, options);
270 public RegistryValueKind GetValueKind (string name)
272 throw new NotImplementedException ();
277 /// Create a sub key.
279 public RegistryKey CreateSubKey (string subkey)
281 AssertKeyStillValid ();
282 AssertKeyNameNotNull (subkey);
283 if (subkey.Length > 255)
284 throw new ArgumentException ("keyName length is larger than 255 characters", subkey);
287 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
288 return RegistryApi.CreateSubKey (this, subkey);
293 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck)
295 throw new NotImplementedException ();
299 public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistrySecurity registrySecurity)
301 throw new NotImplementedException ();
306 /// Delete the specified subkey.
308 public void DeleteSubKey(string subkey)
310 DeleteSubKey (subkey, true);
315 /// Delete the specified subkey.
317 public void DeleteSubKey(string subkey, bool throwOnMissingSubKey)
319 AssertKeyStillValid ();
320 AssertKeyNameNotNull (subkey);
323 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
325 RegistryKey child = OpenSubKey (subkey);
328 if (throwOnMissingSubKey)
329 throw new ArgumentException ("Cannot delete a subkey tree"
330 + " because the subkey does not exist.");
334 if (child.SubKeyCount > 0){
335 throw new InvalidOperationException ("Registry key has subkeys"
336 + " and recursive removes are not supported by this method.");
341 RegistryApi.DeleteKey (this, subkey, throwOnMissingSubKey);
346 /// Delete a sub tree (node, and values alike).
348 public void DeleteSubKeyTree(string keyName)
350 // Note: this is done by deleting sub-nodes recursively.
351 // The preformance is not very good. There may be a
352 // better way to implement this.
354 AssertKeyStillValid ();
355 AssertKeyNameNotNull (keyName);
357 RegistryKey child = OpenSubKey (keyName, true);
359 throw new ArgumentException ("Cannot delete a subkey tree"
360 + " because the subkey does not exist.");
362 child.DeleteChildKeysAndValues ();
364 DeleteSubKey (keyName, false);
369 /// Delete a value from the registry.
371 public void DeleteValue(string value)
373 DeleteValue (value, true);
378 /// Delete a value from the registry.
380 public void DeleteValue(string value, bool shouldThrowWhenKeyMissing)
382 AssertKeyStillValid ();
383 AssertKeyNameNotNull (value);
386 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
388 RegistryApi.DeleteValue (this, value, shouldThrowWhenKeyMissing);
392 public RegistrySecurity GetAccessControl ()
394 throw new NotImplementedException ();
397 public RegistrySecurity GetAccessControl (AccessControlSections includeSections)
399 throw new NotImplementedException ();
405 /// Get the names of the sub keys.
407 public string[] GetSubKeyNames()
409 AssertKeyStillValid ();
411 return RegistryApi.GetSubKeyNames (this);
416 /// Get the names of values contained in this key.
418 public string[] GetValueNames()
420 AssertKeyStillValid ();
421 return RegistryApi.GetValueNames (this);
425 [MonoTODO ("Not implemented on unix")]
426 public static RegistryKey OpenRemoteBaseKey(RegistryHive hKey,string machineName)
428 if (machineName == null)
429 throw new ArgumentNullException ("machineName");
430 return RegistryApi.OpenRemoteBaseKey (hKey, machineName);
435 public RegistryKey OpenSubKey (string name, RegistryKeyPermissionCheck permissionCheck)
437 throw new NotImplementedException ();
441 public RegistryKey OpenSubKey (string name, RegistryKeyPermissionCheck permissionCheck, RegistryRights rights)
443 throw new NotImplementedException ();
446 public void SetAccessControl (RegistrySecurity registrySecurity)
448 throw new NotImplementedException ();
454 /// Build a string representation of the registry key.
455 /// Conatins the fully qualified key name, and the Hex
456 /// representation of the registry key handle.
458 public override string ToString()
460 AssertKeyStillValid ();
462 return RegistryApi.ToString (this);
465 #endregion // PublicAPI
467 internal bool IsRoot {
468 get { return hive != null; }
471 private bool IsWritable {
472 get { return isWritable; }
475 internal RegistryHive Hive {
478 throw new NotSupportedException ();
479 return (RegistryHive) hive;
483 // returns the key handle for the win32 implementation and the
484 // KeyHandler for the unix implementation
485 internal object Handle {
486 get { return handle; }
490 /// validate that the registry key handle is still usable.
492 private void AssertKeyStillValid ()
495 throw new ObjectDisposedException ("Microsoft.Win32.RegistryKey");
500 /// validate that the registry key handle is still usable, and
501 /// that the 'subKeyName' is not null.
503 private void AssertKeyNameNotNull (string subKeyName)
505 if (subKeyName == null)
506 throw new ArgumentNullException ();
511 /// Utility method to delelte a key's sub keys and values.
512 /// This method removes a level of indirection when deleting
515 private void DeleteChildKeysAndValues ()
520 string[] subKeys = GetSubKeyNames ();
521 foreach (string subKey in subKeys)
523 RegistryKey sub = OpenSubKey (subKey, true);
524 sub.DeleteChildKeysAndValues ();
526 DeleteSubKey (subKey, false);
529 string[] values = GetValueNames ();
530 foreach (string value in values) {
531 DeleteValue (value, false);
536 /// decode a byte array as a string, and strip trailing nulls
538 static internal string DecodeString (byte[] data)
540 string stringRep = Encoding.Unicode.GetString (data);
541 int idx = stringRep.IndexOf ('\0');
543 stringRep = stringRep.TrimEnd ('\0');
547 static internal IOException CreateMarkedForDeletionException ()
549 throw new IOException ("Illegal operation attempted on a"
550 + " registry key that has been marked for deletion.");
553 static string GetHiveName (RegistryHive hive)
556 case RegistryHive.ClassesRoot:
557 return "HKEY_CLASSES_ROOT";
558 case RegistryHive.CurrentConfig:
559 return "HKEY_CURRENT_CONFIG";
560 case RegistryHive.CurrentUser:
561 return "HKEY_CURRENT_USER";
562 case RegistryHive.DynData:
563 return "HKEY_DYN_DATA";
564 case RegistryHive.LocalMachine:
565 return "HKEY_LOCAL_MACHINE";
566 case RegistryHive.PerformanceData:
567 return "HKEY_PERFORMANCE_DATA";
568 case RegistryHive.Users:
572 throw new NotImplementedException (string.Format (
573 "Registry hive '{0}' is not implemented.", hive.ToString ()));