Registry.GetValue有什么问题?

9

我想获取一个注册表键值:

var value = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography", "MachineGuid", 0);

在Windows XP中一切正常,但在Windows 7中返回0。在使用regedit查看时我看到,但如果我运行

var keys = Registry.LocalMachine.OpenSubKey("SOFTWARE").OpenSubKey("Microsoft").OpenSubKey("Cryptography", RegistryKeyPermissionCheck.ReadSubTree).GetValueNames();

keys.Length 的值为0。

我做错了什么?在其他操作系统中,所有的值都正常。


1
在Windows 7上,它为我显示MachineGuid。你的用户是管理员吗?也许这是一个权限问题。 - Jon Skeet
2
我不确定这是否是问题所在,但您使用的是64位还是32位的Windows 7? - grizzly
6个回答

23

问题可能是你正在编译x86解决方案,如果你编译为x64,则可以读取值。

尝试使用以下代码分别进行x86和x64编译:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("MachineGUID:" + MachineGUID);

        Console.ReadKey();
    }

    public static string MachineGUID
    {
        get
        {
            Guid guidMachineGUID;
            if (Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Cryptography") != null)
            {
                if (Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Cryptography").GetValue("MachineGuid") != null)
                {
                    guidMachineGUID = new Guid(Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Cryptography").GetValue("MachineGuid").ToString());
                    return guidMachineGUID.ToString();
                }
            }
            return null;
        }
    }
}

您可以阅读有关访问备用注册表视图的更多信息。

您可以在这里找到一种在x86和x64中读取值的方法。


非常感谢这个绝妙的提示。我在Windows 7 / 64位系统中遇到了完全相同的问题,而文章“您可以在此处找到一种读取x86和x64值的方法”解决了我的问题。谢谢你,pedrocgsousa !!! - Matt
1
给其他人的另一个提示:如果您以正常方式打开注册表,那么如果您的应用程序是64位的,则HKLM\Software\YourVendorID无法工作 - 它将始终打开HKLM\Software\Microsoft。使用文章中描述的RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry64);来打开HKLM,随后的OpenSubKey调用将按预期工作! - Matt

7

这可能与UAC(用户账户控制)有关,它是Windows Vista和Windows 7的额外保护层。

您需要请求对注册表的权限。

编辑: 您现在的代码:

var keys = Registry.LocalMachine.OpenSubKey("SOFTWARE")
    .OpenSubKey("Microsoft")
    .OpenSubKey("Cryptography", RegistryKeyPermissionCheck.ReadSubTree)
    .GetValueNames();

只请求加密子键的权限可能导致问题(至少我曾经遇到过),因此新代码应该是:

var keys = Registry.LocalMachine.OpenSubKey("SOFTWARE", RegistryKeyPermissionCheck.ReadSubTree)
    .OpenSubKey("Microsoft", RegistryKeyPermissionCheck.ReadSubTree)
    .OpenSubKey("Cryptography", RegistryKeyPermissionCheck.ReadSubTree)
    .GetValueNames();

编辑2:
我已经将调试器附加到它上面,针对这段代码:

var key1 = Registry.LocalMachine.OpenSubKey("SOFTWARE", RegistryKeyPermissionCheck.ReadSubTree);
var key2 = key1.OpenSubKey("Microsoft", RegistryKeyPermissionCheck.ReadSubTree);
var key3 = key2.OpenSubKey("Cryptography", RegistryKeyPermissionCheck.ReadSubTree);
var key4 = key3.GetValueNames();

事实证明,您可以读取该特定值,至少这是我的猜测,因为所有数据都是正确的,直到我打开key3,那里的ValueCount为零,而不是预期的1。

我认为这是一种受保护的特殊值。


只有那个键有问题,其他键都没问题。 - Dmitriy Kudinov
我也是这么想的,但那样做会不会抛出SecurityException异常呢? - Steven Jeuris
是的,这就是我说的... 这是完全相同的代码,只不过可以进行调试。 - Aidiakapi
也许您知道注册表中还有哪些未受保护的值可以用作计算机标识符? - Dmitriy Kudinov
1
好的,你应该知道的是MachineGuid并不是唯一的,它只是一个随机变量。我不知道你在用它做什么,但如果是网络相关的话,MAC地址和IP地址可能更好,但它们也不是完全可靠的。 - Aidiakapi
显示剩余2条评论

6

我一直在尝试弄清楚为什么我的编辑值没有返回。这个解决了我的问题,谢谢! - inexcitus

3

如果您不是管理员,您只有在HKLM上的读取权限。您需要只读方式打开密钥。不确定如何使用.NET的Registry类来做到这一点;直接使用API,您可以使用RegOpenKeyEx()并带有KEY_READ标志。

编辑:在查阅MSDN后,我发现OpenSubKey()确实以只读方式打开,并在成功时返回内容,在失败时返回空内容。由于您正在链接多个OpenSubKey调用,最有可能是其中一个OpenSubKey调用失败导致其他调用也失败。尝试将它们分别分解为单独的调用,并检查返回的中间值。


0

也许我来晚了,但是,没有一个解决方案适用于我。

这是我解决这个问题的方法:

public static Guid GetMachineGuid
    {
        get
        {
            var machineGuid = Guid.Empty;

            var localMachineX64View = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
            var cryptographySubKey = localMachineX64View.OpenSubKey(@"SOFTWARE\Microsoft\Cryptography");
            
            if (cryptographySubKey == null) return machineGuid;
            
            var machineGuidValue = (string)cryptographySubKey.GetValue("MachineGuid");

            Guid.TryParse(machineGuidValue, out machineGuid);

            return machineGuid;
        }
    }

-1

我按照pedrocgsousa提到的方法导入了Microsoft.Win32并将应用程序设置更改为x64,这样问题就解决了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接