views:

503

answers:

4

Hello Everyone, I am finding a strange behavior with a .Net module accessing registry using RegistryKey class. For eg I have written .Net module testcom.dll which access registry. This testcom.dll is used both by native 32 bit application and 64 bit application. My requirement is to get the value of a regkey (path being HKEY_LOCAL_MACHINE\SOFTWARE\Test\MyParameters and key name is Age). This "Age" key will be in 32 bit registry in 32 bit machines and 64 bit registry(Not WOW64) in 64 machines.

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

My requirement is to read the key in 64 bit registry in 64 bit machines whatever application uses the testcom.dll. Has anyone come across this? Could anyone help me out?

Thanks in Advance, -Mani.

A: 

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 ORing the samDesired parameter with KEY_WOW64_64KEY.

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

Blair Conrad
Thanks for ur reply. I also hope for the best :)
Manigandan
+1  A: 

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.

CraigTP
A: 

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
A: 

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