【问题标题】:Get Hard disk serial Number获取硬盘序列号
【发布时间】:2011-05-04 07:40:58
【问题描述】:

我想获取硬盘序列号。我该怎么做? 我尝试了两个代码,但没有得到

StringCollection propNames = new StringCollection();
ManagementClass driveClass = new ManagementClass("Win32_DiskDrive");
PropertyDataCollection  props = driveClass.Properties;
foreach (PropertyData driveProperty in props) 
{
    propNames.Add(driveProperty.Name);
}
int idx = 0;
ManagementObjectCollection drives = driveClass.GetInstances();
foreach (ManagementObject drv in drives)
       {
          Label2.Text+=(idx + 1);
          foreach (string strProp in propNames)
           {
            //Label2.Text+=drv[strProp];
         Response.Write(strProp + "   =   " + drv[strProp] + "</br>");
          }
    }

在这个我没有得到任何唯一序列号。
第二个是

string drive = "C";
ManagementObject disk = new ManagementObject("win32_logicaldisk.deviceid=\"" + drive + ":\"");
disk.Get();
Label3.Text = "VolumeSerialNumber="+ disk["VolumeSerialNumber"].ToString();

我在这里收到VolumeSerialNumber。但这不是唯一的。如果我格式化硬盘,这将改变。我怎样才能得到这个?

【问题讨论】:

    标签: c# hard-drive


    【解决方案1】:

    嗯,看看你的第一组代码,我想你已经检索到(也许?)硬盘模型。序列号来自Win32_PhysicalMedia

    获取硬盘型号

        ManagementObjectSearcher searcher = new
        ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");
    
       foreach(ManagementObject wmi_HD in searcher.Get())
       {
        HardDrive hd = new HardDrive();
        hd.Model = wmi_HD["Model"].ToString();
        hd.Type  = wmi_HD["InterfaceType"].ToString(); 
        hdCollection.Add(hd);
       }
    

    获取序列号

     searcher = new
        ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMedia");
    
       int i = 0;
       foreach(ManagementObject wmi_HD in searcher.Get())
       {
        // get the hard drive from collection
        // using index
        HardDrive hd = (HardDrive)hdCollection[i];
    
        // get the hardware serial no.
        if (wmi_HD["SerialNumber"] == null)
         hd.SerialNo = "None";
        else
         hd.SerialNo = wmi_HD["SerialNumber"].ToString();
    
        ++i;
       }
    

    Source

    希望这会有所帮助:)

    【讨论】:

    • 您的意思是两次发布相同的来源吗?
    • 我现在无法编译,但我确实注意到这篇文章是 2004 年的,也许它不适用于 Vista/7?仅使用编译后的 exe,实际上我的 Win7x64 上出现错误“CLR20r3”。
    • 如果用户没有管理员权限,它是否工作...如果他有管理员权限,我拥有的代码可以获取信息..但是如果我尝试使用来自没有管理员的不同用户的相同应用程序权利,没有做到这一点..
    • 我在 WinXp SP3 中试过这个.. wmi_HD["SerialNumber"] 返回 null.. 任何解决方案?
    • 为什么我的测试失败了!(win7_X64 sp1) Win32_PhysicalMedia 的收藏数量大于Win32_DiskDrive 的收藏数量。您有解决方案吗?
    【解决方案2】:

    我在一个项目中使用了以下方法,并且效果很好。

    private string identifier(string wmiClass, string wmiProperty)
    //Return a hardware identifier
    {
        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;
    }
    

    您可以如下调用上述方法,

    string modelNo = identifier("Win32_DiskDrive", "Model");
    string manufatureID = identifier("Win32_DiskDrive", "Manufacturer");
    string signature = identifier("Win32_DiskDrive", "Signature");
    string totalHeads = identifier("Win32_DiskDrive", "TotalHeads");
    

    如果您需要唯一标识符,请使用这些 ID 的组合。

    【讨论】:

    • 感谢您的回复.....格式化HD后是否会重复相同的值?
    【解决方案3】:

    @Sprunth 的回答有一个简单的方法。

    private void GetAllDiskDrives()
        {
            var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");
    
            foreach (ManagementObject wmi_HD in searcher.Get())
            {
                HardDrive hd = new HardDrive();
                hd.Model = wmi_HD["Model"].ToString();
                hd.InterfaceType = wmi_HD["InterfaceType"].ToString();
                hd.Caption = wmi_HD["Caption"].ToString();
    
                hd.SerialNo =wmi_HD.GetPropertyValue("SerialNumber").ToString();//get the serailNumber of diskdrive
    
                hdCollection.Add(hd);
            }
    
     }
    
    
    public class HardDrive
    {
        public string Model { get; set; }
        public string InterfaceType { get; set; }
        public string Caption { get; set; }
        public string SerialNo { get; set; }
    }
    

    【讨论】:

      【解决方案4】:

      使用 "vol" shell 命令并从它的输出中解析串行,就像这样。 至少在 Win7 中工作

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      
      namespace CheckHD
      {
              class HDSerial
              {
                  const string MY_SERIAL = "F845-BB23";
                  public static bool CheckSerial()
                  {
                      string res = ExecuteCommandSync("vol");
                      const string search = "Number is";
                      int startI = res.IndexOf(search, StringComparison.InvariantCultureIgnoreCase);
      
                      if (startI > 0)
                      {
                          string currentDiskID = res.Substring(startI + search.Length).Trim();
                          if (currentDiskID.Equals(MY_SERIAL))
                              return true;
                      }
                      return false;
                  }
      
                  public static string ExecuteCommandSync(object command)
                  {
                      try
                      {
                          // create the ProcessStartInfo using "cmd" as the program to be run,
                          // and "/c " as the parameters.
                          // Incidentally, /c tells cmd that we want it to execute the command that follows,
                          // and then exit.
                          System.Diagnostics.ProcessStartInfo procStartInfo =
                              new System.Diagnostics.ProcessStartInfo("cmd", "/c " + command);
      
                          // The following commands are needed to redirect the standard output.
                          // This means that it will be redirected to the Process.StandardOutput StreamReader.
                          procStartInfo.RedirectStandardOutput = true;
                          procStartInfo.UseShellExecute = false;
                          // Do not create the black window.
                          procStartInfo.CreateNoWindow = true;
                          // Now we create a process, assign its ProcessStartInfo and start it
                          System.Diagnostics.Process proc = new System.Diagnostics.Process();
                          proc.StartInfo = procStartInfo;
                          proc.Start();
                          // Get the output into a string
                          string result = proc.StandardOutput.ReadToEnd();
                          // Display the command output.
                          return result;
                      }
                      catch (Exception)
                      {
                          // Log the exception
                          return null;
                      }
                  }
              }
          }
      

      【讨论】:

      • 啊,是的,这在 Windows 的每个语言版本上都可以出色地工作。与英语版本相比,俄语、日语或挪威语版本的 Windows 中该命令的文本输出并没有什么不同,是吗?
      • 这里给出的是逻辑单元的序列号,而不是硬盘
      【解决方案5】:

      这是一个使用 win32 api 和 std 字符串的解决方案,以防您需要您的应用程序在没有 CLR 的操作系统上运行。我在github 上找到了它。

      #include "stdafx.h"
      #include <windows.h>
      #include <memory>
      #include <string>
      
      //returns the serial number of the first physical drive in a std::string or an empty std::string in case of failure
      //based on http://codexpert.ro/blog/2013/10/26/get-physical-drive-serial-number-part-1/
      std::string getFirstHddSerialNumber() {
          //get a handle to the first physical drive
          HANDLE h = CreateFileW(L"\\\\.\\PhysicalDrive0", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
          if (h == INVALID_HANDLE_VALUE) return{};
          //an std::unique_ptr is used to perform cleanup automatically when returning (i.e. to avoid code duplication)
          std::unique_ptr<std::remove_pointer<HANDLE>::type, void(*)(HANDLE)> hDevice{ h, [](HANDLE handle){CloseHandle(handle); } };
          //initialize a STORAGE_PROPERTY_QUERY data structure (to be used as input to DeviceIoControl)
          STORAGE_PROPERTY_QUERY storagePropertyQuery{};
          storagePropertyQuery.PropertyId = StorageDeviceProperty;
          storagePropertyQuery.QueryType = PropertyStandardQuery;
          //initialize a STORAGE_DESCRIPTOR_HEADER data structure (to be used as output from DeviceIoControl)
          STORAGE_DESCRIPTOR_HEADER storageDescriptorHeader{};
          //the next call to DeviceIoControl retrieves necessary size (in order to allocate a suitable buffer)
          //call DeviceIoControl and return an empty std::string on failure
          DWORD dwBytesReturned = 0;
          if (!DeviceIoControl(hDevice.get(), IOCTL_STORAGE_QUERY_PROPERTY, &storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY),
              &storageDescriptorHeader, sizeof(STORAGE_DESCRIPTOR_HEADER), &dwBytesReturned, NULL))
              return{};
          //allocate a suitable buffer
          const DWORD dwOutBufferSize = storageDescriptorHeader.Size;
          std::unique_ptr<BYTE[]> pOutBuffer{ new BYTE[dwOutBufferSize]{} };
          //call DeviceIoControl with the allocated buffer
          if (!DeviceIoControl(hDevice.get(), IOCTL_STORAGE_QUERY_PROPERTY, &storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY),
              pOutBuffer.get(), dwOutBufferSize, &dwBytesReturned, NULL))
              return{};
          //read and return the serial number out of the output buffer
          STORAGE_DEVICE_DESCRIPTOR* pDeviceDescriptor = reinterpret_cast<STORAGE_DEVICE_DESCRIPTOR*>(pOutBuffer.get());
          const DWORD dwSerialNumberOffset = pDeviceDescriptor->SerialNumberOffset;
          if (dwSerialNumberOffset == 0) return{};
          const char* serialNumber = reinterpret_cast<const char*>(pOutBuffer.get() + dwSerialNumberOffset);
          return serialNumber;
      }
      
      #include <iostream>
      int main() {
          std::string serialNumber = getFirstHddSerialNumber();
          if (serialNumber.empty())
              std::cout << "failed to retrieve serial number\n";
          else
              std::cout << "serial number: " << serialNumber << "\n";
          return 0;
      }
      

      【讨论】:

      • 感谢发布非 WMI 解决方案
      【解决方案6】:

      这里有一些代码可能会有所帮助:

      ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");
      
      string serial_number="";
      
      foreach (ManagementObject wmi_HD in searcher.Get())
      {
          serial_number = wmi_HD["SerialNumber"].ToString();
      }
      
      MessageBox.Show(serial_number);
      

      【讨论】:

      • 欢迎来到 SO。显然,这个答案已经付出了很多努力,如果它只是代码,可能很难掌握。通常用几句话来评论解决方案。请编辑您的答案并添加一些解释。另外,请记住在发布答案之前格式化代码。
      【解决方案7】:

      如果您想将它用于复制保护并且您需要它在一台计算机上始终返回相同的序列号(当然,只要第一个 hdd 或 ssd 没有更改)我会推荐下面的代码。对于 ManagementClass,您需要添加对 System.Management 的引用。附:如果没有“InterfaceType”和“DeviceID”,则检查该方法是否可以返回当前连接到PC的随机磁盘序列或USB闪存驱动器序列。

          public static string GetSerial()
          {
              try
              {
                  var mc = new ManagementClass("Win32_DiskDrive");
                  var moc = mc.GetInstances();
                  var res = string.Empty;
                  var resList = new List<string>(moc.Count);
      
                  foreach (ManagementObject mo in moc)
                  {
                      try
                      {
                          if (mo["InterfaceType"].ToString().Replace(" ", string.Empty) == "USB")
                          {
                              continue;
                          }
                      }
                      catch
                      {
                      }
      
                      try
                      {
                          res = mo["SerialNumber"].ToString().Replace(" ", string.Empty);
                          resList.Add(res);
                          if (mo["DeviceID"].ToString().Replace(" ", string.Empty).Contains("0"))
                          {
                              if (!string.IsNullOrWhiteSpace(res))
                              {
                                  return res;
                              }
                          }
                      }
                      catch
                      {
                      }
                  }
      
                  res = resList[0];
                  if (!string.IsNullOrWhiteSpace(res))
                  {
                      return res;
                  }
              }
              catch
              {
              }
      
              return string.Empty;
          }
      

      【讨论】:

        【解决方案8】:

        我发现最好的方法是从here下载一个dll

        然后,将 dll 添加到您的项目中。

        然后,添加代码:

        [DllImportAttribute("HardwareIDExtractorC.dll")]
        public static extern String GetIDESerialNumber(byte DriveNumber);
        

        然后,从你需要的地方调用硬盘ID

        GetIDESerialNumber(0).Replace(" ", string.Empty);
        

        注意:在资源管理器中转到 dll 的属性并将“构建操作”设置为“嵌入式资源”

        【讨论】:

        【解决方案9】:

        下面是获取硬盘序列号的全功能方法:

        public string GetHardDiskSerialNo()
            {
                ManagementClass mangnmt = new ManagementClass("Win32_LogicalDisk");
                ManagementObjectCollection mcol = mangnmt.GetInstances();
                string result = "";
                foreach (ManagementObject strt in mcol)
                {
                    result += Convert.ToString(strt["VolumeSerialNumber"]);
                }
                return result;
            }
        

        【讨论】:

        • LogicalDisk 序列号和 HardDisk 序列号不一样,你可以试试看有什么区别
        【解决方案10】:

        我正在使用这个:

        <!-- language: c# -->
        private static string wmiProperty(string wmiClass, string wmiProperty){
          using (var searcher = new ManagementObjectSearcher($"SELECT * FROM {wmiClass}")) {
           try {
                            IEnumerable<ManagementObject> objects = searcher.Get().Cast<ManagementObject>();
                            return objects.Select(x => x.GetPropertyValue(wmiProperty)).FirstOrDefault().ToString().Trim();
                        } catch (NullReferenceException) {
                            return null;
                        }
                    }
                }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-06-10
          • 2010-12-06
          • 1970-01-01
          • 2014-01-11
          • 1970-01-01
          • 2010-10-15
          • 2011-05-10
          相关资源
          最近更新 更多