I have a registry HKEY that is openend with RegOpenKeyEx (WinApi). Now I would like to convert the HKEY to the object Microsoft.Win32.RegistryKey. This would allow me to use the more convenient .Net operations to further proceed with this key.
Do you know how this conversion can be done in a reliable way for C# .Net 2.0 not higher?
Thanks for your help!
I tried to use reflection to access RegistryKey.GetBaseKey(hKey) for the conversion from HKEY to RegistryKey but this failed:
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int RegOpenKeyEx(IntPtr hKey, string subKey, int ulOptions, int samDesired, out IntPtr phkResult);
public enum RegWow64Options
{
None = 0,
KEY_WOW64_64KEY = 0x0100,
KEY_WOW64_32KEY = 0x0200
}
public enum RegRights
{
ReadKey = 131097,
WriteKey = 131078
}
static void exampleTransformKeytoRegistryKey()
{
IntPtr hKeyChild;
IntPtr hKeyParent = getRegistryKeyHandle(Registry.LocalMachine);
if (hKeyParent != IntPtr.Zero)
{
int result = RegOpenKeyEx(
getRegistryKeyHandle(Registry.LocalMachine),
@"SOFTWARE\Microsoft",
0,
((int)RegRights.ReadKey) | ((int)RegWow64Options.KEY_WOW64_64KEY),
out hKeyChild);
if (result == 0)
{
// hKeyChild has been retrieved
// now convert hKeyChild to RegistryKey keyChild
Type keyType = typeof(RegistryKey);
RegistryKey keyChild = (RegistryKey)keyType.InvokeMember(
"GetBaseKey",
System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static,
null,
keyType,
new object[] { hKeyChild });
// work with keyChild...
}
}
}
static IntPtr getRegistryKeyHandle(RegistryKey registryKey)
{
Type registryKeyType = typeof(RegistryKey);
System.Reflection.FieldInfo fieldInfo =
registryKeyType.GetField("hkey", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
SafeHandle handle = (SafeHandle)fieldInfo.GetValue(registryKey);
IntPtr dangerousHandle = handle.DangerousGetHandle();
return dangerousHandle;
}
Update: The following approach will work (to some degree). Please focus on the function getKeyToRegistryKey.
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int RegOpenKeyEx(IntPtr hKey, string subKey, int ulOptions, int samDesired, out IntPtr phkResult);
public enum RegWow64Options
{
None = 0,
KEY_WOW64_64KEY = 0x0100,
KEY_WOW64_32KEY = 0x0200
}
public enum RegRights
{
ReadKey = 131097,
WriteKey = 131078
}
static void exampleTransformKeytoRegistryKey2()
{
IntPtr hKeyChild;
IntPtr hKeyParent = getRegistryKeyHandle(Registry.LocalMachine);
if (hKeyParent != IntPtr.Zero)
{
int result = RegOpenKeyEx(
getRegistryKeyHandle(Registry.LocalMachine),
@"SOFTWARE\Microsoft",
0,
((int)RegRights.ReadKey) | ((int)RegWow64Options.KEY_WOW64_32KEY),
out hKeyChild);
if (result == 0)
{
// hKeyChild has been retrieved
// now convert hKeyChild to RegistryKey keyChild
RegistryKey keyChild = getKeyToRegistryKey(hKeyChild, false, true);
// work with keyChild...
}
}
}
static RegistryKey getKeyToRegistryKey(IntPtr hKey, bool writable, bool ownsHandle)
{
//Get the BindingFlags for private contructors
System.Reflection.BindingFlags privateConstructors = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic;
//Get the Type for the SafeRegistryHandle
Type safeRegistryHandleType = typeof(Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid).Assembly.GetType("Microsoft.Win32.SafeHandles.SafeRegistryHandle");
//Get the array of types matching the args of the ctor we want
Type[] safeRegistryHandleCtorTypes = new Type[] { typeof(IntPtr), typeof(bool) };
//Get the constructorinfo for our object
System.Reflection.ConstructorInfo safeRegistryHandleCtorInfo = safeRegistryHandleType.GetConstructor(
privateConstructors, null, safeRegistryHandleCtorTypes, null);
//Invoke the constructor, getting us a SafeRegistryHandle
Object safeHandle = safeRegistryHandleCtorInfo.Invoke(new Object[] { hKey, ownsHandle });
//Get the type of a RegistryKey
Type registryKeyType = typeof(RegistryKey);
//Get the array of types matching the args of the ctor we want
Type[] registryKeyConstructorTypes = new Type[] { safeRegistryHandleType, typeof(bool) };
//Get the constructorinfo for our object
System.Reflection.ConstructorInfo registryKeyCtorInfo = registryKeyType.GetConstructor(
privateConstructors, null, registryKeyConstructorTypes, null);
//Invoke the constructor, getting us a RegistryKey
RegistryKey resultKey = (RegistryKey)registryKeyCtorInfo.Invoke(new Object[] { safeHandle, writable });
//return the resulting key
return resultKey;
}
static IntPtr getRegistryKeyHandle(RegistryKey registryKey)
{
Type registryKeyType = typeof(RegistryKey);
System.Reflection.FieldInfo fieldInfo =
registryKeyType.GetField("hkey", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
SafeHandle handle = (SafeHandle)fieldInfo.GetValue(registryKey);
IntPtr dangerousHandle = handle.DangerousGetHandle();
return dangerousHandle;
}
The problem with this approach is that it will only work in pure .Net 2.0 applications. If you use the code in a .Net 2.0 DLL and try to use it from a .Net 4.0 application the code will fail. Thus I still hope to find another solution that works in mixed environments.