6

I am finding a strange behavior with a .NET module accessing the Windows Registry using the RegistryKey class.

For example, I have written a .NET module, testcom.dll, which access the registry. This testcom.dll file is used both by a native 32-bit application and a 64-bit application. My requirement is to get the value of a regkey (path being HKEY_LOCAL_MACHINE\SOFTWARE\Test\MyParameters and the key name is Age). This "Age" key will be in 32-bit registry on 32-bit machines and 64-bit registry (not WOW64) on 64-bit machines.

On a 64-bit machine, when a 32-bit application is using testcom.dll, the key "Age" is searched in the WOW64 registry. When a 64-bit application is using testcom.dll, the key "Age" is searched in the 64-bit registry.

My requirement is to read the key in the 64-bit registry on 64-bit machines whatever the application uses the testcom.dll file. How can I do this?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • Thats odd. When I once wrote an app that looked up keys and values in the registry I had to manually alter the path for 32-bit application keys when running on a 64-bit OS. Could you post some code maybe? To see if your method of loading the keys differ from mine? – Jonas B Sep 24 '09 at 10:11
  • Also the application was a 32-bit app. It did not search WOW64 by default. – Jonas B Sep 24 '09 at 10:13

5 Answers5

9

If you can change the target .Net version to v4, then you can use the new OpenBaseKey function e.g.

RegistryKey registryKey;
if (Environment.Is64BitOperatingSystem == true)
{
    registryKey = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry64);
}
else
{
    registryKey = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry32);
}
woany
  • 1,219
  • 2
  • 11
  • 10
5

I did extensive research on this and found that in .NET 4 it is handled easy with managed code, but prior to .NET 4, you have to load DLLIMport advapi32.dll.

Here is my research.

http://www.rhyous.com/2011/01/24/how-read-the-64-bit-registry-from-a-32-bit-application-or-vice-versa/

Rhyous
  • 6,510
  • 2
  • 44
  • 50
4

I have had a similar problem, and the best answer I've found is to fall back to the Win32 Registry Functions (such as RegOpenKeyEx) and pass in the appropriate Registry Key Security and Access Rights, specifically OR'ing the samDesired parameter with theKEY_WOW64_64KEY.

It was awful, and I hope you hear a better answer here.

rogerdpack
  • 62,887
  • 36
  • 269
  • 388
Blair Conrad
  • 233,004
  • 25
  • 132
  • 111
2

Blair's answer regarding reverting to the Win32 API, and calling the RegOpenKeyEx function within is about the best way of achieving this.

Windows itself will map specific registry locations into logical views using a Registry Redirector and Registry Reflection.

You can read more about this process in the following MSDN article:
32-bit and 64-bit Application Data in the Registry

Despite the Win32 API being the best way to achieve this, this is the possibility of "hard-coding" the location of the registry that you are seeking to retrieve, although this is fraught with possible problems (Microsoft themselves do not support this method). You can read more about this in this Stack Overflow Question:
How to open a WOW64 registry key from a 64-bit .NET application

Ultimately, the Win32 API seems about the best solution (if not the most elegant) at the moment.
Heath Stewart from Microsoft gives the following answer in this MSDN Social question:

Unfortunately there isn't a way to pass those flags to the managed registry APIs under the Microsoft.Win32 namespace. You would have to P/Invoke the native API such as RegCreateKeyEx that you mentioned.

Consider, however, if you need to store data in a 32- or 64-bit view of the registry. The topic Registry Redirector in MSDN has the keys that are redirected, which you're probably familiar with, and the topic Registry Reflection has the keys in which values are copied between 32- and 64-bit keys.

If indeed you need separate views, you might also consider enabling registry reflection for your keys if you desire both your 32- and 64-bit applications to share at least some registry data. See the documentation for RegEnableReflectionKey for more details.

Community
  • 1
  • 1
CraigTP
  • 44,143
  • 8
  • 72
  • 99
2

In the following code, GetAge() will return your key value, or null if the key doesn't exist.

[DllImport("Advapi32.dll")]
static extern uint RegOpenKeyEx(UIntPtr hKey, string lpSubKey, uint ulOptions, int samDesired, out int phkResult);
[DllImport("Advapi32.dll")]
static extern uint RegCloseKey(int hKey);
[DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")]
public static extern int RegQueryValueEx(int hKey, string lpValueName, int lpReserved, ref uint lpType, System.Text.StringBuilder lpData, ref uint lpcbData);

public const int KEY_QUERY_VALUE = 0x0001;
public const int KEY_WOW64_64KEY = 0x0100;

static public string GetAge()
{
    string EPG_REGKEY = @"SOFTWARE\Test\MyParameters";
    UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
    int hkey = 0;

    try
    {
        uint lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, EPG_REGKEY, 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, out hkey);
        if (0 != lResult) return null;
        uint lpType = 0;
        uint lpcbData = 1024;
        StringBuilder AgeBuffer = new StringBuilder(1024);
        RegQueryValueEx(hkey, "Age", 0, ref lpType, AgeBuffer, ref lpcbData);
        string Age = AgeBuffer.ToString();
        return Age;
    }
    finally
    {
        if (0 != hkey) RegCloseKey(hkey);
    }
}
Nestor
  • 13,706
  • 11
  • 78
  • 119