// Authos:
// Erik LeBel (eriklebel@yahoo.ca)
// Jackson Harper (jackson@ximian.com)
+// Miguel de Icaza (miguel@gnome.org)
//
// Copyright (C) Erik LeBel 2004
-// (C) 2004 Novell, Inc (http://www.novell.com)
+// (C) 2004, 2005 Novell, Inc (http://www.novell.com)
//
+//
+// Copyright (C) 2004, 2005 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.
+//
+
+#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
{
internal class Win32RegistryApi : IRegistryApi
{
// bit masks for registry key open access permissions
- public int OpenRegKeyRead {
- get { return 0x00020019; }
- }
+ const int OpenRegKeyRead = 0x00020019;
+ const int OpenRegKeyWrite = 0x00020006;
- public int OpenRegKeyWrite {
- get { return 0x00020006; }
- }
-
- // type values for registry value data
- public int RegStringType {
- get { return 1; }
- }
+ // FIXME must be a way to determin this dynamically?
+ const int Int32ByteSize = 4;
+ const int Int64ByteSize = 8;
- public int RegEnvironmentString {
- get { return 2; }
- }
+ // FIXME this is hard coded on Mono, can it be determined dynamically?
+ readonly int NativeBytesPerCharacter = Marshal.SystemDefaultCharSize;
- public int RegBinaryType {
- get { return 3; }
- }
+ const int RegOptionsNonVolatile = 0x00000000;
+ const int RegOptionsVolatile = 0x00000001;
- public int RegDwordType {
- get { return 4; }
- }
+ [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);
- public int RegStringArrayType {
- get { return 7; }
- }
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode)]
+ static extern int RegConnectRegistry (string machineName, IntPtr hKey,
+ out IntPtr keyHandle);
- /// <summary>
- /// Create a registry key.
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegCreateKey")]
- private static extern int RegCreateKey_Internal (IntPtr keyBase,
- string keyName, out IntPtr keyHandle);
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegFlushKey")]
+ private static extern int RegFlushKey (IntPtr keyHandle);
- public int RegCreateKey (IntPtr keybase, string keyname, out IntPtr handle)
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegOpenKeyEx")]
+ private static extern int RegOpenKeyEx (IntPtr keyBase,
+ string keyName, IntPtr reserved, int access,
+ out IntPtr keyHandle);
+
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegDeleteKey")]
+ private static extern int RegDeleteKey (IntPtr keyHandle, string valueName);
+
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegDeleteValue")]
+ 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, StringBuilder nameBuffer, int bufferLength);
+
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegEnumValue")]
+ private static extern int RegEnumValue (IntPtr keyBase,
+ int index, StringBuilder nameBuffer,
+ 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,
+ string data, int rawDataLength);
+
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
+ private static extern int RegSetValueEx (IntPtr keyBase,
+ string valueName, IntPtr reserved, RegistryValueKind type,
+ byte[] rawData, int rawDataLength);
+
+ [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
+ private static extern int RegSetValueEx (IntPtr keyBase,
+ 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,
+ IntPtr zero, 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,
+ [Out] byte[] 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 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
+ public IntPtr GetHandle (RegistryKey key)
{
- return RegCreateKey_Internal (keybase, keyname, out handle);
+ return (IntPtr) key.InternalHandle;
}
-
- /// <summary>
- /// Close a registry key.
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegCloseKey")]
- private static extern int RegCloseKey_Internal (IntPtr keyHandle);
- public int RegCloseKey (IntPtr handle)
+ static bool IsHandleValid (RegistryKey key)
{
- return RegCloseKey_Internal (handle);
+ return key.InternalHandle != null;
}
- /// <summary>
- /// Flush a registry key's current state to disk.
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegFlushKey")]
- private static extern int RegFlushKey_Internal (IntPtr keyHandle);
-
- public int RegFlushKey (IntPtr handle)
+ public RegistryValueKind GetValueKind (RegistryKey rkey, string name)
{
- return RegFlushKey_Internal (handle);
- }
+ 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>
- /// Open a registry key.
- /// 'unknown' must be zero.
+ /// Acctually read a registry value. Requires knowledge of the
+ /// value's type and size.
/// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegOpenKeyEx")]
- private static extern int RegOpenKeyEx_Internal (IntPtr keyBase,
- string keyName, IntPtr reserved, int access,
- out IntPtr keyHandle);
+ public object GetValue (RegistryKey rkey, string name, object defaultValue, RegistryValueOptions options)
+ {
+ RegistryValueKind type = 0;
+ int size = 0;
+ object obj = null;
+ 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 defaultValue;
+ }
+
+ if (result != Win32ResultCode.MoreData && result != Win32ResultCode.Success ) {
+ GenerateException (result);
+ }
+
+ if (type == RegistryValueKind.String) {
+ byte[] data;
+ result = GetBinaryValue (rkey, name, type, out data, size);
+ obj = RegistryKey.DecodeString (data);
+ } else if (type == RegistryValueKind.ExpandString) {
+ byte [] data;
+ result = GetBinaryValue (rkey, name, type, out data, size);
+ obj = RegistryKey.DecodeString (data);
+ if ((options & RegistryValueOptions.DoNotExpandEnvironmentNames) == 0)
+ obj = Environment.ExpandEnvironmentVariables ((string) obj);
+ } else if (type == RegistryValueKind.DWord) {
+ 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);
+ obj = data;
+ } else if (type == RegistryValueKind.MultiString) {
+ obj = null;
+ byte[] data;
+ result = GetBinaryValue (rkey, name, type, out data, size);
+
+ if (result == Win32ResultCode.Success)
+ obj = RegistryKey.DecodeString (data).Split ('\0');
+ } else {
+ // should never get here
+ throw new SystemException ();
+ }
+
+ // check result codes again:
+ if (result != Win32ResultCode.Success)
+ {
+ GenerateException (result);
+ }
+
+
+ return obj;
+ }
- public int RegOpenKeyEx (IntPtr keybase, string keyname, IntPtr reserved,
- int access, out IntPtr handle)
+ //
+ // This version has to do extra checking, make sure that the requested
+ // valueKind matches the type of the value being stored
+ //
+ public void SetValue (RegistryKey rkey, string name, object value, RegistryValueKind valueKind)
{
- return RegOpenKeyEx_Internal (keybase, keyname, reserved, access, out handle);
+ Type type = value.GetType ();
+ int result;
+ IntPtr handle = GetHandle (rkey);
+
+ 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[])) {
+ byte[] rawValue = (byte[]) value;
+ result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.Binary, rawValue, rawValue.Length);
+ } else if (valueKind == RegistryValueKind.MultiString && type == typeof (string[])) {
+ string[] vals = (string[]) value;
+ StringBuilder fullStringValue = new StringBuilder ();
+ foreach (string v in vals)
+ {
+ fullStringValue.Append (v);
+ fullStringValue.Append ('\0');
+ }
+ fullStringValue.Append ('\0');
+
+ byte[] rawValue = Encoding.Unicode.GetBytes (fullStringValue.ToString ());
+
+ result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.MultiString, rawValue, rawValue.Length);
+ } else if ((valueKind == RegistryValueKind.String || valueKind == RegistryValueKind.ExpandString) &&
+ type == typeof (string)){
+ string rawValue = String.Format ("{0}{1}", value, '\0');
+ result = RegSetValueEx (handle, name, IntPtr.Zero, valueKind, rawValue,
+ rawValue.Length * NativeBytesPerCharacter);
+
+ } else if (type.IsArray) {
+ throw new ArgumentException ("Only string and byte arrays can written as registry values");
+ } else {
+ throw new ArgumentException ("Type does not match the valueKind");
+ }
+
+ // handle the result codes
+ if (result != Win32ResultCode.Success)
+ {
+ GenerateException (result);
+ }
+ }
+
+ public void SetValue (RegistryKey rkey, string name, object value)
+ {
+ Type type = value.GetType ();
+ int result;
+ IntPtr handle = GetHandle (rkey);
+
+ if (type == typeof (int)) {
+ int rawValue = (int)value;
+ result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.DWord, ref rawValue, Int32ByteSize);
+ } else if (type == typeof (byte[])) {
+ byte[] rawValue = (byte[]) value;
+ result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.Binary, 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 ('\0');
+ }
+ fullStringValue.Append ('\0');
+
+ byte[] rawValue = Encoding.Unicode.GetBytes (fullStringValue.ToString ());
+
+ result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.MultiString, 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, '\0');
+ result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.String, rawValue,
+ rawValue.Length * NativeBytesPerCharacter);
+ }
+
+ if (result == Win32ResultCode.MarkedForDeletion)
+ throw RegistryKey.CreateMarkedForDeletionException ();
+
+ // handle the result codes
+ if (result != Win32ResultCode.Success)
+ {
+ GenerateException (result);
+ }
}
/// <summary>
- /// Delete a registry key.
+ /// Get a binary value.
/// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegDeleteKey")]
- private static extern int RegDeleteKey_Internal (IntPtr keyHandle,
- string valueName);
-
- public int RegDeleteKey (IntPtr handle, string valuename)
+ private int GetBinaryValue (RegistryKey rkey, string name, RegistryValueKind type, out byte[] data, int size)
{
- return RegDeleteKey_Internal (handle, valuename);
+ byte[] internalData = new byte [size];
+ IntPtr handle = GetHandle (rkey);
+ int result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, internalData, ref size);
+ data = internalData;
+ return result;
}
- /// <summary>
- /// Delete a registry value.
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegDeleteValue")]
- private static extern int RegDeleteValue_Internal (IntPtr keyHandle,
- string valueName);
+
+ // 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;
+
+ public int SubKeyCount (RegistryKey rkey)
+ {
+ int index;
+ StringBuilder stringBuffer = new StringBuilder (BufferMaxLength);
+ IntPtr handle = GetHandle (rkey);
+
+ for (index = 0; true; index ++) {
+ int result = RegEnumKey (handle, index, stringBuffer,
+ stringBuffer.Capacity);
+
+ if (result == Win32ResultCode.MarkedForDeletion)
+ throw RegistryKey.CreateMarkedForDeletionException ();
+
+ if (result == Win32ResultCode.Success)
+ continue;
+
+ if (result == Win32ResultCode.NoMoreEntries)
+ break;
+
+ // something is wrong!!
+ GenerateException (result);
+ }
+ return index;
+ }
- public int RegDeleteValue (IntPtr handle, string valuename)
+ public int ValueCount (RegistryKey rkey)
{
- return RegDeleteValue_Internal (handle, valuename);
+ int index, result, bufferCapacity;
+ RegistryValueKind type;
+ StringBuilder buffer = new StringBuilder (BufferMaxLength);
+
+ IntPtr handle = GetHandle (rkey);
+ for (index = 0; true; index ++) {
+ type = 0;
+ bufferCapacity = buffer.Capacity;
+ result = RegEnumValue (handle, index,
+ buffer, ref bufferCapacity,
+ IntPtr.Zero, ref type,
+ IntPtr.Zero, IntPtr.Zero);
+
+ if (result == Win32ResultCode.MarkedForDeletion)
+ throw RegistryKey.CreateMarkedForDeletionException ();
+
+ if (result == Win32ResultCode.Success || result == Win32ResultCode.MoreData)
+ continue;
+
+ if (result == Win32ResultCode.NoMoreEntries)
+ break;
+
+ // something is wrong
+ GenerateException (result);
+ }
+ return index;
}
- /// <summary>
- /// Fetch registry key subkeys itteratively.
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegEnumKey")]
- private static extern int RegEnumKey_Internal (IntPtr keyBase, int index,
- [Out] byte[] nameBuffer, int bufferLength);
+ 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 int RegEnumKey (IntPtr keybase, int index,
- [Out] byte [] namebuffer, int buffer_length)
+ public RegistryKey OpenSubKey (RegistryKey rkey, string keyName, bool writable)
{
- return RegEnumKey_Internal (keybase, index, namebuffer, buffer_length);
+ int access = OpenRegKeyRead;
+ if (writable) access |= OpenRegKeyWrite;
+ IntPtr handle = GetHandle (rkey);
+
+ IntPtr subKeyHandle;
+ int result = RegOpenKeyEx (handle, keyName, IntPtr.Zero, access, out subKeyHandle);
+
+ if (result == Win32ResultCode.FileNotFound || result == Win32ResultCode.MarkedForDeletion)
+ return null;
+
+ if (result != Win32ResultCode.Success)
+ GenerateException (result);
+
+ return new RegistryKey (subKeyHandle, CombineName (rkey, keyName), writable);
}
- /// <summary>
- /// Fetch registry key value names itteratively.
- ///
- /// Arguments 'reserved', 'data', 'dataLength'
- /// should be set to IntPtr.Zero.
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegEnumValue")]
- private static extern int RegEnumValue_Internal (IntPtr keyBase,
- int index, StringBuilder nameBuffer,
- ref int nameLength, IntPtr reserved,
- ref int type, IntPtr data, IntPtr dataLength);
+ public void Flush (RegistryKey rkey)
+ {
+ if (!IsHandleValid (rkey))
+ return;
+ IntPtr handle = GetHandle (rkey);
+ RegFlushKey (handle);
+ }
- public int RegEnumValue (IntPtr keybase, int index, StringBuilder namebuffer,
- ref int namelength, IntPtr reserved, ref int type, IntPtr data,
- IntPtr datalength)
+ public void Close (RegistryKey rkey)
{
- return RegEnumValue_Internal (keybase, index, namebuffer, ref namelength,
- reserved, ref type, data, datalength);
+ 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);
}
- /// <summary>
- /// Set a registry value with string builder data.
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
- private static extern int RegSetValueEx_Internal (IntPtr keyBase,
- string valueName, IntPtr reserved, int type,
- StringBuilder data, int rawDataLength);
+#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 int RegSetValueEx (IntPtr keybase, string valuename, IntPtr reserved,
- int type, StringBuilder data, int datalength)
+ public RegistryKey CreateSubKey (RegistryKey rkey, string keyName)
{
- return RegSetValueEx_Internal (keybase, valuename, reserved,
- type, data, datalength);
+ IntPtr handle = GetHandle (rkey);
+ IntPtr 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 ();
+
+ if (result != Win32ResultCode.Success) {
+ GenerateException (result);
+ }
+
+ return new RegistryKey (subKeyHandle, CombineName (rkey, keyName),
+ true);
}
- /// <summary>
- /// Set a registry value with string data.
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
- private static extern int RegSetValueEx_Internal (IntPtr keyBase,
- string valueName, IntPtr reserved, int type,
- string data, int rawDataLength);
+#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 int RegSetValueEx (IntPtr keybase, string valuename, IntPtr reserved,
- int type, string data, int datalength)
+ public void DeleteKey (RegistryKey rkey, string keyName, bool shouldThrowWhenKeyMissing)
{
- return RegSetValueEx_Internal (keybase, valuename, reserved,
- type, data, datalength);
+ IntPtr handle = GetHandle (rkey);
+ int result = RegDeleteKey (handle, keyName);
+
+ if (result == Win32ResultCode.FileNotFound) {
+ if (shouldThrowWhenKeyMissing)
+ throw new ArgumentException ("key " + keyName);
+ return;
+ }
+
+ if (result != Win32ResultCode.Success)
+ GenerateException (result);
}
-
- /// <summary>
- /// Set a registry value with binary data (a byte array).
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
- private static extern int RegSetValueEx_Internal (IntPtr keyBase,
- string valueName, IntPtr reserved, int type,
- byte[] rawData, int rawDataLength);
- public int RegSetValueEx (IntPtr keybase, string valuename, IntPtr reserved,
- int type, byte [] data, int datalength)
+ public void DeleteValue (RegistryKey rkey, string value, bool shouldThrowWhenKeyMissing)
{
- return RegSetValueEx_Internal (keybase, valuename, reserved,
- type, data, datalength);
+ IntPtr handle = GetHandle (rkey);
+ int result = RegDeleteValue (handle, value);
+
+ if (result == Win32ResultCode.MarkedForDeletion)
+ return;
+
+ if (result == Win32ResultCode.FileNotFound){
+ if (shouldThrowWhenKeyMissing)
+ throw new ArgumentException ("value " + value);
+ return;
+ }
+
+ if (result != Win32ResultCode.Success)
+ GenerateException (result);
}
-
- /// <summary>
- /// Set a registry value to a DWORD value.
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegSetValueEx")]
- private static extern int RegSetValueEx_Internal (IntPtr keyBase,
- string valueName, IntPtr reserved, int type,
- ref int data, int rawDataLength);
- public int RegSetValueEx (IntPtr keybase, string valuename, IntPtr reserved,
- int type, ref int data, int datalength)
+ public string [] GetSubKeyNames (RegistryKey rkey)
{
- return RegSetValueEx_Internal (keybase, valuename, reserved, type,
- ref data, datalength);
+ IntPtr handle = GetHandle (rkey);
+ StringBuilder buffer = new StringBuilder (BufferMaxLength);
+ var keys = new List<string> ();
+
+ for (int index = 0; true; index ++) {
+ int result = RegEnumKey (handle, index, buffer, buffer.Capacity);
+
+ if (result == Win32ResultCode.Success) {
+ keys.Add (buffer.ToString ());
+ buffer.Length = 0;
+ continue;
+ }
+
+ if (result == Win32ResultCode.NoMoreEntries)
+ break;
+
+ // should not be here!
+ GenerateException (result);
+ }
+ return keys.ToArray ();
}
- /// <summary>
- /// Get a registry value's info. No data.
- /// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
- private static extern int RegQueryValueEx_Internal (IntPtr keyBase,
- string valueName, IntPtr reserved, ref int type,
- IntPtr zero, ref int dataSize);
- public int RegQueryValueEx (IntPtr keybase, string valuename, IntPtr reserved,
- ref int type, IntPtr zero, ref int datasize)
+ public string [] GetValueNames (RegistryKey rkey)
{
- return RegQueryValueEx_Internal (keybase, valuename, reserved,
- ref type, zero, ref datasize);
+ IntPtr handle = GetHandle (rkey);
+ var values = new List<string> ();
+
+ for (int index = 0; true; index ++)
+ {
+ StringBuilder buffer = new StringBuilder (BufferMaxLength);
+ int bufferCapacity = buffer.Capacity;
+ RegistryValueKind type = 0;
+
+ int result = RegEnumValue (handle, index, buffer, ref bufferCapacity,
+ IntPtr.Zero, ref type, IntPtr.Zero, IntPtr.Zero);
+
+ if (result == Win32ResultCode.Success || result == Win32ResultCode.MoreData) {
+ values.Add (buffer.ToString ());
+ continue;
+ }
+
+ if (result == Win32ResultCode.NoMoreEntries)
+ break;
+
+ if (result == Win32ResultCode.MarkedForDeletion)
+ throw RegistryKey.CreateMarkedForDeletionException ();
+
+ GenerateException (result);
+ }
+
+ return values.ToArray ();
}
/// <summary>
- /// Get a registry value. Binary data.
+ /// convert a win32 error code into an appropriate exception.
/// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
- private static extern int RegQueryValueEx_Internal (IntPtr keyBase,
- string valueName, IntPtr reserved, ref int type,
- [Out] byte[] data, ref int dataSize);
+ private void GenerateException (int errorCode)
+ {
+ switch (errorCode) {
+ 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 ();
+ }
+ }
- public int RegQueryValueEx (IntPtr keybase, string valuename, IntPtr reserved,
- ref int type, [Out] byte [] data, ref int datasize)
+ public string ToString (RegistryKey rkey)
{
- return RegQueryValueEx_Internal (keybase, valuename, reserved,
- ref type, data, ref datasize);
+ return rkey.Name;
}
/// <summary>
- /// Get a registry value. DWORD data.
+ /// utility: Combine the sub key name to the current name to produce a
+ /// fully qualified sub key name.
/// </summary>
- [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
- private static extern int RegQueryValueEx_Internal (IntPtr keyBase,
- string valueName, IntPtr reserved, ref int type,
- ref int data, ref int dataSize);
-
- public int RegQueryValueEx (IntPtr keybase, string valuename, IntPtr reserved,
- ref int type, ref int data, ref int datasize)
+ internal static string CombineName (RegistryKey rkey, string localName)
{
- return RegQueryValueEx_Internal (keybase, valuename, reserved,
- ref type, ref data, ref datasize);
+ return String.Concat (rkey.Name, "\\", localName);
}
}
}
+#endif // NET_2_1
+