If you want to read the 64 bit (x64) part of the registry from a 32 bits (x86) C# application, you can’t use the standard:

RegistryKey key = Registry.LocalMachine;
string keyName = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer";
key = key.OpenSubKey(keyName);

This is caused by the registry virtualization of (Microsoft Windows Vista, Windows 7 etc). This will redirect the call to the “SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Installer” key.

If you want to read the “SOFTWARE\Microsoft\Windows\CurrentVersion\Installer” you must use P/Invoke in C# and call the function RegOpenKeyExW with parameter KEY_WOW64_64KEY

Note this will all change in  .NET 4.0, because .NET 4.0 will allow managed access to the 32 bit and 64 bit part of the registry.

public static UIntPtr HKEY_CURRENT_USER = (UIntPtr)0x80000001;
public static UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
public static int KEY_QUERY_VALUE = 0x0001;
public static int KEY_READ = 0x20019;

public static int KEY_SET_VALUE = 0x0002;
public static int KEY_CREATE_SUB_KEY = 0x0004;
public static int KEY_ENUMERATE_SUB_KEYS = 0x0008;
public static int KEY_WOW64_64KEY = 0x0100;
public static int KEY_WOW64_32KEY = 0x0200;

public const int Success = 0;
public const int FileNotFound = 2;
public const int AccessDenied = 5;
public const int InvalidParameter = 87;
public const int MoreData = 234;
public const int NoMoreEntries = 259;
public const int MarkedForDeletion = 1018;

public const int BufferMaxLength = 2048;

[DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "RegOpenKeyExW", SetLastError = true)]
public static extern int RegOpenKeyExW(UIntPtr hKey, string subKey, uint options, int sam, out UIntPtr phkResult);

[DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "RegEnumKeyW")]
private static extern int RegEnumKeyW(UIntPtr keyBase, int index, StringBuilder nameBuffer, int bufferLength);

public void LoopSubKeysTest()
{

    UIntPtr regKeyHandle;
    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes", 0, KEY_READ | KEY_WOW64_64KEY, out regKeyHandle) == 0)
    {
        StringBuilder buffer = new StringBuilder(BufferMaxLength);
        for (int index = 0; true; index++)
        {
            int result = RegEnumKeyW(regKeyHandle, index, buffer, buffer.Capacity);

            if (result == Success)
            {
                Console.WriteLine(buffer.ToString());
                buffer.Length = 0;
                continue;
            }

            if (result == NoMoreEntries) { break; };

            throw new ApplicationException("This RegEnumKeyW result is unknown");
        }

    }
}

A more general approach, which will always find the registry key is:

/// <summary>
///Try to find the regsitrykey in the 64 bit part of the registry.
///If not found, try to find the registrykey in the 32 bit part of the registry.
/// </summary>
/// <param name="regKeyPath"></param>
/// <returns>A registrykeyhandle</returns>
public UIntPtr GetRegistryKeyHandle(stringregKeyPath)
{
    UIntPtr regKeyHandle;

    // Check parameters
   if(string.IsNullOrEmpty(regKeyPath)) { throw newArgumentNullException("regKeyPath", "GetRegistryKeyHandle: regKeyPath is null or empty."); }

    // KEY_WOW64_64KEY
    // Access a 64-bit key from either a 32-bit or 64-bit application (not supported on Windows 2000).
    // 64-bit key = all keys in HKEY_LOCAL_MACHINE\Software except the HKEY_LOCAL_MACHINE\Software\Wow6432Node
    //
    // Check if the registrykey can be found in the 64 bit registry part of the register
   if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, regKeyPath, 0, KEY_READ | KEY_WOW64_64KEY, outregKeyHandle) != Success)
    {
        // KEY_WOW64_32KEY
        // Access a 32-bit key from either a 32-bit or 64-bit application. (not supported on Windows 2000)
        // 32-bit key = all keys in HKEY_LOCAL_MACHINE\Software\Wow6432Node
        //
        // Check if the registrykey can be found in the 32 bit registry part of the register
       if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, regKeyPath, 0, KEY_READ | KEY_WOW64_32KEY, outregKeyHandle) != Success)
        {
            throw newApplicationException(string.Format(@"GetRegistryKeyHandle: Could not find regstrykey [{0}\{1}]", Registry.LocalMachine, regKeyPath));
        }
    }

    return regKeyHandle;
}

public void LoopSubKeysTest()

        UIntPtr regKeyHandle = helper.GetRegistryKeyHandle(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes");
StringBuilder buffer = new StringBuilder(BufferMaxLength); for (int index = 0; true; index++) { int result = RegEnumKeyW(regKeyHandle, index, buffer, buffer.Capacity); if (result == Success) { Console.WriteLine(buffer.ToString()); buffer.Length = 0; continue; } if (result == NoMoreEntries) { break; }; throw new ApplicationException("This RegEnumKeyW result is unknown"); } }

Tags:

3 Comments on How to read the 64 bit (x64) part of the registry from a 32 bits (x86) C# application

  1. Claire says:

    If you’re using VS 2010 and version 4.x of the .NET framework, all you need is the following:

    RegistryBase = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);

    You can also use Registry32 if you need to access the 32-bit registry from a 64-bit application. I’m super thrilled that Microsoft included this in .NET 4.0. It’s already made my life much easier, and I’ve only just started developing in C#!

  2. Dylan says:

    Thanks for this info. I’m working on a VS2008 / .net 3.5 project where I’ve need to access the x64 view from a x32 process – your post helped.

  3. guot says:

    how to get the key value like the fucntion do
    Microsoft.Win32.RegistryKey regSubKey.GetValue()?

Leave a Reply