Removed debugging CWL that shows during normal execution.
[mono.git] / mcs / class / corlib / Microsoft.Win32 / Win32RegistryApi.cs
index a3242e28a92bcf05b1a1b761db8276dcb8e07291..03629c99c632573e6617120f9f070115eb943ad2 100644 (file)
@@ -4,13 +4,39 @@
 // 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.
+//
+
 using System;
+using System.Collections;
 using System.Runtime.InteropServices;
+using System.Security;
 using System.Text;
 
 namespace Microsoft.Win32
@@ -22,244 +48,411 @@ 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; 
+
+               // FIXME must be a way to determin this dynamically?
+               const int Int32ByteSize = 4;
+
+               // FIXME this is hard coded on Mono, can it be determined dynamically? 
+               readonly int NativeBytesPerCharacter = Marshal.SystemDefaultCharSize;
 
-               public int OpenRegKeyWrite {
-                       get { return 0x00020006; }
+               internal enum RegistryType {
+                       String = 1,
+                       EnvironmentString = 2,
+                       Binary = 3,
+                       Dword = 4,
+                       StringArray = 7,
                }
                
-               // type values for registry value data
-               public int RegStringType {
-                       get { return 1; }
-               }
+               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegCreateKey")]
+               static extern int RegCreateKey (IntPtr keyBase, string keyName, out IntPtr keyHandle);
+              
+               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegCloseKey")]
+               static extern int RegCloseKey (IntPtr keyHandle);
 
-               public int RegEnvironmentString {
-                       get { return 2; }
-               }
+               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegFlushKey")]
+               private static extern int RegFlushKey (IntPtr keyHandle);
 
-               public int RegBinaryType {
-                       get { return 3; }
-               }
+               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegOpenKeyEx")]
+               private static extern int RegOpenKeyEx (IntPtr keyBase,
+                               string keyName, IntPtr reserved, int access,
+                               out IntPtr keyHandle);
 
-               public int RegDwordType {
-                       get { return 4; }
-               }
+               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="RegDeleteKey")]
+               private static extern int RegDeleteKey (IntPtr keyHandle, string valueName);
 
-               public int RegStringArrayType {
-                       get { return 7; }
-               }
+               [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, [Out] byte[] 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);
+
+               [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, RegistryType 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,
+                               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,
+                               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,
+                               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,
+                               [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,
+                               ref int data, ref int dataSize);
 
                /// <summary>
-               ///     Create a registry key.
+               ///     Acctually read a registry value. Requires knoledge of the
+               ///     value's type and size.
                /// </summary>
-               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode)]
-               private static extern int RegCreateKey_Internal (IntPtr keyBase, 
-                               string keyName, out IntPtr keyHandle);
-
-               public int RegCreateKey (IntPtr keybase, string keyname, out IntPtr handle)
+               public object GetValue (RegistryKey rkey, string name, bool returnDefaultValue, object defaultValue)
                {
-                       return RegCreateKey_Internal (keybase, keyname, out handle);
+                       RegistryType type = 0;
+                       int size = 0;
+                       object obj = null;
+                       IntPtr handle = (IntPtr)rkey.Data;
+                       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.MoreData && result != Win32ResultCode.Success ) {
+                               GenerateException (result);
+                       }
+                       
+                       if (type == RegistryType.String || type == RegistryType.EnvironmentString) {
+                               byte[] data;
+                               result = GetBinaryValue (rkey, name, type, out data, size);
+                               obj = RegistryKey.DecodeString (data);
+                       } else if (type == RegistryType.Dword) {
+                               int data = 0;
+                               result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, ref data, ref size);
+                               obj = data;
+                       } else if (type == RegistryType.Binary) {
+                               byte[] data;
+                               result = GetBinaryValue (rkey, name, type, out data, size);
+                               obj = data;
+                       } else if (type == RegistryType.StringArray) {
+                               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;
                }
-              
-               /// <summary>
-               ///     Close a registry key.
-               /// </summary>
-               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode)]
-               private static extern int RegCloseKey_Internal (IntPtr keyHandle);
 
-               public int RegCloseKey (IntPtr handle)
+               public void SetValue (RegistryKey rkey, string name, object value)
                {
-                       return RegCloseKey_Internal (handle);
+                       Type type = value.GetType ();
+                       int result;
+                       IntPtr handle = (IntPtr)rkey.Data;
+
+                       if (type == typeof (int)) {
+                               int rawValue = (int)value;
+                               result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryType.Dword, ref rawValue, Int32ByteSize); 
+                       } else if (type == typeof (byte[])) {
+                               byte[] rawValue = (byte[]) value;
+                               result = RegSetValueEx (handle, name, IntPtr.Zero, RegistryType.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, RegistryType.StringArray, 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,
+                                                       rawValue.Length * NativeBytesPerCharacter);
+                       }
+
+                       // handle the result codes
+                       if (result != Win32ResultCode.Success)
+                       {
+                               GenerateException (result);
+                       }
                }
 
                /// <summary>
-               ///     Flush a registry key's current state to disk.
+               ///     Get a binary value.
                /// </summary>
-               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode)]
-               private static extern int RegFlushKey_Internal (IntPtr keyHandle);
-
-               public int RegFlushKey (IntPtr handle)
+               private int GetBinaryValue (RegistryKey rkey, string name, RegistryType type, out byte[] data, int size)
                {
-                       return RegFlushKey_Internal (handle);
+                       byte[] internalData = new byte [size];
+                       IntPtr handle = (IntPtr)rkey.Data;
+                       int result = RegQueryValueEx (handle, name, IntPtr.Zero, ref type, internalData, ref size);
+                       data = internalData;
+                       return result;
                }
 
-               /// <summary>
-               ///     Open a registry key.
-               ///     'unknown' must be zero.
-               /// </summary>
-               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode)]
-               private static extern int RegOpenKeyEx_Internal (IntPtr keyBase,
-                               string keyName, IntPtr reserved, int access,
-                               out IntPtr keyHandle);
-
-               public int RegOpenKeyEx (IntPtr keybase, string keyname, IntPtr reserved,
-                               int access, out IntPtr handle)
+               
+               // 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)
                {
-                       return RegOpenKeyEx_Internal (keybase, keyname, reserved, access, out handle);
+                       int index, result;
+                       byte[] stringBuffer = new byte [BufferMaxLength];
+                       IntPtr handle = (IntPtr)rkey.Data;
+                       
+                       for (index = 0; true; index ++) {
+                               result = RegEnumKey (handle, index, stringBuffer, BufferMaxLength);
+                               
+                               if (result == Win32ResultCode.Success)
+                                       continue;
+                               
+                               if (result == Win32ResultCode.NoMoreEntries)
+                                       break;
+                               
+                               // something is wrong!!
+                               GenerateException (result);
+                       }
+                       return index;
                }
 
-               /// <summary>
-               ///     Delete a registry key.
-               /// </summary>
-               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode)]
-               private static extern int RegDeleteKey_Internal (IntPtr keyHandle, 
-                               string valueName);
-
-               public int RegDeleteKey (IntPtr handle, string valuename)
+               public int ValueCount (RegistryKey rkey)
                {
-                       return RegDeleteKey_Internal (handle, valuename);
+                       int index, result, bufferCapacity;
+                       RegistryType type;
+                       StringBuilder buffer = new StringBuilder (BufferMaxLength);
+                       
+                       IntPtr handle = (IntPtr)rkey.Data;
+                       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.Success || result == Win32ResultCode.MoreData)
+                                       continue;
+                               
+                               if (result == Win32ResultCode.NoMoreEntries)
+                                       break;
+                               
+                               // something is wrong
+                               GenerateException (result);
+                       }
+                       return index;
                }
-
-               /// <summary>
-               ///     Delete a registry value.
-               /// </summary>
-               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode)]
-               private static extern int RegDeleteValue_Internal (IntPtr keyHandle, 
-                               string valueName);
-
-               public int RegDeleteValue (IntPtr handle, string valuename)
+               
+               public RegistryKey OpenSubKey (RegistryKey rkey, string keyName, bool writtable)
                {
-                       return RegDeleteValue_Internal (handle, valuename);
+                       int access = OpenRegKeyRead;
+                       if (writtable) access |= OpenRegKeyWrite;
+                       IntPtr handle = new IntPtr ((int) rkey.Data);
+                       
+                       IntPtr subKeyHandle;
+                       int result = RegOpenKeyEx (handle, keyName, IntPtr.Zero, access, out subKeyHandle);
+
+                       if (result == Win32ResultCode.FileNotFound)
+                               return null;
+                       
+                       if (result != Win32ResultCode.Success)
+                               GenerateException (result);
+                       
+                       return new RegistryKey (subKeyHandle, CombineName (rkey, keyName));
                }
 
-               /// <summary>
-               ///     Fetch registry key subkeys itteratively.
-               /// </summary>
-               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode)]
-               private static extern int RegEnumKey_Internal (IntPtr keyBase, int index,
-                               [Out] byte[] nameBuffer, int bufferLength);
-
-               public int RegEnumKey (IntPtr keybase, int index,
-                               [Out] byte [] namebuffer, int buffer_length)
+               public void Flush (RegistryKey rkey)
                {
-                       return RegEnumKey_Internal (keybase, index, namebuffer, buffer_length);
+                       IntPtr handle = (IntPtr)rkey.Data;
+                       RegFlushKey (handle);
                }
 
-               /// <summary>
-               ///     Fetch registry key value names itteratively.
-               ///
-               ///     Arguments 'reserved', 'data', 'dataLength' 
-               ///     should be set to IntPtr.Zero.
-               /// </summary>
-               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode)]
-               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 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);
+                       IntPtr handle = (IntPtr)rkey.Data;
+                       RegCloseKey (handle);
                }
 
-               /// <summary>
-               ///     Set a registry value with string builder data.
-               /// </summary>
-               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode)]
-               private static extern int RegSetValueEx_Internal (IntPtr keyBase, 
-                               string valueName, IntPtr reserved, int type,
-                               StringBuilder data, int rawDataLength);
-
-               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 = (IntPtr)rkey.Data;
+                       IntPtr subKeyHandle;
+                       int result = RegCreateKey (handle , keyName, out subKeyHandle);
 
-               /// <summary>
-               ///     Set a registry value with string data.
-               /// </summary>
-               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode)]
-               private static extern int RegSetValueEx_Internal (IntPtr keyBase, 
-                               string valueName, IntPtr reserved, int type,
-                               string data, int rawDataLength);
+                       if (result != Win32ResultCode.Success) {
+                               GenerateException (result);
+                       }
+                       
+                       RegistryKey subKey = new RegistryKey (subKeyHandle, CombineName (rkey, keyName));
+
+                       return subKey;
+               }
 
-               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 = (IntPtr)rkey.Data;
+                       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)]
-               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 = (IntPtr)rkey.Data;
+                       int result = RegDeleteValue (handle, value);
+                       
+                       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)]
-               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 = (IntPtr)rkey.Data;
+                       byte[] buffer = new byte [BufferMaxLength];
+                       int bufferCapacity = BufferMaxLength;
+                       ArrayList keys = new ArrayList ();
+                               
+                       for (int index = 0; true; index ++) {
+                               int result = RegEnumKey (handle, index, buffer, bufferCapacity);
+
+                               if (result == Win32ResultCode.Success) {
+                                       keys.Add (RegistryKey.DecodeString (buffer));
+                                       continue;
+                               }
+
+                               if (result == Win32ResultCode.NoMoreEntries)
+                                       break;
+
+                               // should not be here!
+                               GenerateException (result);
+                       }
+                       return (string []) keys.ToArray (typeof(String));
                }
 
-               /// <summary>
-               ///     Get a registry value's info. No data.
-               /// </summary>
-               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode)]
-               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 = (IntPtr)rkey.Data;
+                       ArrayList values = new ArrayList ();
+                       
+                       for (int index = 0; true; index ++)
+                       {
+                               StringBuilder buffer = new StringBuilder (BufferMaxLength);
+                               int bufferCapacity = buffer.Capacity;
+                               RegistryType 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;
+                                       
+                               GenerateException (result);
+                       }
+
+                       return (string []) values.ToArray (typeof(String));
                }
 
                /// <summary>
-               ///     Get a registry value. Binary data.
+               /// convert a win32 error code into an appropriate exception.
                /// </summary>
-               [DllImport ("advapi32.dll", CharSet=CharSet.Unicode)]
-               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 ();
+
+                               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);
+                       IntPtr handle = (IntPtr)rkey.Data;
+                       
+                       return String.Format ("{0} [0x{1:X}]", rkey.Name, handle.ToInt32 ());
                }
 
                /// <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)]
-               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);
                }
        }
 }