有很多类似的问题在stackoverflow上,比如:
- What's a good way to uniquely identify a computer?
- What is a good unique PC identifier?
- Unique computer id C#
- WIN32_Processor::Is ProcessorId Unique for all computers
- How to uniquely identify computer using C#?
一些被接受的答案建议使用MAC地址作为唯一标识符,这是完全不正确的。其他答案建议使用各种组件的组合,这似乎更合理。然而,在使用组合的情况下,应该考虑哪个组件自然不太可能经常更改。几天前,我们为软件许可问题开发了一个密钥生成器,我们使用CPUID和MAC的组合来唯一地识别Windows PC,直到进行实际测试之前,我们认为我们的方法已足够好。具有讽刺意味的是,当我们进行测试时,我们发现三台计算机返回相同的ID与我们的密钥生成器!
那么,真的有办法唯一地识别任何计算机吗?现在我们只需要让我们的密钥生成器在Windows PC上工作。如果可能的话,使用c#的某种方式将是很好的,因为我们的系统是基于.NET开发的。
更新:
抱歉造成一些混乱和明显的虚假警报。我们发现我们检索硬件信息的方法有误。首先,我想删除这个问题,因为我的困惑已经消失,我确信两个或更多组件的组合足以识别计算机。然而,然后我决定保留它,因为我认为我应该澄清造成问题的原因,因为同样的事情可能会伤害未来的其他人。
这就是我们在做什么(不包括其他代码):
我们使用一个getManagementInfo
函数来检索MAC和处理器ID
private String getManagementInfo(String StrKey_String, String strIndex)
{
String strHwInfo = null;
try
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from " + StrKey_String);
foreach (ManagementObject share in searcher.Get())
{
strHwInfo += share[strIndex];
}
}
catch (Exception ex)
{
// show some error message
}
return strHwInfo;
}
然后在需要的地方,我们使用了该函数来检索MAC地址。
string strMAC = getManagementInfo("Win32_NetworkAdapterConfiguration", "MacAddress");
获取处理器ID
string strProcessorId = getManagementInfo("Win32_Processor", "ProcessorId");
在这一点上,如果有多个MAC地址,strMAC
将包含多个MAC地址。要仅获取一个,我们只需取前17个字符(12个MAC数字和5个冒号之间的字符)。
strMAC = strMAC.Length > 17 ? strMAC.Remove(17) : strMAC;
我们犯了错误,是因为getManagementInfo("Win32_NetworkAdapterConfiguration", "MacAddress")
返回了许多额外的MAC地址,而这些地址实际上并没有使用。例如,在命令提示符中通过getmac
命令搜索MAC地址时,每台计算机显示了一个或两个不同的MAC地址。但是getManagementInfo("Win32_NetworkAdapterConfiguration", "MacAddress")
则返回了4到5个MAC地址,其中一些对于所有计算机都相同。由于我们只取了我们函数返回的第一个MAC地址而没有检查其他任何内容,因此相同的MAC地址被意外地放在了strMAC
中。
以下代码由Sowkot Osman编写,可通过返回仅第一个活动/启用的MAC地址来解决问题:
private static string macId()
{
return identifier("Win32_NetworkAdapterConfiguration", "MACAddress", "IPEnabled");
}
private static string identifier(string wmiClass, string wmiProperty, string wmiMustBeTrue)
{
string result = "";
System.Management.ManagementClass mc = new System.Management.ManagementClass(wmiClass);
System.Management.ManagementObjectCollection moc = mc.GetInstances();
foreach (System.Management.ManagementObject mo in moc)
{
if (mo[wmiMustBeTrue].ToString() == "True")
{
//Only get the first one
if (result == "")
{
try
{
result = mo[wmiProperty].ToString();
break;
}
catch
{
}
}
}
}
return result;
}
//Return a hardware identifier
private static string identifier(string wmiClass, string wmiProperty)
{
string result = "";
System.Management.ManagementClass mc = new System.Management.ManagementClass(wmiClass);
System.Management.ManagementObjectCollection moc = mc.GetInstances();
foreach (System.Management.ManagementObject mo in moc)
{
//Only get the first one
if (result == "")
{
try
{
result = mo[wmiProperty].ToString();
break;
}
catch
{
}
}
}
return result;
}
然而,我关于相同处理器 ID 问题的判断是正确的。当我们在三台机器的命令提示符中执行 wmic cpu get ProcessorId
命令时,它们都返回了相同的处理器 ID。
现在,我们决定使用主板序列号代替处理器 ID,并与 MAC 地址一起组成一个组合。我认为这样可以达到我们的目的,如果有些情况下不行,那我们就放手让它发展。