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;
40 namespace Microsoft.Win32
43 /// Wrapper class for Windows Registry Entry.
45 public sealed class RegistryKey : MarshalByRefObject, IDisposable
48 // This represents the backend data, used when creating the
53 object hive; // the RegistryHive if the key represents a base key
54 readonly string qname; // the fully qualified registry key name
55 readonly bool isRemoteRoot; // is an instance of a remote root key?
56 readonly bool isWritable; // is the key openen in writable mode
58 static readonly IRegistryApi RegistryApi;
62 if (Path.DirectorySeparatorChar == '\\')
63 RegistryApi = new Win32RegistryApi ();
65 RegistryApi = new UnixRegistryApi ();
69 /// Construct an instance of a root registry key entry.
71 internal RegistryKey (RegistryHive hiveId) : this (hiveId,
72 new IntPtr ((int) hiveId), false)
77 /// Construct an instance of a root registry key entry.
79 internal RegistryKey (RegistryHive hiveId, IntPtr keyHandle, bool remoteRoot)
83 qname = GetHiveName (hiveId);
84 isRemoteRoot = remoteRoot;
85 isWritable = true; // always consider root writable
89 /// Construct an instance of a registry key entry.
91 internal RegistryKey (object data, string keyName, bool writable)
95 isWritable = writable;
101 /// Dispose of registry key object. Close the
102 /// key if it's still open.
104 void IDisposable.Dispose ()
106 GC.SuppressFinalize (this);
112 /// Final cleanup of registry key object. Close the
113 /// key if it's still open.
122 /// Get the fully qualified registry key name.
125 get { return qname; }
130 /// Flush the current registry state to disk.
134 RegistryApi.Flush (this);
139 /// Close the current registry key and flushes the state of the registry
146 // a handle to a remote hive must be closed, while one to a local
147 // hive should not be closed
148 if (!isRemoteRoot && IsRoot)
151 RegistryApi.Close (this);
157 /// get the number of sub-keys for this key
159 public int SubKeyCount {
161 AssertKeyStillValid ();
163 return RegistryApi.SubKeyCount (this);
169 /// get the number of values for this key
171 public int ValueCount {
173 AssertKeyStillValid ();
175 return RegistryApi.ValueCount (this);
181 /// Set a registry value.
183 public void SetValue (string name, object value)
185 AssertKeyStillValid ();
188 throw new ArgumentNullException ("value");
191 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
193 RegistryApi.SetValue (this, name, value);
198 public void SetValue (string name, object value, RegistryValueKind valueKind)
200 AssertKeyStillValid ();
203 throw new ArgumentNullException ();
206 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
208 RegistryApi.SetValue (this, name, value, valueKind);
213 /// Open the sub key specified, for read access.
215 public RegistryKey OpenSubKey (string keyName)
217 return OpenSubKey (keyName, false);
222 /// Open the sub key specified.
224 public RegistryKey OpenSubKey (string keyName, bool writtable)
226 AssertKeyStillValid ();
227 AssertKeyNameNotNull (keyName);
229 return RegistryApi.OpenSubKey (this, keyName, writtable);
234 /// Get a registry value.
236 public object GetValue (string name)
238 return GetValue (name, null);
243 /// Get a registry value.
245 public object GetValue (string name, object defaultValue)
247 AssertKeyStillValid ();
249 return RegistryApi.GetValue (this, name, defaultValue,
250 RegistryValueOptions.None);
255 public object GetValue (string name, object defaultValue, RegistryValueOptions options)
257 AssertKeyStillValid ();
259 return RegistryApi.GetValue (this, name, defaultValue, options);
264 /// Create a sub key.
266 [MonoTODO("RegistryPermission")]
267 public RegistryKey CreateSubKey (string subkey)
269 AssertKeyStillValid ();
270 AssertKeyNameNotNull (subkey);
271 if (subkey.Length > 255)
272 throw new ArgumentException ("keyName length is larger than 255 characters", subkey);
275 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
276 return RegistryApi.CreateSubKey (this, subkey);
281 /// Delete the specified subkey.
283 public void DeleteSubKey(string subkey)
285 DeleteSubKey (subkey, true);
290 /// Delete the specified subkey.
292 public void DeleteSubKey(string subkey, bool throwOnMissingSubKey)
294 AssertKeyStillValid ();
295 AssertKeyNameNotNull (subkey);
298 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
300 RegistryKey child = OpenSubKey (subkey);
303 if (throwOnMissingSubKey)
304 throw new ArgumentException ("Cannot delete a subkey tree"
305 + " because the subkey does not exist.");
309 if (child.SubKeyCount > 0){
310 throw new InvalidOperationException ("Registry key has subkeys"
311 + " and recursive removes are not supported by this method.");
316 RegistryApi.DeleteKey (this, subkey, throwOnMissingSubKey);
321 /// Delete a sub tree (node, and values alike).
323 public void DeleteSubKeyTree(string keyName)
325 // Note: this is done by deleting sub-nodes recursively.
326 // The preformance is not very good. There may be a
327 // better way to implement this.
329 AssertKeyStillValid ();
330 AssertKeyNameNotNull (keyName);
332 RegistryKey child = OpenSubKey (keyName, true);
334 throw new ArgumentException ("Cannot delete a subkey tree"
335 + " because the subkey does not exist.");
337 child.DeleteChildKeysAndValues ();
339 DeleteSubKey (keyName, false);
344 /// Delete a value from the registry.
346 public void DeleteValue(string value)
348 DeleteValue (value, true);
353 /// Delete a value from the registry.
355 public void DeleteValue(string value, bool shouldThrowWhenKeyMissing)
357 AssertKeyStillValid ();
358 AssertKeyNameNotNull (value);
361 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
363 RegistryApi.DeleteValue (this, value, shouldThrowWhenKeyMissing);
368 /// Get the names of the sub keys.
370 public string[] GetSubKeyNames()
372 AssertKeyStillValid ();
374 return RegistryApi.GetSubKeyNames (this);
379 /// Get the names of values contained in this key.
381 public string[] GetValueNames()
383 AssertKeyStillValid ();
384 return RegistryApi.GetValueNames (this);
388 [MonoTODO ("Not implemented on unix")]
389 public static RegistryKey OpenRemoteBaseKey(RegistryHive hKey,string machineName)
391 if (machineName == null)
392 throw new ArgumentNullException ("machineName");
393 return RegistryApi.OpenRemoteBaseKey (hKey, machineName);
398 /// Build a string representation of the registry key.
399 /// Conatins the fully qualified key name, and the Hex
400 /// representation of the registry key handle.
402 public override string ToString()
404 AssertKeyStillValid ();
406 return RegistryApi.ToString (this);
409 #endregion // PublicAPI
411 internal bool IsRoot {
412 get { return hive != null; }
415 private bool IsWritable {
416 get { return isWritable; }
419 internal RegistryHive Hive {
422 throw new NotSupportedException ();
423 return (RegistryHive) hive;
427 // returns the key handle for the win32 implementation and the
428 // KeyHandler for the unix implementation
429 internal object Handle {
430 get { return handle; }
434 /// validate that the registry key handle is still usable.
436 private void AssertKeyStillValid ()
439 throw new ObjectDisposedException ("Microsoft.Win32.RegistryKey");
444 /// validate that the registry key handle is still usable, and
445 /// that the 'subKeyName' is not null.
447 private void AssertKeyNameNotNull (string subKeyName)
449 if (subKeyName == null)
450 throw new ArgumentNullException ();
455 /// Utility method to delelte a key's sub keys and values.
456 /// This method removes a level of indirection when deleting
459 private void DeleteChildKeysAndValues ()
464 string[] subKeys = GetSubKeyNames ();
465 foreach (string subKey in subKeys)
467 RegistryKey sub = OpenSubKey (subKey, true);
468 sub.DeleteChildKeysAndValues ();
470 DeleteSubKey (subKey, false);
473 string[] values = GetValueNames ();
474 foreach (string value in values) {
475 DeleteValue (value, false);
480 /// decode a byte array as a string, and strip trailing nulls
482 static internal string DecodeString (byte[] data)
484 string stringRep = Encoding.Unicode.GetString (data);
485 int idx = stringRep.IndexOf ('\0');
487 stringRep = stringRep.TrimEnd ('\0');
491 static internal IOException CreateMarkedForDeletionException ()
493 throw new IOException ("Illegal operation attempted on a"
494 + " registry key that has been marked for deletion.");
497 static string GetHiveName (RegistryHive hive)
500 case RegistryHive.ClassesRoot:
501 return "HKEY_CLASSES_ROOT";
502 case RegistryHive.CurrentConfig:
503 return "HKEY_CURRENT_CONFIG";
504 case RegistryHive.CurrentUser:
505 return "HKEY_CURRENT_USER";
506 case RegistryHive.DynData:
507 return "HKEY_DYN_DATA";
508 case RegistryHive.LocalMachine:
509 return "HKEY_LOCAL_MACHINE";
510 case RegistryHive.PerformanceData:
511 return "HKEY_PERFORMANCE_DATA";
512 case RegistryHive.Users:
516 throw new NotImplementedException (string.Format (
517 "Registry hive '{0}' is not implemented.", hive.ToString ()));