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 readonly string qname; // the fully qualified registry key name
54 readonly bool isRoot; // is the an instance of a root key?
55 readonly bool isWritable; // is the key openen in writable mode
57 internal bool IsRoot {
58 get { return isRoot; }
61 internal bool IsWritable {
62 get { return isWritable; }
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, string keyName)
83 isWritable = true; // always consider root writable
87 /// Construct an instance of a registry key entry.
89 internal RegistryKey (object data, string keyName, bool writable)
94 isWritable = writable;
100 /// Dispose of registry key object. Close the
101 /// key if it's still open.
103 void IDisposable.Dispose ()
105 GC.SuppressFinalize (this);
111 /// Final cleanup of registry key object. Close the
112 /// key if it's still open.
121 /// Get the fully qualified registry key name.
124 get { return qname; }
129 /// Flush the current registry state to disk.
133 RegistryApi.Flush (this);
138 /// Close the current registry key and flushes the state of the registry
148 RegistryApi.Close (this);
154 /// get the number of sub-keys for this key
156 public int SubKeyCount {
158 AssertKeyStillValid ();
160 return RegistryApi.SubKeyCount (this);
166 /// get the number of values for this key
168 public int ValueCount {
170 AssertKeyStillValid ();
172 return RegistryApi.ValueCount (this);
178 /// Set a registry value.
180 public void SetValue (string name, object value)
182 AssertKeyStillValid ();
185 throw new ArgumentNullException ("value");
188 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
190 RegistryApi.SetValue (this, name, value);
194 public void SetValue (string name, object value, RegistryValueKind valueKind)
196 AssertKeyStillValid ();
199 throw new ArgumentNullException ();
202 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
204 RegistryApi.SetValue (this, name, value, valueKind);
209 /// Open the sub key specified, for read access.
211 public RegistryKey OpenSubKey (string keyName)
213 return OpenSubKey (keyName, false);
218 /// Open the sub key specified.
220 public RegistryKey OpenSubKey (string keyName, bool writtable)
222 AssertKeyStillValid ();
223 AssertKeyNameNotNull (keyName);
225 return RegistryApi.OpenSubKey (this, keyName, writtable);
230 /// Get a registry value.
232 public object GetValue (string name)
234 return RegistryApi.GetValue (this, name, false, null);
239 /// Get a registry value.
241 public object GetValue (string name, object defaultValue)
243 AssertKeyStillValid ();
245 return RegistryApi.GetValue (this, name, true, defaultValue);
250 /// Create a sub key.
252 [MonoTODO("RegistryPermission")]
253 public RegistryKey CreateSubKey (string subkey)
255 AssertKeyStillValid ();
256 AssertKeyNameNotNull (subkey);
257 if (subkey.Length > 255)
258 throw new ArgumentException ("keyName length is larger than 255 characters", subkey);
261 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
262 return RegistryApi.CreateSubKey (this, subkey);
267 /// Delete the specified subkey.
269 public void DeleteSubKey(string subkey)
271 DeleteSubKey (subkey, true);
276 /// Delete the specified subkey.
278 public void DeleteSubKey(string subkey, bool throwOnMissingSubKey)
280 AssertKeyStillValid ();
281 AssertKeyNameNotNull (subkey);
284 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
286 RegistryKey child = OpenSubKey (subkey);
289 if (throwOnMissingSubKey)
290 throw new ArgumentException ("Cannot delete a subkey tree"
291 + " because the subkey does not exist.");
295 if (child.SubKeyCount > 0){
296 throw new InvalidOperationException ("Registry key has subkeys"
297 + " and recursive removes are not supported by this method.");
302 RegistryApi.DeleteKey (this, subkey, throwOnMissingSubKey);
307 /// Delete a sub tree (node, and values alike).
309 public void DeleteSubKeyTree(string keyName)
311 // Note: this is done by deleting sub-nodes recursively.
312 // The preformance is not very good. There may be a
313 // better way to implement this.
315 AssertKeyStillValid ();
316 AssertKeyNameNotNull (keyName);
318 RegistryKey child = OpenSubKey (keyName, true);
320 throw new ArgumentException ("Cannot delete a subkey tree"
321 + " because the subkey does not exist.");
323 child.DeleteChildKeysAndValues ();
325 DeleteSubKey (keyName, false);
330 /// Delete a value from the registry.
332 public void DeleteValue(string value)
334 DeleteValue (value, true);
339 /// Delete a value from the registry.
341 public void DeleteValue(string value, bool shouldThrowWhenKeyMissing)
343 AssertKeyStillValid ();
344 AssertKeyNameNotNull (value);
347 throw new UnauthorizedAccessException ("Cannot write to the registry key.");
349 RegistryApi.DeleteValue (this, value, shouldThrowWhenKeyMissing);
354 /// Get the names of the sub keys.
356 public string[] GetSubKeyNames()
358 AssertKeyStillValid ();
360 return RegistryApi.GetSubKeyNames (this);
365 /// Get the names of values contained in this key.
367 public string[] GetValueNames()
369 AssertKeyStillValid ();
370 return RegistryApi.GetValueNames (this);
375 public static RegistryKey OpenRemoteBaseKey(RegistryHive hKey,string machineName)
377 throw new NotImplementedException ();
382 /// Build a string representation of the registry key.
383 /// Conatins the fully qualified key name, and the Hex
384 /// representation of the registry key handle.
386 public override string ToString()
388 return RegistryApi.ToString (this);
391 #endregion // PublicAPI
395 /// validate that the registry key handle is still usable.
397 private void AssertKeyStillValid ()
400 throw new ObjectDisposedException ("Microsoft.Win32.RegistryKey");
405 /// validate that the registry key handle is still usable, and
406 /// that the 'subKeyName' is not null.
408 private void AssertKeyNameNotNull (string subKeyName)
410 if (subKeyName == null)
411 throw new ArgumentNullException ();
416 /// Utility method to delelte a key's sub keys and values.
417 /// This method removes a level of indirection when deleting
420 private void DeleteChildKeysAndValues ()
425 string[] subKeys = GetSubKeyNames ();
426 foreach (string subKey in subKeys)
428 RegistryKey sub = OpenSubKey (subKey, true);
429 sub.DeleteChildKeysAndValues ();
431 DeleteSubKey (subKey, false);
434 string[] values = GetValueNames ();
435 foreach (string value in values) {
436 DeleteValue (value, false);
441 /// decode a byte array as a string, and strip trailing nulls
443 static internal string DecodeString (byte[] data)
445 string stringRep = Encoding.Unicode.GetString (data);
446 int idx = stringRep.IndexOf ('\0');
448 stringRep = stringRep.TrimEnd ('\0');
452 static internal IOException CreateMarkedForDeletionException ()
454 throw new IOException ("Illegal operation attempted on a"
455 + " registry key that has been marked for deletion.");