Reading 64 bit registry from 32bit app
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 use 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)
Native methods required:
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);