Use simple Convert when storing registry values
[mono.git] / mcs / class / corlib / Microsoft.Win32 / Win32RegistryApi.cs
index a39ead72a1f245ec086322dbad3406a4f8c96229..a3108ec2b992442d116088210016a90ed13f5cf6 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.Collections.Generic;
+using System.IO;
 using System.Runtime.InteropServices;
 using System.Security;
 using System.Text;
+using Microsoft.Win32.SafeHandles;
 
 namespace Microsoft.Win32
 {
@@ -53,16 +58,26 @@ namespace Microsoft.Win32
 
                // FIXME must be a way to determin this dynamically?
                const int Int32ByteSize = 4;
+               const int Int64ByteSize = 8;
 
                // 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);
 
+               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode)]
+               static extern int RegConnectRegistry (string machineName, IntPtr hKey,
+                               out IntPtr keyHandle);
+
                [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegFlushKey")]
                private static extern int RegFlushKey (IntPtr keyHandle);
 
@@ -78,7 +93,7 @@ namespace Microsoft.Win32
                private static extern int RegDeleteValue (IntPtr keyHandle, string valueName);
 
                [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegEnumKey")]
-               private static extern int RegEnumKey (IntPtr keyBase, int index, [Out] byte[] nameBuffer, int bufferLength);
+               private static extern int RegEnumKey (IntPtr keyBase, int index, StringBuilder nameBuffer, int bufferLength);
 
                [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegEnumValue")]
                private static extern int RegEnumValue (IntPtr keyBase, 
@@ -86,10 +101,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, 
@@ -106,6 +121,11 @@ namespace Microsoft.Win32
                                string valueName, IntPtr reserved, RegistryValueKind type,
                                ref int data, int rawDataLength);
 
+               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
+               private static extern int RegSetValueEx (IntPtr keyBase, 
+                               string valueName, IntPtr reserved, RegistryValueKind type,
+                               ref long data, int rawDataLength);
+
                [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
                private static extern int RegQueryValueEx (IntPtr keyBase,
                                string valueName, IntPtr reserved, ref RegistryValueKind type,
@@ -121,18 +141,35 @@ namespace Microsoft.Win32
                                string valueName, IntPtr reserved, ref RegistryValueKind type,
                                ref int data, ref int dataSize);
 
+               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
+               private static extern int RegQueryValueEx (IntPtr keyBase,
+                               string valueName, IntPtr reserved, ref RegistryValueKind type,
+                               ref long data, ref int dataSize);
+
                // Returns our handle from the RegistryKey
-               static IntPtr GetHandle (RegistryKey key)
+               public IntPtr GetHandle (RegistryKey key)
                {
-                       return key.IsRoot ? new IntPtr ((int) key.Data)
-                               : (IntPtr) key.Data;
+                       return (IntPtr) key.InternalHandle;
                }
 
                static bool IsHandleValid (RegistryKey key)
                {
-                       return key.Data != 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.
@@ -167,6 +204,10 @@ namespace Microsoft.Win32
                                int data = 0;
                                result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, ref data, ref size);
                                obj = data;
+                       } else if (type == RegistryValueKind.QWord) {
+                               long data = 0;
+                               result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, ref data, ref size);
+                               obj = data;
                        } else if (type == RegistryValueKind.Binary) {
                                byte[] data;
                                result = GetBinaryValue (rkey, name, type, out data, size);
@@ -193,7 +234,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
@@ -204,7 +244,10 @@ namespace Microsoft.Win32
                        int result;
                        IntPtr handle = GetHandle (rkey);
 
-                       if (valueKind == RegistryValueKind.DWord && type == typeof (int)) {
+                       if (valueKind == RegistryValueKind.QWord && type == typeof (long)) {
+                               long rawValue = (long)value;
+                               result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.QWord, ref rawValue, Int64ByteSize); 
+                       } else if (valueKind == RegistryValueKind.DWord && type == typeof (int)) {
                                int rawValue = (int)value;
                                result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.DWord, ref rawValue, Int32ByteSize); 
                        } else if (valueKind == RegistryValueKind.Binary && type == typeof (byte[])) {
@@ -241,7 +284,6 @@ namespace Microsoft.Win32
                                GenerateException (result);
                        }
                }
-#endif
        
                public void SetValue (RegistryKey rkey, string name, object value)
                {
@@ -306,12 +348,13 @@ namespace Microsoft.Win32
                
                public int SubKeyCount (RegistryKey rkey)
                {
-                       int index, result;
-                       byte[] stringBuffer = new byte [BufferMaxLength];
+                       int index;
+                       StringBuilder stringBuffer = new StringBuilder (BufferMaxLength);
                        IntPtr handle = GetHandle (rkey);
                        
                        for (index = 0; true; index ++) {
-                               result = RegEnumKey (handle, index, stringBuffer, BufferMaxLength);
+                               int result = RegEnumKey (handle, index, stringBuffer,
+                                       stringBuffer.Capacity);
 
                                if (result == Win32ResultCode.MarkedForDeletion)
                                        throw RegistryKey.CreateMarkedForDeletionException ();
@@ -357,7 +400,19 @@ namespace Microsoft.Win32
                        }
                        return index;
                }
-               
+
+               public RegistryKey OpenRemoteBaseKey (RegistryHive hKey, string machineName)
+               {
+                       IntPtr handle = new IntPtr ((int) hKey);
+
+                       IntPtr keyHandle;
+                       int result = RegConnectRegistry (machineName, handle, out keyHandle);
+                       if (result != Win32ResultCode.Success)
+                               GenerateException (result);
+
+                       return new RegistryKey (hKey, keyHandle, true);
+               }
+
                public RegistryKey OpenSubKey (RegistryKey rkey, string keyName, bool writable)
                {
                        int access = OpenRegKeyRead;
@@ -388,15 +443,36 @@ namespace Microsoft.Win32
                {
                        if (!IsHandleValid (rkey))
                                return;
+#if NET_4_0
+                       SafeRegistryHandle safe_handle = rkey.Handle;
+                       if (safe_handle != null) {
+                               // closes the unmanaged pointer for us.
+                               safe_handle.Close ();
+                               return;
+                       }
+#endif
                        IntPtr handle = GetHandle (rkey);
                        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 ();
@@ -409,6 +485,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);
@@ -445,15 +542,15 @@ namespace Microsoft.Win32
                public string [] GetSubKeyNames (RegistryKey rkey)
                {
                        IntPtr handle = GetHandle (rkey);
-                       byte[] buffer = new byte [BufferMaxLength];
-                       int bufferCapacity = BufferMaxLength;
-                       ArrayList keys = new ArrayList ();
+                       StringBuilder buffer = new StringBuilder (BufferMaxLength);
+                       var keys = new List<string> ();
                                
                        for (int index = 0; true; index ++) {
-                               int result = RegEnumKey (handle, index, buffer, bufferCapacity);
+                               int result = RegEnumKey (handle, index, buffer, buffer.Capacity);
 
                                if (result == Win32ResultCode.Success) {
-                                       keys.Add (RegistryKey.DecodeString (buffer));
+                                       keys.Add (buffer.ToString ());
+                                       buffer.Length = 0;
                                        continue;
                                }
 
@@ -463,14 +560,14 @@ namespace Microsoft.Win32
                                // should not be here!
                                GenerateException (result);
                        }
-                       return (string []) keys.ToArray (typeof(String));
+                       return keys.ToArray ();
                }
 
 
                public string [] GetValueNames (RegistryKey rkey)
                {
                        IntPtr handle = GetHandle (rkey);
-                       ArrayList values = new ArrayList ();
+                       var values = new List<string> ();
                        
                        for (int index = 0; true; index ++)
                        {
@@ -495,7 +592,7 @@ namespace Microsoft.Win32
                                GenerateException (result);
                        }
 
-                       return (string []) values.ToArray (typeof(String));
+                       return values.ToArray ();
                }
 
                /// <summary>
@@ -507,10 +604,12 @@ namespace Microsoft.Win32
                                case Win32ResultCode.FileNotFound:
                                case Win32ResultCode.InvalidParameter:
                                        throw new ArgumentException ();
-                               
                                case Win32ResultCode.AccessDenied:
                                        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 ();
@@ -519,9 +618,7 @@ namespace Microsoft.Win32
 
                public string ToString (RegistryKey rkey)
                {
-                       IntPtr handle = GetHandle (rkey);
-                       
-                       return String.Format ("{0} [0x{1:X}]", rkey.Name, handle.ToInt32 ());
+                       return rkey.Name;
                }
 
                /// <summary>
@@ -535,3 +632,5 @@ namespace Microsoft.Win32
        }
 }
 
+#endif // NET_2_1
+