[Test] Avoid MethodInfoTest.GetMethodBody failure when executed on a release (IL...
[mono.git] / mcs / class / corlib / Microsoft.Win32 / RegistryKey.cs
index dbad875b11f637f8bff4c0dc405c1bbf795e66a6..2d742a6ee9385007de91fb0778d6a17ee4953dd6 100644 (file)
@@ -4,8 +4,8 @@
 // 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)
 //
@@ -29,6 +29,8 @@
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
+#if !NET_2_1
+
 using System;
 using System.IO;
 using System.Collections;
@@ -36,96 +38,86 @@ using System.Diagnostics;
 using System.Runtime.InteropServices;
 using System.Security;
 using System.Text;
+using System.Security.AccessControl;
+using System.Security.Permissions;
+using Microsoft.Win32.SafeHandles;
 
 namespace Microsoft.Win32
 {
        /// <summary>
        ///     Wrapper class for Windows Registry Entry.
        /// </summary>
+       [ComVisible (true)]
        public sealed class RegistryKey : MarshalByRefObject, IDisposable 
        {
-               const char NullChar = '\0';
-               
-               // Arbitrary max size for key/values names that can be fetched.
-               // .NET framework SDK docs say that the max name length that can 
-               // be used is 255 characters, we'll allow for a bit more.
-               const int BufferMaxLength = 1024;
+               //
+               // This represents the backend data, used when creating the
+               // RegistryKey object
+               //
+               object handle;
+#if NET_4_0
+               SafeRegistryHandle safe_handle;
+#endif
 
-               // FIXME must be a way to determin this dynamically?
-               const int Int32ByteSize = 4;
+               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
 
-               // FIXME this is hard coded on Mono, can it be determined dynamically? 
-               readonly int NativeBytesPerCharacter = Marshal.SystemDefaultCharSize;
+               static readonly IRegistryApi RegistryApi;
 
-               // FIXME this should be determined dynamically.
-               // It will be used to decode some return strings
-               // for which embeded '\0' must be preserved.
-               readonly Encoding Decoder = Encoding.Unicode;
-               
-               
-               IntPtr hkey;    // the reg key handle
-               string qname;   // the fully qualified registry key name
-               bool isRoot;    // is the an instance of a root key?
-               
-               IRegistryApi reg_api;
+               static RegistryKey ()
+               {
+                       if (Path.DirectorySeparatorChar == '\\')
+                               RegistryApi = new Win32RegistryApi ();
+                       else
+                               RegistryApi = new UnixRegistryApi ();
+               }
 
                /// <summary>
                ///     Construct an instance of a root registry key entry.
                /// </summary>
-               internal RegistryKey (RegistryHive hiveId, string keyName)
+               internal RegistryKey (RegistryHive hiveId) : this (hiveId, 
+                       new IntPtr ((int) hiveId), false)
                {
-                       hkey = new IntPtr ((int)hiveId);
-                       qname = keyName;
-                       isRoot = true;
-
-                       InitRegistryApi ();
                }
-               
+
                /// <summary>
-               ///     Construct an instance of a registry key entry.
+               ///     Construct an instance of a root registry key entry.
                /// </summary>
-               internal RegistryKey (IntPtr hkey, string keyName)
-               {
-                       this.hkey = hkey;
-                       qname = keyName;
-                       isRoot = false;
-
-                       InitRegistryApi ();
-               }
-
-               internal void InitRegistryApi ()
+               internal RegistryKey (RegistryHive hiveId, IntPtr keyHandle, bool remoteRoot)
                {
-                       if (Path.DirectorySeparatorChar == '\\')
-                               reg_api = new Win32RegistryApi ();
-               }
-
-               private IRegistryApi RegistryApi {
-                       get {
-                               if (reg_api == null)
-                                       throw new NotImplementedException ("The registry is" +
-                                                       " only available on Windows.");
-                               return reg_api;
-                       }
+                       hive = hiveId;
+                       handle = keyHandle;
+                       qname = GetHiveName (hiveId);
+                       isRemoteRoot = remoteRoot;
+                       isWritable = true; // always consider root writable
                }
 
                /// <summary>
-               ///     Fetch the inetrnal registry key.
+               ///     Construct an instance of a registry key entry.
                /// </summary>
-               private IntPtr Handle {
-                       get { return hkey; }
+               internal RegistryKey (object data, string keyName, bool writable)
+               {
+                       handle = data;
+                       qname = keyName;
+                       isWritable = writable;
                }
 
-               
                #region PublicAPI
 
                /// <summary>
                ///     Dispose of registry key object. Close the 
                ///     key if it's still open.
                /// </summary>
+#if NET_4_0
+               public void Dispose ()
+#else
                void IDisposable.Dispose ()
+#endif
                {
-                       Close ();
                        GC.SuppressFinalize (this);
+                       Close ();
                }
 
                
@@ -152,25 +144,28 @@ namespace Microsoft.Win32
                /// </summary>
                public void Flush()
                {
-                       RegTrace (" +Flush");
-                       RegistryApi.RegFlushKey (Handle);
-                       RegTrace (" -Flush");
+                       RegistryApi.Flush (this);
                }
                
                
                /// <summary>
-               ///     Close the current registry key. This may not 
-               ///     flush the state of the registry right away.
+               ///     Close the current registry key and flushes the state of the registry
+               /// right away.
                /// </summary>
                public void Close()
                {
-                       if (isRoot)
+                       Flush ();
+
+                       // a handle to a remote hive must be closed, while one to a local
+                       // hive should not be closed
+                       if (!isRemoteRoot && IsRoot)
                                return;
                        
-                       RegTrace (" +Close");
-                       RegistryApi.RegCloseKey (Handle);
-                       hkey = IntPtr.Zero;
-                       RegTrace (" -Close");
+                       RegistryApi.Close (this);
+                       handle = null;
+#if NET_4_0
+                       safe_handle = null;
+#endif
                }
                
                
@@ -179,31 +174,9 @@ namespace Microsoft.Win32
                /// </summary>
                public int SubKeyCount {
                        get {
-                               RegTrace (" +SubKeyCount");
                                AssertKeyStillValid ();
-                               
-                               int index, result;
-                               byte[] stringBuffer = new byte [BufferMaxLength];
-
-                               for (index = 0; true; index ++)
-                               {
-                                       result = RegistryApi.RegEnumKey (Handle, index, 
-                                                       stringBuffer, BufferMaxLength);
-                                       
-                                       if (result == Win32ResultCode.Success)
-                                               continue;
-                                       
-                                       if (result == Win32ResultCode.NoMoreEntries)
-                                               break;
-                                       
-                                       // something is wrong!!
-                                       RegTrace ("Win32Api::ReEnumKey  result='{0}'  name='{1}'", 
-                                                       result, Name);
-                                       GenerateException (result);
-                               }
-                               
-                               RegTrace (" -SubKeyCount");
-                               return index;
+
+                               return RegistryApi.SubKeyCount (this);
                        }
                }
 
@@ -213,37 +186,36 @@ namespace Microsoft.Win32
                /// </summary>
                public int ValueCount {
                        get {
-                               RegTrace (" +ValueCount");      
                                AssertKeyStillValid ();
-                       
-                               int index, result, type, bufferCapacity;
-                               StringBuilder buffer = new StringBuilder (BufferMaxLength);
-                               
-                               for (index = 0; true; index ++)
-                               {
-                                       type = 0;
-                                       bufferCapacity = buffer.Capacity;
-                                       result = RegistryApi.RegEnumValue (Handle, index, 
-                                                       buffer, ref bufferCapacity,
-                                                       IntPtr.Zero, ref type, 
-                                                       IntPtr.Zero, IntPtr.Zero);
-
-                                       if (result == Win32ResultCode.Success || result == Win32ResultCode.MoreData)
-                                               continue;
-                                       
-                                       if (result == Win32ResultCode.NoMoreEntries)
-                                               break;
-
-                                       // something is wrong
-                                       RegTrace ("Win32Api::RegEnumValue  result='{0}'  name='{1}'", 
-                                                       result, Name);
-                                       GenerateException (result);
+
+                               return RegistryApi.ValueCount (this);
+                       }
+               }
+
+#if NET_4_0
+               [ComVisible (false)]
+               [MonoTODO ("Not implemented in Unix")]
+               public SafeRegistryHandle Handle {
+                       get {
+                               AssertKeyStillValid ();
+
+                               if (safe_handle == null) {
+                                       IntPtr h = RegistryApi.GetHandle (this);
+                                       safe_handle = new SafeRegistryHandle (h, true);
                                }
 
-                               RegTrace (" -ValueCount");
-                               return index;
+                               return safe_handle;
+                       }
+               }
+
+               [ComVisible (false)]
+               [MonoLimitation ("View is ignored in Mono.")]
+               public RegistryView View {
+                       get {
+                               return RegistryView.Default;
                        }
                }
+#endif
 
                
                /// <summary>
@@ -251,110 +223,59 @@ namespace Microsoft.Win32
                /// </summary>
                public void SetValue (string name, object value)
                {
-                       RegTrace (" +SetValue");
                        AssertKeyStillValid ();
-                       
+
                        if (value == null)
-                               throw new ArgumentNullException ();
-                       
-                       Type type = value.GetType ();
-                       int result;
+                               throw new ArgumentNullException ("value");
 
-                       if (type == typeof (int))
-                       {
-                               int rawValue = (int)value;
-                               result = RegistryApi.RegSetValueEx (Handle, name, 
-                                               IntPtr.Zero, RegistryApi.RegDwordType, 
-                                               ref rawValue, Int32ByteSize); 
-                       }
-                       else if (type == typeof (byte[]))
-                       {
-                               byte[] rawValue = (byte[]) value;
-                               result = RegistryApi.RegSetValueEx (Handle, name,
-                                               IntPtr.Zero, RegistryApi.RegBinaryType,
-                                               rawValue, rawValue.Length);
-                       }
-                       else if (type == typeof (string[]))
-                       {
-                               string[] vals = (string[]) value;
-                               StringBuilder fullStringValue = new StringBuilder ();
-                               foreach (string v in vals)
-                               {
-                                       fullStringValue.Append (v);
-                                       fullStringValue.Append (NullChar);
-                               }
-                               fullStringValue.Append (NullChar);
+                       if (name != null)
+                               AssertKeyNameLength (name);
 
-                               byte[] rawValue = Decoder.GetBytes (fullStringValue.ToString ());
-                       
-                               result = RegistryApi.RegSetValueEx (Handle, name, 
-                                               IntPtr.Zero, RegistryApi.RegStringArrayType, 
-                                               rawValue, rawValue.Length); 
-                       }
-                       else if (type.IsArray)
-                       {
-                               throw new ArgumentException ("Only string and byte arrays can written as registry values");
-                       }
-                       else
-                       {
-                               string rawValue = String.Format ("{0}{1}", value, NullChar);
-                               result = RegistryApi.RegSetValueEx (Handle, name,
-                                               IntPtr.Zero, RegistryApi.RegStringType,
-                                               rawValue, rawValue.Length * NativeBytesPerCharacter);
-                       }
+                       if (!IsWritable)
+                               throw new UnauthorizedAccessException ("Cannot write to the registry key.");
 
-                       // handle the result codes
-                       if (result != Win32ResultCode.Success)
-                       {
-                               RegTrace ("Win32Api::RegSetValueEx: result: {0}", result);
-                               GenerateException (result);
-                       }
+                       RegistryApi.SetValue (this, name, value);
+               }
+
+               [ComVisible (false)]
+               public void SetValue (string name, object value, RegistryValueKind valueKind)
+               {
+                       AssertKeyStillValid ();
                        
-                       RegTrace (" -SetValue");
+                       if (value == null)
+                               throw new ArgumentNullException ("value");
+
+                       if (name != null)
+                               AssertKeyNameLength (name);
+
+                       if (!IsWritable)
+                               throw new UnauthorizedAccessException ("Cannot write to the registry key.");
+
+                       RegistryApi.SetValue (this, name, value, valueKind);
                }
 
-               
                /// <summary>
                ///     Open the sub key specified, for read access.
                /// </summary>
-               public RegistryKey OpenSubKey (string keyName)
+               public RegistryKey OpenSubKey (string name)
                {
-                       return OpenSubKey (keyName, false);
+                       return OpenSubKey (name, false);
                }
 
                
                /// <summary>
                ///     Open the sub key specified.
                /// </summary>
-               public RegistryKey OpenSubKey (string keyName, bool writtable)
+               public RegistryKey OpenSubKey (string name, bool writable)
                {
-                       RegTrace (" +OpenSubKey");
                        AssertKeyStillValid ();
-                       AssertKeyNameNotNull (keyName);
-                       
-                       int access = RegistryApi.OpenRegKeyRead;
-                       if (writtable) access |= RegistryApi.OpenRegKeyWrite;
-                       
-                       IntPtr subKeyHandle;
-                       int result = RegistryApi.RegOpenKeyEx (Handle, keyName, IntPtr.Zero, 
-                                       access, out subKeyHandle);
 
-                       if (result == Win32ResultCode.FileNotFound)
-                       {
-                               RegTrace (" -OpenSubKey");
-                               return null;
-                       }
-                       
-                       if (result != Win32ResultCode.Success)
-                       {
-                               RegTrace ("Win32Api::RegOpenKeyEx  result='{0}'  key name='{1}'", 
-                                               result, CombineName (keyName));
-                               GenerateException (result);
-                       }
-                       
-                       RegistryKey subKey = new RegistryKey (subKeyHandle, CombineName (keyName));
-                       RegTrace (" -OpenSubKey");
-                       return subKey;
+                       if (name == null)
+                               throw new ArgumentNullException ("name");
+
+                       AssertKeyNameLength (name);
+
+                       return RegistryApi.OpenSubKey (this, name, writable);
                }
                
                
@@ -363,10 +284,7 @@ namespace Microsoft.Win32
                /// </summary>
                public object GetValue (string name)
                {
-                       RegTrace (" +GetValue");
-                       object obj = GetValueImpl (name, false, null);
-                       RegTrace (" -GetValue");
-                       return obj;
+                       return GetValue (name, null);
                }
 
                
@@ -375,37 +293,78 @@ namespace Microsoft.Win32
                /// </summary>
                public object GetValue (string name, object defaultValue)
                {
-                       RegTrace (" +GetValue");
-                       object obj = GetValueImpl (name, true, defaultValue);
-                       RegTrace (" -GetValue");
-                       return obj;
+                       AssertKeyStillValid ();
+                       
+                       return RegistryApi.GetValue (this, name, defaultValue,
+                               RegistryValueOptions.None);
+               }
+
+               [ComVisible (false)]
+               public object GetValue (string name, object defaultValue, RegistryValueOptions options)
+               {
+                       AssertKeyStillValid ();
+
+                       return RegistryApi.GetValue (this, name, defaultValue, options);
+               }
+
+               [ComVisible (false)]
+               public RegistryValueKind GetValueKind (string name)
+               {
+                       return RegistryApi.GetValueKind (this, name);
                }
 
-               
                /// <summary>
                ///     Create a sub key.
                /// </summary>
-               public RegistryKey CreateSubKey (string keyName)
+               public RegistryKey CreateSubKey (string subkey)
                {
-                       RegTrace (" +CreateSubKey");
                        AssertKeyStillValid ();
-                       AssertKeyNameNotNull (keyName);
-                       
-                       IntPtr subKeyHandle;
-                       int result = RegistryApi.RegCreateKey (Handle , keyName, out subKeyHandle);
+                       AssertKeyNameNotNull (subkey);
+                       AssertKeyNameLength (subkey);
 
-                       if (result != Win32ResultCode.Success)
-                       {
-                               RegTrace ("Win32Api::RegCreateKey: result='{0}' key name='{1}'", 
-                                               result, CombineName (keyName));
-                               GenerateException (result);
-                       }
-                       
-                       RegistryKey subKey = new RegistryKey (subKeyHandle, CombineName (keyName));
-                       RegTrace (" -CreateSubKey");
-                       return subKey;
+                       if (!IsWritable)
+                               throw new UnauthorizedAccessException ("Cannot write to the registry key.");
+                       return RegistryApi.CreateSubKey (this, subkey);
                }
-               
+
+               [ComVisible (false)]
+               [MonoLimitation ("permissionCheck is ignored in Mono")]
+               public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck)
+               {
+                       return CreateSubKey (subkey);
+               }
+
+               [ComVisible (false)]
+               [MonoLimitation ("permissionCheck and registrySecurity are ignored in Mono")]
+               public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistrySecurity registrySecurity)
+               {
+                       return CreateSubKey (subkey);
+               }
+
+#if NET_4_0
+               [ComVisible (false)]
+               [MonoLimitation ("permissionCheck is ignored in Mono")]
+               public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistryOptions options)
+               {
+                       AssertKeyStillValid ();
+                       AssertKeyNameNotNull (subkey);
+                       AssertKeyNameLength (subkey);
+
+                       if (!IsWritable)
+                               throw new UnauthorizedAccessException ("Cannot write to the registry key.");
+
+                       return RegistryApi.CreateSubKey (this, subkey, options);
+               }
+
+               [ComVisible (false)]
+               [MonoLimitation ("permissionCheck and registrySecurity are ignored in Mono")]
+               public RegistryKey CreateSubKey (string subkey, RegistryKeyPermissionCheck permissionCheck, RegistryOptions registryOptions,
+                       RegistrySecurity registrySecurity)
+               {
+                       return CreateSubKey (subkey, permissionCheck, registryOptions);
+               }
+#endif
+
                
                /// <summary>
                ///     Delete the specified subkey.
@@ -419,106 +378,106 @@ namespace Microsoft.Win32
                /// <summary>
                ///     Delete the specified subkey.
                /// </summary>
-               public void DeleteSubKey(string keyName, bool shouldThrowWhenKeyMissing)
+               public void DeleteSubKey(string subkey, bool throwOnMissingSubKey)
                {
-                       RegTrace (" +DeleteSubKey");
                        AssertKeyStillValid ();
-                       AssertKeyNameNotNull (keyName);
-                       
-                       RegistryKey child = OpenSubKey (keyName);
+                       AssertKeyNameNotNull (subkey);
+                       AssertKeyNameLength (subkey);
+
+                       if (!IsWritable)
+                               throw new UnauthorizedAccessException ("Cannot write to the registry key.");
+
+                       RegistryKey child = OpenSubKey (subkey);
                        
-                       if (child == null)
-                       {
-                               if (shouldThrowWhenKeyMissing)
-                                       throw new ArgumentException ("key " + keyName);
-                               RegTrace (" -DeleteSubKey");
+                       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 ("key " + keyName + " has sub keys");
-                       
-                       child.Close ();
-
-                       int result = RegistryApi.RegDeleteKey (Handle, keyName);
-                       if (result == Win32ResultCode.FileNotFound)
-                       {
-                               if (shouldThrowWhenKeyMissing)
-                                       throw new ArgumentException ("key " + keyName);
-                               RegTrace (" -DeleteSubKey");
-                               return;
+                       if (child.SubKeyCount > 0){
+                               throw new InvalidOperationException ("Registry key has subkeys"
+                                       + " and recursive removes are not supported by this method.");
                        }
                        
-                       if (result != Win32ResultCode.Success)
-                       {
-                               RegTrace ("Win32Api::RegDeleteKey: result='{0}' key name='{1}'", 
-                                               result, CombineName (keyName));
-                               GenerateException (result);
-                       }
+                       child.Close ();
 
-                       RegTrace (" -DeleteSubKey");
+                       RegistryApi.DeleteKey (this, subkey, throwOnMissingSubKey);
                }
                
                
                /// <summary>
                ///     Delete a sub tree (node, and values alike).
                /// </summary>
-               public void DeleteSubKeyTree(string keyName)
+               public void DeleteSubKeyTree(string subkey)
+               {
+                       DeleteSubKeyTree (subkey, true);
+               }
+
+#if NET_4_0
+               public
+#endif
+               void DeleteSubKeyTree (string subkey, bool throwOnMissingSubKey)
                {
                        // Note: this is done by deleting sub-nodes recursively.
                        // The preformance is not very good. There may be a 
                        // better way to implement this.
-                       RegTrace (" +DeleteSubKeyTree");
+                       
                        AssertKeyStillValid ();
-                       AssertKeyNameNotNull (keyName);
+                       AssertKeyNameNotNull (subkey);
+                       AssertKeyNameLength (subkey);
                        
-                       RegistryKey child = OpenSubKey (keyName, true);
-                       if (child == null)
-                               throw new ArgumentException ("key " + keyName);
+                       RegistryKey child = OpenSubKey (subkey, true);
+                       if (child == null) {
+                               if (!throwOnMissingSubKey)
+                                       return;
+
+                               throw new ArgumentException ("Cannot delete a subkey tree"
+                                       + " because the subkey does not exist.");
+                       }
 
                        child.DeleteChildKeysAndValues ();
                        child.Close ();
-                       DeleteSubKey (keyName, false);
-                       RegTrace (" -DeleteSubKeyTree");
+                       DeleteSubKey (subkey, false);
                }
                
 
                /// <summary>
                ///     Delete a value from the registry.
                /// </summary>
-               public void DeleteValue(string value)
+               public void DeleteValue(string name)
                {
-                       DeleteValue (value, true);
+                       DeleteValue (name, true);
                }
                
                
                /// <summary>
                ///     Delete a value from the registry.
                /// </summary>
-               public void DeleteValue(string value, bool shouldThrowWhenKeyMissing)
+               public void DeleteValue(string name, bool throwOnMissingValue)
                {
-                       RegTrace (" +DeleteValue");
                        AssertKeyStillValid ();
-                       AssertKeyNameNotNull (value);
-                       
-                       int result = RegistryApi.RegDeleteValue (Handle, value);
-                       
-                       if (result == Win32ResultCode.FileNotFound)
-                       {
-                               if (shouldThrowWhenKeyMissing)
-                                       throw new ArgumentException ("value " + value);
-                               RegTrace (" -DeleteValue");
-                               return;
-                       }
-                       
-                       if (result != Win32ResultCode.Success)
-                       {
-                               RegTrace ("Win32Api::RegDeleteValue: result='{0}' value name='{1}'", 
-                                               result, CombineName (value));
-                               GenerateException (result);
-                       }
-                       
-                       RegTrace (" -DeleteValue");
+
+                       if (name == null)
+                               throw new ArgumentNullException ("name");
+
+                       if (!IsWritable)
+                               throw new UnauthorizedAccessException ("Cannot write to the registry key.");
+
+                       RegistryApi.DeleteValue (this, name, throwOnMissingValue);
+               }
+
+               public RegistrySecurity GetAccessControl ()
+               {
+                       return GetAccessControl (AccessControlSections.Owner |
+                                                AccessControlSections.Group |
+                                                AccessControlSections.Access);
+               }
+               
+               public RegistrySecurity GetAccessControl (AccessControlSections includeSections)
+               {
+                       return new RegistrySecurity (Name, includeSections);
                }
                
                
@@ -527,34 +486,9 @@ namespace Microsoft.Win32
                /// </summary>
                public string[] GetSubKeyNames()
                {
-                       RegTrace (" +GetSubKeyNames");
                        AssertKeyStillValid ();
-                       
-                       byte[] buffer = new byte [BufferMaxLength];
-                       int bufferCapacity = BufferMaxLength;
-                       ArrayList keys = new ArrayList ();
-                               
-                       for (int index = 0; true; index ++)
-                       {
-                               int result = RegistryApi.RegEnumKey (Handle, index, buffer, bufferCapacity);
-
-                               if (result == Win32ResultCode.Success)
-                               {
-                                       keys.Add (DecodeString (buffer));
-                                       continue;
-                               }
-
-                               if (result == Win32ResultCode.NoMoreEntries)
-                                       break;
 
-                               // should not be here!
-                               RegTrace ("Win32Api::RegEnumKey: result='{0}' value name='{1}'", 
-                                               result, CombineName (Name));
-                               GenerateException (result);
-                       }
-
-                       RegTrace (" -GetSubKeyNames");
-                       return (string []) keys.ToArray (typeof(String));
+                       return RegistryApi.GetSubKeyNames (this);
                }
                
                
@@ -563,44 +497,94 @@ namespace Microsoft.Win32
                /// </summary>
                public string[] GetValueNames()
                {
-                       RegTrace (" +GetValueNames");
                        AssertKeyStillValid ();
-                       
-                       ArrayList values = new ArrayList ();
-                       
-                       for (int index = 0; true; index ++)
-                       {
-                               StringBuilder buffer = new StringBuilder (BufferMaxLength);
-                               int bufferCapacity = buffer.Capacity;
-                               int type = 0;
-                               
-                               int result = RegistryApi.RegEnumValue (Handle, index, buffer, ref bufferCapacity,
-                                                       IntPtr.Zero, ref type, IntPtr.Zero, IntPtr.Zero);
+                       return RegistryApi.GetValueNames (this);
+               }
 
-                               if (result == Win32ResultCode.Success || result == Win32ResultCode.MoreData)
-                               {
-                                       values.Add (buffer.ToString ());
-                                       continue;
-                               }
-                               
-                               if (result == Win32ResultCode.NoMoreEntries)
-                                       break;
-                                       
-                               // should not be here!
-                               RegTrace ("RegistryApi.RegEnumValue: result code='{0}' name='{1}'", 
-                                               result, CombineName (Name));
-                               GenerateException (result);
-                       }
+#if NET_4_0
+               [ComVisible (false)]
+               [SecurityPermission (SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
+               [MonoTODO ("Not implemented on unix")]
+               public static RegistryKey FromHandle (SafeRegistryHandle handle)
+               {
+                       if (handle == null)
+                               throw new ArgumentNullException ("handle");
 
-                       RegTrace (" -GetValueNames");
-                       return (string []) values.ToArray (typeof(String));
+                       return RegistryApi.FromHandle (handle);
                }
+
+               [ComVisible (false)]
+               [SecurityPermission (SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
+               [MonoTODO ("Not implemented on unix")]
+               public static RegistryKey FromHandle (SafeRegistryHandle handle, RegistryView view)
+               {
+                       return FromHandle (handle);
+               }
+#endif
                
                
-               [MonoTODO]
+               [MonoTODO ("Not implemented on unix")]
                public static RegistryKey OpenRemoteBaseKey(RegistryHive hKey,string machineName)
                {
-                       throw new NotImplementedException ();
+                       if (machineName == null)
+                               throw new ArgumentNullException ("machineName");
+                       return RegistryApi.OpenRemoteBaseKey (hKey, machineName);
+               }
+
+#if NET_4_0
+               [ComVisible (false)]
+               [MonoTODO ("Not implemented on unix")]
+               public static RegistryKey OpenRemoteBaseKey (RegistryHive hKey, string machineName, RegistryView view)
+               {
+                       if (machineName == null)
+                               throw new ArgumentNullException ("machineName");
+                       return RegistryApi.OpenRemoteBaseKey (hKey, machineName);
+               }
+
+               [ComVisible (false)]
+               [MonoLimitation ("View is ignored in Mono")]
+               public static RegistryKey OpenBaseKey (RegistryHive hKey, RegistryView view)
+               {
+                       switch (hKey) {
+                               case RegistryHive.ClassesRoot:
+                                       return Registry.ClassesRoot;
+                               case RegistryHive.CurrentConfig:
+                                       return Registry.CurrentConfig;
+                               case RegistryHive.CurrentUser:
+                                       return Registry.CurrentUser;
+                               case RegistryHive.DynData:
+                                       return Registry.DynData;
+                               case RegistryHive.LocalMachine:
+                                       return Registry.LocalMachine;
+                               case RegistryHive.PerformanceData:
+                                       return Registry.PerformanceData;
+                               case RegistryHive.Users:
+                                       return Registry.Users;
+                       }
+
+                       throw new ArgumentException ("hKey");
+               }
+#endif
+
+               [ComVisible (false)]
+               public RegistryKey OpenSubKey (string name, RegistryKeyPermissionCheck permissionCheck)
+               {
+                       return OpenSubKey (name, permissionCheck == RegistryKeyPermissionCheck.ReadWriteSubTree);
+               }
+               
+               [ComVisible (false)]
+               [MonoLimitation ("rights are ignored in Mono")]
+               public RegistryKey OpenSubKey (string name, RegistryKeyPermissionCheck permissionCheck, RegistryRights rights)
+               {
+                       return OpenSubKey (name, permissionCheck == RegistryKeyPermissionCheck.ReadWriteSubTree);
+               }
+               
+               public void SetAccessControl (RegistrySecurity registrySecurity)
+               {
+                       if (null == registrySecurity)
+                               throw new ArgumentNullException ("registrySecurity");
+                               
+                       registrySecurity.PersistModifications (Name);
                }
                
                
@@ -611,18 +595,41 @@ namespace Microsoft.Win32
                /// </summary>
                public override string ToString()
                {
-                       return String.Format ("{0} [0x{1:X}]", Name, Handle.ToInt32 ());
+                       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 InternalHandle {
+                       get { return handle; }
+               }
+
                /// <summary>
                /// validate that the registry key handle is still usable.
                /// </summary>
                private void AssertKeyStillValid ()
                {
-                       if (Handle == IntPtr.Zero)
+                       if (handle == null)
                                throw new ObjectDisposedException ("Microsoft.Win32.RegistryKey");
                }
 
@@ -634,9 +641,14 @@ namespace Microsoft.Win32
                private void AssertKeyNameNotNull (string subKeyName)
                {
                        if (subKeyName == null)
-                               throw new ArgumentNullException ();
+                               throw new ArgumentNullException ("name");
+               }
+
+               private void AssertKeyNameLength (string name)
+               {
+                       if (name.Length > 255)
+                               throw new ArgumentException ("Name of registry key cannot be greater than 255 characters");
                }
-               
 
                /// <summary>
                ///     Utility method to delelte a key's sub keys and values.
@@ -645,12 +657,8 @@ namespace Microsoft.Win32
                /// </summary>
                private void DeleteChildKeysAndValues ()
                {
-                       RegTrace (" +DeleteChildKeysAndValues");
-                       if (isRoot)
-                       {
-                               RegTrace (" -DeleteChildKeysAndValues");
+                       if (IsRoot)
                                return;
-                       }
                        
                        string[] subKeys = GetSubKeyNames ();
                        foreach (string subKey in subKeys)
@@ -662,167 +670,54 @@ namespace Microsoft.Win32
                        }
 
                        string[] values = GetValueNames ();
-                       foreach (string value in values)
-                       {
+                       foreach (string value in values) {
                                DeleteValue (value, false);
                        }
-                       
-                       RegTrace (" -DeleteChildKeysAndValues");
                }
 
-
-               /// <summary>
-               ///     Acctually read a registry value. Requires knoledge of the
-               ///     value's type and size.
-               /// </summary>
-               private object GetValueImpl (string name, bool returnDefaultValue, object defaultValue)
-               {
-                       RegTrace (" +GetValueImpl");
-                       AssertKeyStillValid ();
-                       
-                       int type = 0;
-                       int size = 0;
-                       object obj = null;
-                       
-                       int result = RegistryApi.RegQueryValueEx (Handle, name, IntPtr.Zero,
-                                       ref type, IntPtr.Zero, ref size);
-
-                       if (result == Win32ResultCode.FileNotFound)
-                       {
-                               if (returnDefaultValue) {
-                                       RegTrace (" -GetValueImpl");
-                                       return defaultValue;
-                               }
-                               return null;
-                       }
-                       
-                       if (result != Win32ResultCode.MoreData && result != Win32ResultCode.Success )
-                       {
-                               RegTrace ("Win32Api::RegQueryValueEx: result='{0}'  name='{1}'  type='{2}'  size='{3}'",        
-                                               result, name, type, size);
-                               GenerateException (result);
-                       }
-                       
-                       if (type == RegistryApi.RegStringType || type == RegistryApi.RegEnvironmentString)
-                       {
-                               byte[] data;
-                               result = GetBinaryValue (name, type, out data, size);
-                               obj = DecodeString (data);
-                       }
-                       else if (type == RegistryApi.RegDwordType)
-                       {
-                               int data = 0;
-                               result = RegistryApi.RegQueryValueEx (Handle, name, IntPtr.Zero,
-                                               ref type, ref data, ref size);
-                               obj = data;
-                       }
-                       else if (type == RegistryApi.RegBinaryType)
-                       {
-                               byte[] data;
-                               result = GetBinaryValue (name, type, out data, size);
-                               obj = data;
-                       }
-                       else if (type == RegistryApi.RegStringArrayType)
-                       {
-                               obj = null;
-                               byte[] data;
-                               result = GetBinaryValue (name, type, out data, size);
-                               
-                               if (result == Win32ResultCode.Success)
-                                       obj = DecodeString (data).Split (NullChar);
-                       }
-                       else
-                       {
-                               // should never get here
-                               throw new SystemException ();
-                       }
-
-                       // check result codes again:
-                       if (result != Win32ResultCode.Success)
-                       {
-                               RegTrace ("Win32Api::RegQueryValueEx: result='{0}' name='{1}'", 
-                                               result, name);
-                               GenerateException (result);
-                       }
-                       
-                       RegTrace (" -ReadValueImpl");
-                       return obj;
-               }
-
-               
-               /// <summary>
-               ///     Get a binary value.
-               /// </summary>
-               private int GetBinaryValue (string name, int type, out byte[] data, int size)
-               {
-                       byte[] internalData = new byte [size];
-                       int result = RegistryApi.RegQueryValueEx (Handle, name, 
-                                       IntPtr.Zero, ref type, internalData, ref size);
-                       data = internalData;
-                       return result;
-               }
-
-               
                /// <summary>
                ///     decode a byte array as a string, and strip trailing nulls
                /// </summary>
-               private string DecodeString (byte[] data)
+               static internal string DecodeString (byte[] data)
                {
-                       string stringRep = Decoder.GetString (data);
-                       int idx = stringRep.IndexOf (NullChar);
-                       if (idx >= 0)
-                                       stringRep = stringRep.Substring (0, idx);
+                       string stringRep = Encoding.Unicode.GetString (data);
+                       int idx = stringRep.IndexOf ('\0');
+                       if (idx != -1)
+                               stringRep = stringRep.TrimEnd ('\0');
                        return stringRep;
                }
-               
-               
-               /// <summary>
-               ///     utility: Combine the sub key name to the current name to produce a 
-               ///     fully qualified sub key name.
-               /// </summary>
-               private string CombineName (string localName)
+
+               static internal IOException CreateMarkedForDeletionException ()
                {
-                       return String.Format ("{0}\\{1}", Name, localName);
+                       throw new IOException ("Illegal operation attempted on a"
+                               + " registry key that has been marked for deletion.");
                }
-               
-               
-               /// <summary>
-               /// convert a win32 error code into an appropriate exception.
-               /// </summary>
-               private void GenerateException (int errorCode)
-               {
-                       switch (errorCode) {
-                               case Win32ResultCode.FileNotFound:
-                               case Win32ResultCode.InvalidParameter:
-                                       throw new ArgumentException ();
-                               
-                               case Win32ResultCode.AccessDenied:
-                                       throw new SecurityException ();
 
-                               default:
-                                       // unidentified system exception
-                                       throw new SystemException ();
-                       }
-               }
-               
-#if (false)
-               /// <summary>
-               ///     dump trace messages if this code was compiled with tracing enabled.
-               /// </summary>
-               [Conditional("TRACE")]
-               private static void RegTrace (string message, params object[] args)
+               static string GetHiveName (RegistryHive hive)
                {
-                       message = "REG " + message;
-                       if (args.Length > 0)
-                               message = String.Format (message, args);
+                       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";
+                       }
 
-                       Trace.WriteLine (message);
-                       //Console.WriteLine (message);
-               }
-#endif         
-               private static void RegTrace (string message, params object[] args)
-               {
+                       throw new NotImplementedException (string.Format (
+                               "Registry hive '{0}' is not implemented.", hive.ToString ()));
                }
+
        }
 }
 
+#endif // NET_2_1
+