Implement 4.0 RegistryKey.Handle property.
[mono.git] / mcs / class / corlib / Microsoft.Win32 / Win32RegistryApi.cs
index 22ad8406c0543de77cbde4b97df1b0105e1a10ed..472f4a73c5b9a4d076e0f205851f92d90d4b372c 100644 (file)
@@ -41,6 +41,7 @@ using System.IO;
 using System.Runtime.InteropServices;
 using System.Security;
 using System.Text;
+using Microsoft.Win32.SafeHandles;
 
 namespace Microsoft.Win32
 {
@@ -60,8 +61,13 @@ namespace Microsoft.Win32
                // FIXME this is hard coded on Mono, can it be determined dynamically? 
                readonly int NativeBytesPerCharacter = Marshal.SystemDefaultCharSize;
 
-               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegCreateKey")]
-               static extern int RegCreateKey (IntPtr keyBase, string keyName, out IntPtr keyHandle);
+               const int RegOptionsNonVolatile = 0x00000000;
+               const int RegOptionsVolatile = 0x00000001;
+
+               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegCreateKeyEx")]
+               static extern int RegCreateKeyEx (IntPtr keyBase, string keyName, int reserved, 
+                       IntPtr lpClass, int options, int access, IntPtr securityAttrs,
+                       out IntPtr keyHandle, out int disposition);
               
                [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegCloseKey")]
                static extern int RegCloseKey (IntPtr keyHandle);
@@ -129,16 +135,29 @@ namespace Microsoft.Win32
                                ref int data, ref int dataSize);
 
                // Returns our handle from the RegistryKey
-               static IntPtr GetHandle (RegistryKey key)
+               public IntPtr GetHandle (RegistryKey key)
                {
-                       return (IntPtr) key.Handle;
+                       return (IntPtr) key.InternalHandle;
                }
 
                static bool IsHandleValid (RegistryKey key)
                {
-                       return key.Handle != null;
+                       return key.InternalHandle != null;
                }
 
+               public RegistryValueKind GetValueKind (RegistryKey rkey, string name)
+               {
+                       RegistryValueKind type = 0;
+                       int size = 0;
+                       IntPtr handle = GetHandle (rkey);
+                       int result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, IntPtr.Zero, ref size);
+
+                       if (result == Win32ResultCode.FileNotFound || result == Win32ResultCode.MarkedForDeletion) 
+                               return RegistryValueKind.Unknown;
+
+                       return type;
+               }
+               
                /// <summary>
                /// Acctually read a registry value. Requires knowledge of the
                /// value's type and size.
@@ -409,11 +428,24 @@ namespace Microsoft.Win32
                        RegCloseKey (handle);
                }
 
+#if NET_4_0
+               public RegistryKey FromHandle (SafeRegistryHandle handle)
+               {
+                       // At this point we can't tell whether the key is writable
+                       // or not (nor the name), so we let the error check code handle it later, as
+                       // .Net seems to do.
+                       return new RegistryKey (handle.DangerousGetHandle (), String.Empty, true);
+               }
+#endif
+
                public RegistryKey CreateSubKey (RegistryKey rkey, string keyName)
                {
                        IntPtr handle = GetHandle (rkey);
                        IntPtr subKeyHandle;
-                       int result = RegCreateKey (handle , keyName, out subKeyHandle);
+                       int disposition;
+                       int result = RegCreateKeyEx (handle , keyName, 0, IntPtr.Zero,
+                               RegOptionsNonVolatile,
+                               OpenRegKeyRead | OpenRegKeyWrite, IntPtr.Zero, out subKeyHandle, out disposition);
 
                        if (result == Win32ResultCode.MarkedForDeletion)
                                throw RegistryKey.CreateMarkedForDeletionException ();
@@ -426,6 +458,27 @@ namespace Microsoft.Win32
                                true);
                }
 
+#if NET_4_0
+               public RegistryKey CreateSubKey (RegistryKey rkey, string keyName, RegistryOptions options)
+               {
+                       IntPtr handle = GetHandle (rkey);
+                       IntPtr subKeyHandle;
+                       int disposition;
+                       int result = RegCreateKeyEx (handle , keyName, 0, IntPtr.Zero,
+                               options == RegistryOptions.Volatile ? RegOptionsVolatile : RegOptionsNonVolatile,
+                               OpenRegKeyRead | OpenRegKeyWrite, IntPtr.Zero, out subKeyHandle, out disposition);
+
+                       if (result == Win32ResultCode.MarkedForDeletion)
+                               throw RegistryKey.CreateMarkedForDeletionException ();
+
+                       if (result != Win32ResultCode.Success)
+                               GenerateException (result);
+                       
+                       return new RegistryKey (subKeyHandle, CombineName (rkey, keyName),
+                               true);
+               }
+#endif
+
                public void DeleteKey (RegistryKey rkey, string keyName, bool shouldThrowWhenKeyMissing)
                {
                        IntPtr handle = GetHandle (rkey);
@@ -528,6 +581,8 @@ namespace Microsoft.Win32
                                        throw new SecurityException ();
                                case Win32ResultCode.NetworkPathNotFound:
                                        throw new IOException ("The network path was not found.");
+                               case Win32ResultCode.InvalidHandle:
+                                       throw new IOException ("Invalid handle.");
                                default:
                                        // unidentified system exception
                                        throw new SystemException ();