By default all registry keys you access from a 32bit application are redirect to the Wow6432Node, and also the other way around, when accessing it from a 64bit program, you only see the 64bit section of the registry.
The normal way of opening a registry key is:
RegistryKey rk = Registry.LocalMachine.OpenSubKey(
"SOFTWARE\Microsoft");
EDIT: In .NET 4 you don’t have to do the P/Invoke, just use this instead:
RegistryKey regkey =
RegistryKey.OpenBaseKey(
RegistryHive.LocalMachine,
RegistryView.Registry32)
.OpenSubKey("SOFTWARE")
and
RegistryKey regkey =
RegistryKey.OpenBaseKey(
RegistryHive.LocalMachine,
RegistryView.Registry64)
.OpenSubKey("SOFTWARE")
Note that this returns a different section depending on wether the application that’s executing the code has 32 or 64 bit.
To fix this, you have to use an unmanaged api that can be P/Invoked. We add the following 2 extension methods:
public static RegistryKey Open32BitSubKey(
this RegistryKey parentKey,
string subKeyName,
bool writeable)
public static RegistryKey Open64BitSubKey(
this RegistryKey parentKey,
string subKeyName,
bool writeable)
Click “toggle code” to see the full P/Invoke code
static class NativeMethods
{
[DllImport("advapi32.dll",
CharSet = CharSet.Unicode,
EntryPoint = "RegOpenKeyEx")]
static extern int RegOpenKeyEx(
IntPtr hKey,
string subKey,
uint options,
int sam,
out IntPtr phkResult);
[Flags]
public enum eRegWow64Options
{
None = 0x0000,
KEY_WOW64_64KEY = 0x0100,
KEY_WOW64_32KEY = 0x0200,
}
[Flags]
public enum eRegistryRights
{
ReadKey = 131097,
WriteKey = 131078,
}
public static RegistryKey Open32BitSubKey(
this RegistryKey parentKey,
string subKeyName,
bool writeable)
{
return OpenSubKey(
parentKey,
subKeyName,
writeable,
eRegWow64Options.KEY_WOW64_32KEY);
}
public static RegistryKey Open64BitSubKey(
this RegistryKey parentKey,
string subKeyName,
bool writeable)
{
return OpenSubKey(
parentKey,
subKeyName,
writeable,
eRegWow64Options.KEY_WOW64_64KEY);
}
static RegistryKey OpenSubKey(
RegistryKey parentKey,
string subKeyName,
bool writeable,
eRegWow64Options options)
{
if (parentKey == null)
throw new ArgumentNullException("parentKey");
IntPtr parentKeyHandle = GetRegistryKeyHandle(parentKey);
if (parentKeyHandle == IntPtr.Zero)
throw new ArgumentException("Parent key is not open", "parentKey");
eRegistryRights rights = eRegistryRights.ReadKey;
if (writeable)
rights = eRegistryRights.WriteKey;
IntPtr subKeyHandle;
int result = RegOpenKeyEx(
parentKeyHandle,
subKeyName,
0,
(int)rights | (int)options,
out subKeyHandle);
if (result != 0)
Marshal.ThrowExceptionForHR(result);
return PointerToRegistryKey(subKeyHandle, writeable, false);
}
private static IntPtr GetRegistryKeyHandle(
RegistryKey pRegisteryKey)
{
Type type = Type.GetType("Microsoft.Win32.RegistryKey");
FieldInfo info = type.GetField("hkey", BindingFlags.NonPublic |
BindingFlags.Instance);
SafeHandle handle = (SafeHandle)info.GetValue(pRegisteryKey);
return handle.DangerousGetHandle();
}
private static RegistryKey PointerToRegistryKey(IntPtr hKey, bool pWritable,
bool pOwnsHandle)
{
if (hKey == IntPtr.Zero)
return null;
// Create a SafeHandles.SafeRegistryHandle from this pointer - this
// is a private class
BindingFlags privateConstructors = BindingFlags.Instance |
BindingFlags.NonPublic;
Type safeRegistryHandleType = typeof(
SafeHandleZeroOrMinusOneIsInvalid).Assembly.GetType(
"Microsoft.Win32.SafeHandles.SafeRegistryHandle");
Type[] safeRegistryHandleConstructorTypes =
new[] { typeof(IntPtr), typeof(Boolean) };
ConstructorInfo safeRegistryHandleConstructor =
safeRegistryHandleType.GetConstructor(
privateConstructors,
null,
safeRegistryHandleConstructorTypes,
null);
Object safeHandle = safeRegistryHandleConstructor.Invoke(new Object[]
{
hKey,
pOwnsHandle
});
// Create a new Registry key using the private constructor using the
// safeHandle - this should then behave like
// a .NET natively opened handle and disposed of correctly
Type registryKeyType = typeof(RegistryKey);
Type[] registryKeyConstructorTypes =
new[] { safeRegistryHandleType, typeof(Boolean) };
ConstructorInfo registryKeyConstructor =
registryKeyType.GetConstructor(privateConstructors, null,
registryKeyConstructorTypes, null);
RegistryKey result = RegistryKey)registryKeyConstructor.Invoke(
new[] { safeHandle, pWritable });
return result;
}
}
To open the 64 bit version of the same section from a 32bit application you use:
Registry.LocalMachine.Open64BitSubKey(
subKey,
false);
And to open the 32bit version from a 64bit application:
Registry.LocalMachine.Open32BitSubKey(
subKey,
false);