// // RegistryKey.cs: a single node in the Windows registry // // Author: // Miguel de Icaza (miguel@ximian.com) // Erik LeBel (eriklebel@yahoo.ca) // Gert Driesen (drieseng@users.sourceforge.net) // // // Copyright (C) 2004 Novell, Inc (http://www.novell.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.IO; using System.Collections; using System.Diagnostics; using System.Runtime.InteropServices; using System.Security; using System.Text; namespace Microsoft.Win32 { /// /// Wrapper class for Windows Registry Entry. /// public sealed class RegistryKey : MarshalByRefObject, IDisposable { // // This represents the backend data, used when creating the // RegistryKey object // object handle; object hive; // the RegistryHive if the key represents a base key readonly string qname; // the fully qualified registry key name readonly bool isRemoteRoot; // is an instance of a remote root key? readonly bool isWritable; // is the key openen in writable mode static readonly IRegistryApi RegistryApi; static RegistryKey () { if (Path.DirectorySeparatorChar == '\\') RegistryApi = new Win32RegistryApi (); else RegistryApi = new UnixRegistryApi (); } /// /// Construct an instance of a root registry key entry. /// internal RegistryKey (RegistryHive hiveId) : this (hiveId, new IntPtr ((int) hiveId), false) { } /// /// Construct an instance of a root registry key entry. /// internal RegistryKey (RegistryHive hiveId, IntPtr keyHandle, bool remoteRoot) { hive = hiveId; handle = keyHandle; qname = GetHiveName (hiveId); isRemoteRoot = remoteRoot; isWritable = true; // always consider root writable } /// /// Construct an instance of a registry key entry. /// internal RegistryKey (object data, string keyName, bool writable) { handle = data; qname = keyName; isWritable = writable; } #region PublicAPI /// /// Dispose of registry key object. Close the /// key if it's still open. /// void IDisposable.Dispose () { GC.SuppressFinalize (this); Close (); } /// /// Final cleanup of registry key object. Close the /// key if it's still open. /// ~RegistryKey () { Close (); } /// /// Get the fully qualified registry key name. /// public string Name { get { return qname; } } /// /// Flush the current registry state to disk. /// public void Flush() { RegistryApi.Flush (this); } /// /// Close the current registry key and flushes the state of the registry /// right away. /// public void Close() { Flush (); // a handle to a remote hive must be closed, while one to a local // hive should not be closed if (!isRemoteRoot && IsRoot) return; RegistryApi.Close (this); handle = null; } /// /// get the number of sub-keys for this key /// public int SubKeyCount { get { AssertKeyStillValid (); return RegistryApi.SubKeyCount (this); } } /// /// get the number of values for this key /// public int ValueCount { get { AssertKeyStillValid (); return RegistryApi.ValueCount (this); } } /// /// Set a registry value. /// public void SetValue (string name, object value) { AssertKeyStillValid (); if (value == null) throw new ArgumentNullException ("value"); if (!IsWritable) throw new UnauthorizedAccessException ("Cannot write to the registry key."); RegistryApi.SetValue (this, name, value); } #if NET_2_0 [ComVisible (false)] public void SetValue (string name, object value, RegistryValueKind valueKind) { AssertKeyStillValid (); if (value == null) throw new ArgumentNullException (); if (!IsWritable) throw new UnauthorizedAccessException ("Cannot write to the registry key."); RegistryApi.SetValue (this, name, value, valueKind); } #endif /// /// Open the sub key specified, for read access. /// public RegistryKey OpenSubKey (string keyName) { return OpenSubKey (keyName, false); } /// /// Open the sub key specified. /// public RegistryKey OpenSubKey (string keyName, bool writtable) { AssertKeyStillValid (); AssertKeyNameNotNull (keyName); return RegistryApi.OpenSubKey (this, keyName, writtable); } /// /// Get a registry value. /// public object GetValue (string name) { return GetValue (name, null); } /// /// Get a registry value. /// public object GetValue (string name, object defaultValue) { AssertKeyStillValid (); return RegistryApi.GetValue (this, name, defaultValue, RegistryValueOptions.None); } #if NET_2_0 [ComVisible (false)] public object GetValue (string name, object defaultValue, RegistryValueOptions options) { AssertKeyStillValid (); return RegistryApi.GetValue (this, name, defaultValue, options); } #endif /// /// Create a sub key. /// [MonoTODO("RegistryPermission")] public RegistryKey CreateSubKey (string subkey) { AssertKeyStillValid (); AssertKeyNameNotNull (subkey); if (subkey.Length > 255) throw new ArgumentException ("keyName length is larger than 255 characters", subkey); if (!IsWritable) throw new UnauthorizedAccessException ("Cannot write to the registry key."); return RegistryApi.CreateSubKey (this, subkey); } /// /// Delete the specified subkey. /// public void DeleteSubKey(string subkey) { DeleteSubKey (subkey, true); } /// /// Delete the specified subkey. /// public void DeleteSubKey(string subkey, bool throwOnMissingSubKey) { AssertKeyStillValid (); AssertKeyNameNotNull (subkey); if (!IsWritable) throw new UnauthorizedAccessException ("Cannot write to the registry key."); RegistryKey child = OpenSubKey (subkey); if (child == null) { if (throwOnMissingSubKey) throw new ArgumentException ("Cannot delete a subkey tree" + " because the subkey does not exist."); return; } if (child.SubKeyCount > 0){ throw new InvalidOperationException ("Registry key has subkeys" + " and recursive removes are not supported by this method."); } child.Close (); RegistryApi.DeleteKey (this, subkey, throwOnMissingSubKey); } /// /// Delete a sub tree (node, and values alike). /// public void DeleteSubKeyTree(string keyName) { // Note: this is done by deleting sub-nodes recursively. // The preformance is not very good. There may be a // better way to implement this. AssertKeyStillValid (); AssertKeyNameNotNull (keyName); RegistryKey child = OpenSubKey (keyName, true); if (child == null) throw new ArgumentException ("Cannot delete a subkey tree" + " because the subkey does not exist."); child.DeleteChildKeysAndValues (); child.Close (); DeleteSubKey (keyName, false); } /// /// Delete a value from the registry. /// public void DeleteValue(string value) { DeleteValue (value, true); } /// /// Delete a value from the registry. /// public void DeleteValue(string value, bool shouldThrowWhenKeyMissing) { AssertKeyStillValid (); AssertKeyNameNotNull (value); if (!IsWritable) throw new UnauthorizedAccessException ("Cannot write to the registry key."); RegistryApi.DeleteValue (this, value, shouldThrowWhenKeyMissing); } /// /// Get the names of the sub keys. /// public string[] GetSubKeyNames() { AssertKeyStillValid (); return RegistryApi.GetSubKeyNames (this); } /// /// Get the names of values contained in this key. /// public string[] GetValueNames() { AssertKeyStillValid (); return RegistryApi.GetValueNames (this); } [MonoTODO ("Not implemented on unix")] public static RegistryKey OpenRemoteBaseKey(RegistryHive hKey,string machineName) { if (machineName == null) throw new ArgumentNullException ("machineName"); return RegistryApi.OpenRemoteBaseKey (hKey, machineName); } /// /// Build a string representation of the registry key. /// Conatins the fully qualified key name, and the Hex /// representation of the registry key handle. /// public override string ToString() { AssertKeyStillValid (); return RegistryApi.ToString (this); } #endregion // PublicAPI internal bool IsRoot { get { return hive != null; } } private bool IsWritable { get { return isWritable; } } internal RegistryHive Hive { get { if (!IsRoot) throw new NotSupportedException (); return (RegistryHive) hive; } } // returns the key handle for the win32 implementation and the // KeyHandler for the unix implementation internal object Handle { get { return handle; } } /// /// validate that the registry key handle is still usable. /// private void AssertKeyStillValid () { if (handle == null) throw new ObjectDisposedException ("Microsoft.Win32.RegistryKey"); } /// /// validate that the registry key handle is still usable, and /// that the 'subKeyName' is not null. /// private void AssertKeyNameNotNull (string subKeyName) { if (subKeyName == null) throw new ArgumentNullException (); } /// /// Utility method to delelte a key's sub keys and values. /// This method removes a level of indirection when deleting /// key node trees. /// private void DeleteChildKeysAndValues () { if (IsRoot) return; string[] subKeys = GetSubKeyNames (); foreach (string subKey in subKeys) { RegistryKey sub = OpenSubKey (subKey, true); sub.DeleteChildKeysAndValues (); sub.Close (); DeleteSubKey (subKey, false); } string[] values = GetValueNames (); foreach (string value in values) { DeleteValue (value, false); } } /// /// decode a byte array as a string, and strip trailing nulls /// static internal string DecodeString (byte[] data) { string stringRep = Encoding.Unicode.GetString (data); int idx = stringRep.IndexOf ('\0'); if (idx != -1) stringRep = stringRep.TrimEnd ('\0'); return stringRep; } static internal IOException CreateMarkedForDeletionException () { throw new IOException ("Illegal operation attempted on a" + " registry key that has been marked for deletion."); } static string GetHiveName (RegistryHive hive) { switch (hive) { case RegistryHive.ClassesRoot: return "HKEY_CLASSES_ROOT"; case RegistryHive.CurrentConfig: return "HKEY_CURRENT_CONFIG"; case RegistryHive.CurrentUser: return "HKEY_CURRENT_USER"; case RegistryHive.DynData: return "HKEY_DYN_DATA"; case RegistryHive.LocalMachine: return "HKEY_LOCAL_MACHINE"; case RegistryHive.PerformanceData: return "HKEY_PERFORMANCE_DATA"; case RegistryHive.Users: return "HKEY_USERS"; } throw new NotImplementedException (string.Format ( "Registry hive '{0}' is not implemented.", hive.ToString ())); } } }