6

我发现一个使用 RegistryKey 类访问Windows 注册表的.NET模块的奇怪行为。

例如,我编写了一个访问注册表的 .NET 模块 testcom.dll。此 testcom.dll 文件由本机 32 位应用程序和 64 位应用程序使用。我的要求是获取 regkey 的值(路径是HKEY_LOCAL_MACHINE\SOFTWARE\Test\MyParameters,键名是Age)。这个“Age”键将在 32 位机器上的 32 位注册表和 64 位机器上的 64 位注册表(不是 WOW64)中。

在 64 位机器上,当 32 位应用程序使用 testcom.dll 时,会在 WOW64 注册表中搜索键“Age”。当 64 位应用程序使用 testcom.dll 时,会在 64 位注册表中搜索“Age”键。

我的要求是在 64 位机器上读取 64 位注册表中的密钥,无论应用程序使用 testcom.dll 文件。我怎样才能做到这一点?

4

5 回答 5

9

如果您可以将目标 .Net 版本更改为 v4,那么您可以使用新的 OpenBaseKey 功能,例如

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);
}
于 2010-06-01T18:19:52.257 回答
5

我对此进行了广泛的研究,发现在 .NET 4 中使用托管代码可以轻松处理,但在 .NET 4 之前,您必须加载 DLLIMport advapi32.dll。

这是我的研究。

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

于 2011-01-25T02:59:10.777 回答
4

我遇到过类似的问题,我发现的最佳答案是回退到 Win32 注册表函数(例如RegOpenKeyEx)并传入适当的注册表项安全和访问权限,特别是samDesired使用KEY_WOW64_64KEY.

这太糟糕了,我希望你能在这里听到更好的答案。

于 2009-09-24T10:08:17.407 回答
2

在以下代码中,GetAge()将返回您的键值,如果键不存在,则返回 null。

[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);
    }
}
于 2009-11-12T15:26:37.237 回答
2

Blair 关于恢复到 Win32 API 并在其中调用 RegOpenKeyEx 函数的回答是实现这一目标的最佳方式。

Windows 本身会使用Registry RedirectorRegistry Reflection将特定的注册表位置映射到逻辑视图中。

您可以在以下 MSDN 文章中阅读有关此过程的更多信息:
注册表中的 32 位和 64 位应用程序数据

尽管 Win32 API 是实现此目的的最佳方法,但这是对您要检索的注册表位置进行“硬编码”的可能性,尽管这可能会出现问题(Microsoft 本身不支持此方法) . 您可以在此堆栈溢出问题中阅读更多相关信息:
如何从 64 位 .NET 应用程序打开 WOW64 注册表项

最终,Win32 API 似乎是目前最好的解决方案(如果不是最优雅的)。来自 Microsoft 的 Heath Stewart 在此 MSDN Social
question 中给出了以下答案:

不幸的是,没有办法将这些标志传递给 Microsoft.Win32 命名空间下的托管注册表 API。您必须 P/Invoke 本地 API,例如您提到的 RegCreateKeyEx。

但是,请考虑是否需要将数据存储在注册表的 32 位或 64 位视图中。MSDN 中的主题注册表重定向器具有重定向的键,您可能很熟悉,主题注册表反射具有在 32 位和 64 位键之间复制值的键。

如果您确实需要单独的视图,如果您希望 32 位和 64 位应用程序至少共享一些注册表数据,您还可以考虑为您的键启用注册表反射。有关更多详细信息,请参阅 RegEnableReflectionKey 的文档。

于 2009-09-24T10:24:27.997 回答