Implement 4.0 RegistryKey.Handle property.
[mono.git] / mcs / class / corlib / Microsoft.Win32 / Win32RegistryApi.cs
index c32ac30c801a8b9b5cc6827fe884274bc0d85a91..472f4a73c5b9a4d076e0f205851f92d90d4b372c 100644 (file)
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
+#if !NET_2_1
+
 using System;
 using System.Collections;
 using System.IO;
 using System.Runtime.InteropServices;
 using System.Security;
 using System.Text;
+using Microsoft.Win32.SafeHandles;
 
 namespace Microsoft.Win32
 {
@@ -58,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);
@@ -91,10 +99,10 @@ namespace Microsoft.Win32
                                ref int nameLength, IntPtr reserved, 
                                ref RegistryValueKind type, IntPtr data, IntPtr dataLength);
 
-               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
-               private static extern int RegSetValueEx (IntPtr keyBase, 
-                               string valueName, IntPtr reserved, RegistryValueKind type,
-                               StringBuilder data, int rawDataLength);
+//             [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
+//             private static extern int RegSetValueEx (IntPtr keyBase, 
+//                             string valueName, IntPtr reserved, RegistryValueKind type,
+//                             StringBuilder data, int rawDataLength);
 
                [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
                private static extern int RegSetValueEx (IntPtr keyBase, 
@@ -127,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.
@@ -197,7 +218,6 @@ namespace Microsoft.Win32
                        return obj;
                }
 
-#if NET_2_0
                //
                // This version has to do extra checking, make sure that the requested
                // valueKind matches the type of the value being stored
@@ -245,7 +265,6 @@ namespace Microsoft.Win32
                                GenerateException (result);
                        }
                }
-#endif
        
                public void SetValue (RegistryKey rkey, string name, object value)
                {
@@ -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 ();
@@ -536,13 +591,7 @@ namespace Microsoft.Win32
 
                public string ToString (RegistryKey rkey)
                {
-#if NET_2_0
                        return rkey.Name;
-#else                  
-                       IntPtr handle = GetHandle (rkey);
-                       
-                       return String.Format ("{0} [0x{1:X}]", rkey.Name, handle.ToInt32 ());
-#endif
                }
 
                /// <summary>
@@ -556,3 +605,5 @@ namespace Microsoft.Win32
        }
 }
 
+#endif // NET_2_1
+