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

标签 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 数量和硬盘数量是否取决于当前的 Windows 安装?

最佳答案

您实际上拥有主板 ID、CPUID、磁盘序列号和 MAC 地址,根据经验,它们都不是 100%。

我们的数据显示

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

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

磁盘序列号是最可靠的,但容易更改,mac 可以更改,并且如果添加设备驱动程序(hyperv、wireshark 等),则可以更改应用的过滤。

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

您还应该注意,这些函数的调用速度可能非常慢(即使在快速的 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);

关于c# - 如何为每台计算机生成唯一编号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40696404/

相关文章:

c# - 如何将数组传递给执行存储命令?

php - 使用 PHP 将数据打印到打印机

windows - findstr ms-dos 命令不会搜索子目录

asp.net - Windows Server 最大文件夹数

.net - WinForms ListView 控件上的多行列表项?

c# - 如何在 C# 中使用 win 应用程序检测静态 ip

c# - 将 XML 字符串 block 附加到现有的 XmlDocument

c# - COM异常 : 80040154

c# - RegularExpressionAttribute 的正则表达式必须包含 "[S]"文本

C# 在面板上绘图