C# 获取 Windows 序列号(原为:从注册表获取 MachineGuid)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14213020/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 11:04:48  来源:igfitidea点击:

Getting Windows serial number (was: Getting MachineGuid from Registry)

c#windowsregistrywmiserial-number

提问by Bart Friederichs

I am trying to fetch MachineGuidfrom the registry, to create some level of binding with the OS for my license system. From the documentation I can use

我试图MachineGuid从注册表中获取,为我的许可证系统创建与操作系统的某种程度的绑定。从我可以使用的文档中

string key = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography";
string r = (string)Registry.GetValue(key, "MachineGuid", (object)"default");

to get it. Also, the docs tell me that I get "default"when the name is not found, or nullif the key doesn't exist. I should get a security exception if I have no access.

为拿到它,为实现它。此外,文档告诉我,"default"当找不到名称或null密钥不存在时,我会得到。如果我没有访问权限,我应该得到一个安全例外。

The above code gives me "default", which means the name isn't found. However, if I look in the registry with RegEdit, it's there. How do I get the MachineGuidvalue from an application without administrator privileges?

上面的代码给了我"default",这意味着找不到名字。但是,如果我使用 RegEdit 查看注册表,它就在那里。如何MachineGuid从没有管理员权限的应用程序中获取值?

Update: when using reg.exeI have no problems getting the value.

更新:使用时reg.exe我没有问题获得价值。

Update: I updated the title, so people looking for a unique way of determining the Windows install get here as well.

更新:我更新了标题,因此寻找确定 Windows 安装的独特方法的人也可以在这里找到。

采纳答案by Bart Friederichs

As other people have already pointed out, you are not supposed to get that value directly from the registry (which is probably why it doesn't work reliably among different versions of Windows).

正如其他人已经指出的那样,您不应该直接从注册表中获取该值(这可能是它在不同版本的 Windows 中无法可靠工作的原因)。

A little searching led me to the Win32_OperatingSystemWMI class. Using this class, you can actually get the Windows serial number. It took me some searching and experimenting to get it right, but this is how to use it in C#.

经过一番搜索,我找到了WMI 课程。使用这个类,您实际上可以获取Windows 序列号。我花了一些搜索和试验才把它弄对了,但这就是在 C# 中使用它的方法。Win32_OperatingSystem

Make sure you have the System.Management.dllreference in your project:

确保您System.Management.dll的项目中有参考:

using System.Management;

...

ManagementObject os = new ManagementObject("Win32_OperatingSystem=@");
string serial = (string)os["SerialNumber"];

Using the []operator, you can get any property in the class.

使用[]运算符,您可以获取类中的任何属性。

回答by Hans Passant

which is probably why it doesn't work reliably among different versions of Windows

这可能就是为什么它不能在不同版本的 Windows 中可靠地工作的原因

No, that's not the reason. This problem is caused by the platform target selection for your EXE project. Project + Properties, Build tab, Platform target combobox. You have it set to x86 instead of AnyCPU. On VS2012, the "Prefer 32-bit" checkbox matters. This setting forces your program to run in 32-bit mode on a 64-bit version of Windows. Which has a number of side effects, the one that matters here is that access to registry keys are redirected. Your program is actually reading the value of HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Cryptography\MachineGuid. Which doesn't exist.

不,这不是原因。此问题是由您的 EXE 项目的平台目标选择引起的。项目 + 属性、构建选项卡、平台目标组合框。您已将其设置为 x86 而不是 AnyCPU。在 VS2012 上,“首选 32 位”复选框很重要。此设置强制您的程序在 64 位版本的 Windows 上以 32 位模式运行。这有许多副作用,这里重要的一个是对注册表项的访问被重定向。您的程序实际上正在读取 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Cryptography\MachineGuid 的值。哪个不存在。

The x86 selection is the default for VS2010 and up, previously AnyCPU was the default. Microsoft prefers x86, Visual Studio works better with 32-bit mode processes. Particularly when debugging, VS is a 32-bit process itself so requires the remote debugger if your program executes in 64-bit mode. Which has a few limitations like not supported mixed-mode debugging. And the Edit + Continue feature only works for 32-bit code. Your program itself however works "better" if you have the setting at AnyCPU, including not getting bitten by the file system and registry redirection appcompat features built into Windows.

x86 选项是 VS2010 及更高版本的默认选项,以前 AnyCPU 是默认选项。Microsoft 更喜欢 x86,Visual Studio 更适合 32 位模式进程。特别是在调试时,VS 本身就是一个 32 位进程,因此如果您的程序在 64 位模式下执行,则需要远程调试器。它有一些限制,比如不支持混合模式调试。并且“编辑 + 继续”功能仅适用于 32 位代码。但是,如果您在 AnyCPU 上进行了设置,则您的程序本身会“更好地”运行,包括不会被 Windows 内置的文件系统和注册表重定向 appcompat 功能所困扰。

If you are really stuck with x86 mode, typically because you have a dependency on 32-bit native code that you can't update then the next workaround is to use the .NET 4+ RegistryKey.OpenBaseKey() method. Which allows you to pass RegistryView.Registry64, ensuring that you'll read the non-redirected keys.

如果您真的坚持使用 x86 模式,通常是因为您依赖于无法更新的 32 位本机代码,那么下一个解决方法是使用 .NET 4+ RegistryKey.OpenBaseKey() 方法。这允许您传递 RegistryView.Registry64,确保您将读取非重定向键。

Sure, using WMI is a workaround. Just keep in mind that you are notreading the same information when you use Win32_OperatingSystem.SerialNumber. To what degree that key is reliably random on different machines isn't that clear to me, let's just say that this value is a pretty attractive target for the kind of users that are not very interested in paying the license fee for your product either.

当然,使用 WMI 是一种解决方法。请记住,当您使用 Win32_OperatingSystem.SerialNumber 时,您不会读取相同的信息。我不清楚该密钥在不同机器上的可靠随机程度如何,我们只能说,对于那些对为您的产品支付许可费也不太感兴趣的用户来说,这个值是一个非常有吸引力的目标。

Last but not least, do consider that it is pretty easy to generate your own unique id that doesn't depend at all on Windows. With the considerable advantage that you won't piss off your customer when he updates Windows on his machine. Just use Guid.NewGuid() once and store the value in a file. That will be lost when the drive goes bad, but that usually takes out your product as well.

最后但并非最不重要的一点是,请考虑生成完全不依赖于 Windows 的您自己的唯一 ID 非常容易。具有相当大的优势,当您的客户在他的机器上更新 Windows 时,您不会惹他生气。只需使用 Guid.NewGuid() 一次并将值存储在文件中。当驱动器出现故障时,这将丢失,但这通常也会使您的产品失效。

回答by Jonathan Alfaro

I my humble opinion none of the answers satisfies the question; is pretty straight forward asking for a way to read the MachineGuid from the registry... so here is my answer: You will need to add a reference to "Microsoft.Win32". This code was written for demonstration purposes and should be adapted accordingly. EDIT:Someone stated wrongly that the x64 code is useless. In 64 bit OS that is where the correcty key is found. So this answer stands as the only one that satisfies the question.

我的拙见,没有一个答案能满足这个问题;非常直接地要求一种从注册表中读取 MachineGuid 的方法......所以这是我的答案:您需要添加对“Microsoft.Win32”的引用。此代码是为演示目的而编写的,应相应地进行调整。 编辑:有人错误地指出 x64 代码是无用的。在 64 位操作系统中,这是找到正确密钥的地方。所以这个答案是唯一满足这个问题的答案。

private void buttonGetMachineGuid_Click(object sender, RoutedEventArgs e)
{
  try
  {
    string x64Result = string.Empty;
    string x86Result = string.Empty;
    RegistryKey keyBaseX64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
    RegistryKey keyBaseX86 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32);
    RegistryKey keyX64 = keyBaseX64.OpenSubKey(@"SOFTWARE\Microsoft\Cryptography", RegistryKeyPermissionCheck.ReadSubTree);
    RegistryKey keyX86 = keyBaseX86.OpenSubKey(@"SOFTWARE\Microsoft\Cryptography", RegistryKeyPermissionCheck.ReadSubTree);
    object resultObjX64 = keyX64.GetValue("MachineGuid", (object)"default");
    object resultObjX86 = keyX86.GetValue("MachineGuid", (object)"default");
    keyX64.Close();
    keyX86.Close();
    keyBaseX64.Close();
    keyBaseX86.Close();
    keyX64.Dispose();
    keyX86.Dispose();
    keyBaseX64.Dispose();
    keyBaseX86.Dispose();
    keyX64 = null;
    keyX86 = null;
    keyBaseX64 = null;
    keyBaseX86 = null;
    if(resultObjX64 != null && resultObjX64.ToString() != "default")
    {
      MessageBox.Show(resultObjX64.ToString());
    }
    if(resultObjX86 != null && resultObjX86.ToString() != "default")
    {
      MessageBox.Show(resultObjX86.ToString());
    }
  }
  catch(Exception)
  {
  }
}

Hope this helps some one.

希望这对某人有所帮助。