如何为每台计算机生成唯一编号?

时间:2016-11-19 18:21:03

标签: c# windows winforms

我正在使用C#进行软件锁定。我需要为每台计算机生成一个唯一的编号。

我已经研究并决定使用CPU编号和硬盘编号作为每台计算机的唯一编号。

我的代码:

private string UniqID()
{
    ////////////////CpuID
    string cpuInfo = string.Empty;
    ManagementClass mc = new ManagementClass("win32_processor");
    ManagementObjectCollection moc = mc.GetInstances();

    foreach (ManagementObject mo in moc)
    {
        cpuInfo = mo.Properties["processorID"].Value.ToString();
        break;
    }

    ////////////////HDD ID
    string drive = "C";
    ManagementObject dsk = new ManagementObject(
        @"win32_logicaldisk.deviceid=""" + drive + @":""");
    dsk.Get();
    string volumeSerial = dsk["VolumeSerialNumber"].ToString();

    return volumeSerial + cpuInfo;
}

有效,但有问题! 当用户重新安装Windows(OS)并想要运行我的软件时,唯一编号已更改。 为什么在再次安装Windows时,唯一编号会发生变化? CPU编号和HDD编号是否取决于当前的Windows安装?

2 个答案:

答案 0 :(得分:2)

您实际拥有MotherboardID,CPUID,磁盘串口和MAC地址,根据经验,它们都不是100%。

我们的统计数据显示

  • 磁盘序列缺少0.1%
  • MAC缺少1.3%
  • 主板ID缺少30%
  • CPUID缺少99%

0.04%的测试机器没有提供任何信息,我们甚至无法读取计算机名称。也许这些是虚拟PC,HyperV或VMWare实例的某种?

磁盘序列是最可靠的,但很容易更改,mac可以更改,并且如果添加了设备驱动程序(hyperv,wireshark等),则应用的过滤可能会发生变化。

主板和CPUID有时会返回占位符为“无”等的值。

您还应该注意,这些功能调用起来可能非常慢(即使在快速PC上也可能需要几秒钟),因此可能需要尽早在后台线程中将它们踢掉,理想情况下我想阻止他们。

主板ID

    private static void FetchMotherboardIdInternal()
    {
        try
        {
            ManagementScope scope = new ManagementScope("\\\\" + Environment.MachineName + "\\root\\cimv2");
            scope.Connect();

            using (ManagementObject wmiClass = new ManagementObject(scope, new ManagementPath("Win32_BaseBoard.Tag=\"Base Board\""), new ObjectGetOptions()))
            {
                object motherboardIDObj = wmiClass["SerialNumber"];
                if (motherboardIDObj != null)
                {
                    string motherboardID = motherboardIDObj.ToString().Trim();
                    Trace.WriteLine("MotherboardID = " + motherboardID);
                    if (IsValidMotherBoardID(motherboardID))
                    {
                        _motherboardID = motherboardID;
                    }
                }
            }
        }
        catch (System.Threading.ThreadAbortException)
        {
            throw;
        }
        catch (Exception ex)
        {
            Trace.TraceWarning("Failed to read MotherbaordID\r\n" + ex.Message);
        }
    }
    public static bool IsValidMotherBoardID(string value)
    {
        if (value == null)
            return false;
        string motherboardID = value.Trim();
        return !(   motherboardID.Replace(".", "").Replace(" ", "").Replace("\t", "").Trim().Length < 5 ||
                   motherboardID.ToUpper().Contains("BASE") ||
                   motherboardID.Contains("2345") ||
                   motherboardID.ToUpper().StartsWith("TO BE") ||
                   motherboardID.ToUpper().StartsWith("NONE") ||
                   motherboardID.ToUpper().StartsWith("N/A") ||
                   motherboardID.ToUpper().Contains("SERIAL") ||
                   motherboardID.ToUpper().Contains("OEM") ||
                   motherboardID.ToUpper().Contains("AAAAA") ||
                   motherboardID.ToUpper().Contains("ABCDE") ||
                   motherboardID.ToUpper().Contains("XXXXX") ||
                   motherboardID.ToUpper().Contains("NOT") ||
                   motherboardID.ToUpper().StartsWith("00000")
                );

    }

CPU ID

    private static void FetchCpuIdInternal()
    {
        try
        {
            using (ManagementClass mc = new ManagementClass("Win32_Processor"))
            {
                using (ManagementObjectCollection moc = mc.GetInstances())
                {
                    foreach (ManagementObject mo in moc)
                    {
                        if (mo.Properties["UniqueId"] != null && mo.Properties["UniqueId"].Value != null)
                        {
                            // only return cpuInfo from first CPU
                            Trace.WriteLine("CPU ID = " + mo.Properties["UniqueId"].Value.ToString());
                            _cpuID = mo.Properties["UniqueId"].Value.ToString();
                        }
                        mo.Dispose();
                    }
                }
            }
        }
        catch (System.Threading.ThreadAbortException)
        {
            throw;
        }
        catch (Exception ex)
        {
            Trace.TraceWarning("Failed to read CPUID\r\n" + ex.Message);
        }
    }

第一张卡的MAC地址

    private static void FecthMACAddressInternal()
    {
        try
        {
            using (ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration"))
            {
                using (ManagementObjectCollection moc = mc.GetInstances())
                {
                    if (moc != null)
                    {
                        foreach (ManagementObject mo in moc)
                        {
                            Trace.WriteLine(mo["Index"] + " Mac " + mo["Caption"] + " : " + mo["MacAddress"] + " Enabled " + (bool)mo["IPEnabled"]);
                            if (string.IsNullOrEmpty(_macAdderss))  // only return MAC Address from first card
                            {
                                if ( mo["MacAddress"] != null && mo["IPEnabled"] != null && (bool)mo["IPEnabled"] == true)
                                {
                                    _macAdderss = mo["MacAddress"].ToString();
                                }
                            }
                            mo.Dispose();
                        }
                    }
                }
            }
        }
        catch (System.Threading.ThreadAbortException)
        {
            throw;
        }
        catch (Exception ex)
        {
            Trace.TraceWarning("Failed to read DiskID\r\n" + ex.Message);
        }
        if (_macAdderss != null)
            _macAdderss = _macAdderss.Replace(":", "");
    }

驱动器序列号

    /// <summary>
    /// return Volume Serial Number from hard drive
    /// </summary>
    /// <param name="strDriveLetter">[optional] Drive letter</param>
    /// <returns>[string] VolumeSerialNumber</returns>
    public static string GetVolumeSerial(char driveLetter)
    {
        try
        {
            using (ManagementObject disk = new ManagementObject("win32_logicaldisk.deviceid=\"" + driveLetter + ":\""))
            {
                if (disk == null)
                    return null;
                disk.Get();
                object diskObj = disk["VolumeSerialNumber"];
                if (diskObj != null)
                    return diskObj.ToString();
            }
        }
        catch (System.Threading.ThreadAbortException)
        {
            throw;
        }
        catch (Exception ex)
        {
            Trace.TraceWarning("Failed to read DiskID\r\n" + ex.Message);
        }

        try
        {
            uint serialNum, serialNumLength, flags;
            StringBuilder volumename = new StringBuilder(256);
            StringBuilder fstype = new StringBuilder(256);

            bool ok = GetVolumeInformation(driveLetter.ToString() + ":\\", volumename, (uint)volumename.Capacity - 1, out serialNum, out serialNumLength, out flags, fstype, (uint)fstype.Capacity - 1);
            if (ok)
            {
                return string.Format("{0:X4}{1:X4}", serialNum >> 16, serialNum & 0xFFFF);
            }
        }
        catch (System.Threading.ThreadAbortException)
        {
            throw;
        }
        catch (Exception ex2)
        {
            Trace.TraceWarning("Failed to read DiskID\r\n" + ex2.Message);
        }

        return null;
    }


  [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    static extern bool GetVolumeInformation(string Volume, StringBuilder VolumeName, uint VolumeNameSize, out uint SerialNumber, out uint SerialNumberLength, out uint flags, StringBuilder fs, uint fs_size);

答案 1 :(得分:1)

使用 System.Management ,您可以提取所有硬件信息。有了这个,你可以从这个值创建一个ID,meaby一个加密的id并保存它。

以下是参考:Link

我使用MAC地址,主板ID并且对我很好。

我希望这有帮助!