// 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
{
// FIXME this is hard coded on Mono, can it be determined dynamically?
readonly int NativeBytesPerCharacter = Marshal.SystemDefaultCharSize;
- internal enum RegistryType {
- String = 1,
- EnvironmentString = 2,
- Binary = 3,
- Dword = 4,
- StringArray = 7,
- }
-
- [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);
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,
int index, StringBuilder nameBuffer,
ref int nameLength, IntPtr reserved,
- ref RegistryType type, IntPtr data, IntPtr dataLength);
+ 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, RegistryType 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,
- string valueName, IntPtr reserved, RegistryType type,
+ 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, RegistryType type,
+ 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, RegistryType type,
+ string valueName, IntPtr reserved, RegistryValueKind type,
ref int data, int rawDataLength);
[DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegQueryValueEx")]
private static extern int RegQueryValueEx (IntPtr keyBase,
- string valueName, IntPtr reserved, ref RegistryType type,
+ 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 RegistryType type,
+ 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 RegistryType type,
+ string valueName, IntPtr reserved, ref RegistryValueKind type,
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.InternalHandle;
+ }
+
+ static bool IsHandleValid (RegistryKey key)
{
- return key.IsRoot ? new IntPtr ((int) key.Data)
- : (IntPtr) key.Data;
+ 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 knoledge of the
- /// value's type and size.
+ /// Acctually read a registry value. Requires knowledge of the
+ /// value's type and size.
/// </summary>
- public object GetValue (RegistryKey rkey, string name, bool returnDefaultValue, object defaultValue)
+ public object GetValue (RegistryKey rkey, string name, object defaultValue, RegistryValueOptions options)
{
- RegistryType type = 0;
+ 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) {
- if (returnDefaultValue) {
- return defaultValue;
- }
- return null;
+ if (result == Win32ResultCode.FileNotFound || result == Win32ResultCode.MarkedForDeletion) {
+ return defaultValue;
}
if (result != Win32ResultCode.MoreData && result != Win32ResultCode.Success ) {
GenerateException (result);
}
- if (type == RegistryType.String || type == RegistryType.EnvironmentString) {
+ if (type == RegistryValueKind.String) {
byte[] data;
result = GetBinaryValue (rkey, name, type, out data, size);
obj = RegistryKey.DecodeString (data);
- } else if (type == RegistryType.Dword) {
+ } 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 == RegistryType.Binary) {
+ } else if (type == RegistryValueKind.Binary) {
byte[] data;
result = GetBinaryValue (rkey, name, type, out data, size);
obj = data;
- } else if (type == RegistryType.StringArray) {
+ } else if (type == RegistryValueKind.MultiString) {
obj = null;
byte[] data;
result = GetBinaryValue (rkey, name, type, out data, size);
return obj;
}
+ //
+ // 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)
+ {
+ Type type = value.GetType ();
+ int result;
+ IntPtr handle = GetHandle (rkey);
+
+ 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 ();
if (type == typeof (int)) {
int rawValue = (int)value;
- result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryType.Dword, ref rawValue, Int32ByteSize);
+ 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, RegistryType.Binary, rawValue, rawValue.Length);
+ result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryValueKind.Binary, rawValue, rawValue.Length);
} else if (type == typeof (string[])) {
string[] vals = (string[]) value;
StringBuilder fullStringValue = new StringBuilder ();
byte[] rawValue = Encoding.Unicode.GetBytes (fullStringValue.ToString ());
- result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryType.StringArray, rawValue, rawValue.Length);
+ 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, RegistryType.String, rawValue,
+ 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)
{
/// <summary>
/// Get a binary value.
/// </summary>
- private int GetBinaryValue (RegistryKey rkey, string name, RegistryType type, out byte[] data, int size)
+ private int GetBinaryValue (RegistryKey rkey, string name, RegistryValueKind type, out byte[] data, int size)
{
byte[] internalData = new byte [size];
IntPtr handle = GetHandle (rkey);
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 ();
+
if (result == Win32ResultCode.Success)
continue;
public int ValueCount (RegistryKey rkey)
{
int index, result, bufferCapacity;
- RegistryType type;
+ RegistryValueKind type;
StringBuilder buffer = new StringBuilder (BufferMaxLength);
IntPtr handle = GetHandle (rkey);
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;
}
return index;
}
-
- public RegistryKey OpenSubKey (RegistryKey rkey, string keyName, bool writtable)
+
+ 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;
- if (writtable) access |= OpenRegKeyWrite;
+ if (writable) access |= OpenRegKeyWrite;
IntPtr handle = GetHandle (rkey);
IntPtr subKeyHandle;
int result = RegOpenKeyEx (handle, keyName, IntPtr.Zero, access, out subKeyHandle);
- if (result == Win32ResultCode.FileNotFound)
+ if (result == Win32ResultCode.FileNotFound || result == Win32ResultCode.MarkedForDeletion)
return null;
if (result != Win32ResultCode.Success)
GenerateException (result);
- return new RegistryKey (subKeyHandle, CombineName (rkey, keyName));
+ return new RegistryKey (subKeyHandle, CombineName (rkey, keyName), writable);
}
public void Flush (RegistryKey rkey)
{
+ if (!IsHandleValid (rkey))
+ return;
IntPtr handle = GetHandle (rkey);
RegFlushKey (handle);
}
public void Close (RegistryKey rkey)
{
+ if (!IsHandleValid (rkey))
+ return;
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 ();
if (result != Win32ResultCode.Success) {
GenerateException (result);
}
- RegistryKey subKey = new RegistryKey (subKeyHandle, CombineName (rkey, keyName));
+ return new RegistryKey (subKeyHandle, CombineName (rkey, keyName),
+ 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 ();
- return subKey;
+ 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);
int result = RegDeleteValue (handle, value);
-
+
+ if (result == Win32ResultCode.MarkedForDeletion)
+ return;
+
if (result == Win32ResultCode.FileNotFound){
if (shouldThrowWhenKeyMissing)
throw new ArgumentException ("value " + value);
public string [] GetSubKeyNames (RegistryKey rkey)
{
IntPtr handle = GetHandle (rkey);
- byte[] buffer = new byte [BufferMaxLength];
- int bufferCapacity = BufferMaxLength;
+ StringBuilder buffer = new StringBuilder (BufferMaxLength);
ArrayList keys = new ArrayList ();
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;
}
{
StringBuilder buffer = new StringBuilder (BufferMaxLength);
int bufferCapacity = buffer.Capacity;
- RegistryType type = 0;
+ RegistryValueKind type = 0;
int result = RegEnumValue (handle, index, buffer, ref bufferCapacity,
IntPtr.Zero, ref type, IntPtr.Zero, IntPtr.Zero);
if (result == Win32ResultCode.NoMoreEntries)
break;
-
+
+ if (result == Win32ResultCode.MarkedForDeletion)
+ throw RegistryKey.CreateMarkedForDeletionException ();
+
GenerateException (result);
}
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 string ToString (RegistryKey rkey)
{
- IntPtr handle = GetHandle (rkey);
-
- return String.Format ("{0} [0x{1:X}]", rkey.Name, handle.ToInt32 ());
+ return rkey.Name;
}
/// <summary>
}
}
+#endif // NET_2_1
+