【问题标题】:How do I get the disk drive serial number in C/C++如何在 C/C++ 中获取磁盘驱动器序列号
【发布时间】:2014-07-25 19:23:00
【问题描述】:

这已经是answered,但它是一个 C# 解决方案。如何在 C 或 C++ 中执行此操作?

【问题讨论】:

标签: c++ c windows hard-drive serial-number


【解决方案1】:

有几种方法可以做到这一点。您可以使用系统拨打电话以获取信息。

对于 Linux:

system("hdparm -i /dev/hda | grep -i serial");

不使用系统:

static struct hd_driveid hd;
int fd;

if ((fd = open("/dev/hda", O_RDONLY | O_NONBLOCK)) < 0) {
    printf("ERROR opening /dev/hda\n");
    exit(1);
}

if (!ioctl(fd, HDIO_GET_IDENTITY, &hd)) {
    printf("%.20s\n", hd.serial_no);
} else if (errno == -ENOMSG) {
    printf("No serial number available\n");
} else {
    perror("ERROR: HDIO_GET_IDENTITY");
    exit(1);
}

对于 Windows:

system("wmic path win32_physicalmedia get SerialNumber");

不使用系统(基于Getting WMI Data ):

hres = pSvc->ExecQuery(
    bstr_t("WQL"),
    bstr_t("SELECT SerialNumber FROM Win32_PhysicalMedia"),
    WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 
    NULL,
    &pEnumerator);
hr = pclsObj->Get(L"SerialNumber", 0, &vtProp, 0, 0);

【讨论】:

  • 正是如此。谢谢!
  • 在 Windows 上,这些空格是序列号字符串的一部分吗?
  • 如果你没有root权限,Linux提出的方法是行不通的。
  • 我也有空格。我不确定如何处理它们。在获得完整答案之前,我宁愿将它们视为序列号的一部分。当然,只是为了展示,最好裁剪一下。
【解决方案2】:

这是一个适用于 Windows完整解决方案,它不使用使用 cmd 或 system 包装 WMI 调用。
因此,您可以轻松地从 WMI 获得任何东西,包括硬盘驱动器序列号。

你所要做的就是打电话:

getWmiQueryResult(L"SELECT SerialNumber FROM Win32_PhysicalMedia", L"SerialNumber");

PS。它基于official documentation,另外还做了一些更好的错误处理和清理。此外,您可能希望使用 thisthis 来创建 WQL 查询。

#include "stdafx.h"

#define _WIN32_DCOM
#include <iostream>
#include <comdef.h>
#include <Wbemidl.h>

#include <vector>
#include <string>

#pragma comment(lib, "wbemuuid.lib")

enum class WmiQueryError {
    None,
    BadQueryFailure,
    PropertyExtractionFailure,
    ComInitializationFailure,
    SecurityInitializationFailure,
    IWbemLocatorFailure,
    IWbemServiceConnectionFailure,
    BlanketProxySetFailure,
};

struct WmiQueryResult
{
    std::vector<std::wstring> ResultList;
    WmiQueryError Error = WmiQueryError::None;
    std::wstring ErrorDescription;
};

WmiQueryResult getWmiQueryResult(std::wstring wmiQuery, std::wstring propNameOfResultObject, bool allowEmptyItems = false) {

    WmiQueryResult retVal;
    retVal.Error = WmiQueryError::None;
    retVal.ErrorDescription = L"";

    HRESULT hres;


    IWbemLocator *pLoc = NULL;
    IWbemServices *pSvc = NULL;
    IEnumWbemClassObject* pEnumerator = NULL;
    IWbemClassObject *pclsObj = NULL;
    VARIANT vtProp;


    // Step 1: --------------------------------------------------
    // Initialize COM. ------------------------------------------

    hres = CoInitializeEx(0, COINIT_MULTITHREADED);
    if (FAILED(hres))
    {
        retVal.Error = WmiQueryError::ComInitializationFailure;
        retVal.ErrorDescription = L"Failed to initialize COM library. Error code : " + std::to_wstring(hres);
    }
    else
    {
        // Step 2: --------------------------------------------------
        // Set general COM security levels --------------------------
        // note: JUCE Framework users should comment this call out,
        // as this does not need to be initialized to run the query.
        // see https://social.msdn.microsoft.com/Forums/en-US/48b5626a-0f0f-4321-aecd-17871c7fa283/unable-to-call-coinitializesecurity?forum=windowscompatibility 
        hres = CoInitializeSecurity(
            NULL,
            -1,                          // COM authentication
            NULL,                        // Authentication services
            NULL,                        // Reserved
            RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication 
            RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation  
            NULL,                        // Authentication info
            EOAC_NONE,                   // Additional capabilities 
            NULL                         // Reserved
        );


        if (FAILED(hres))
        {
            retVal.Error = WmiQueryError::SecurityInitializationFailure;
            retVal.ErrorDescription = L"Failed to initialize security. Error code : " + std::to_wstring(hres);
        }
        else
        {
            // Step 3: ---------------------------------------------------
            // Obtain the initial locator to WMI -------------------------
            pLoc = NULL;

            hres = CoCreateInstance(
                CLSID_WbemLocator,
                0,
                CLSCTX_INPROC_SERVER,
                IID_IWbemLocator, (LPVOID *)&pLoc);

            if (FAILED(hres))
            {
                retVal.Error = WmiQueryError::IWbemLocatorFailure;
                retVal.ErrorDescription = L"Failed to create IWbemLocator object. Error code : " + std::to_wstring(hres);
            }
            else
            {
                // Step 4: -----------------------------------------------------
                // Connect to WMI through the IWbemLocator::ConnectServer method

                pSvc = NULL;

                // Connect to the root\cimv2 namespace with
                // the current user and obtain pointer pSvc
                // to make IWbemServices calls.
                hres = pLoc->ConnectServer(
                    _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
                    NULL,                    // User name. NULL = current user
                    NULL,                    // User password. NULL = current
                    0,                       // Locale. NULL indicates current
                    NULL,                    // Security flags.
                    0,                       // Authority (for example, Kerberos)
                    0,                       // Context object 
                    &pSvc                    // pointer to IWbemServices proxy
                );

                // Connected to ROOT\\CIMV2 WMI namespace

                if (FAILED(hres))
                {
                    retVal.Error = WmiQueryError::IWbemServiceConnectionFailure;
                    retVal.ErrorDescription = L"Could not connect to Wbem service.. Error code : " + std::to_wstring(hres);
                }
                else
                {
                    // Step 5: --------------------------------------------------
                    // Set security levels on the proxy -------------------------

                    hres = CoSetProxyBlanket(
                        pSvc,                        // Indicates the proxy to set
                        RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
                        RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
                        NULL,                        // Server principal name 
                        RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx 
                        RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
                        NULL,                        // client identity
                        EOAC_NONE                    // proxy capabilities 
                    );

                    if (FAILED(hres))
                    {
                        retVal.Error = WmiQueryError::BlanketProxySetFailure;
                        retVal.ErrorDescription = L"Could not set proxy blanket. Error code : " + std::to_wstring(hres);
                    }
                    else
                    {
                        // Step 6: --------------------------------------------------
                        // Use the IWbemServices pointer to make requests of WMI ----

                        // For example, get the name of the operating system
                        pEnumerator = NULL;
                        hres = pSvc->ExecQuery(
                            bstr_t("WQL"),
                            bstr_t(wmiQuery.c_str()),
                            WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
                            NULL,
                            &pEnumerator);

                        if (FAILED(hres))
                        {
                            retVal.Error = WmiQueryError::BadQueryFailure;
                            retVal.ErrorDescription = L"Bad query. Error code : " + std::to_wstring(hres);
                        }
                        else
                        {
                            // Step 7: -------------------------------------------------
                            // Get the data from the query in step 6 -------------------

                            pclsObj = NULL;
                            ULONG uReturn = 0;

                            while (pEnumerator)
                            {
                                HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
                                    &pclsObj, &uReturn);

                                if (0 == uReturn)
                                {
                                    break;
                                }

                                // VARIANT vtProp;

                                // Get the value of desired property
                                hr = pclsObj->Get(propNameOfResultObject.c_str(), 0, &vtProp, 0, 0);
                                if (S_OK != hr) {
                                    retVal.Error = WmiQueryError::PropertyExtractionFailure;
                                    retVal.ErrorDescription = L"Couldn't extract property: " + propNameOfResultObject + L" from result of query. Error code : " + std::to_wstring(hr);
                                }
                                else {
                                    BSTR val = vtProp.bstrVal;

                                    // Sometimes val might be NULL even when result is S_OK
                                    // Convert NULL to empty string (otherwise "std::wstring(val)" would throw exception)
                                    if (NULL == val) {
                                        if (allowEmptyItems) {
                                            retVal.ResultList.push_back(std::wstring(L""));
                                        }
                                    }
                                    else {
                                        retVal.ResultList.push_back(std::wstring(val));
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    // Cleanup
    // ========

    VariantClear(&vtProp);
    if (pclsObj)
        pclsObj->Release();

    if (pSvc)
        pSvc->Release();

    if (pLoc)
        pLoc->Release();

    if (pEnumerator)
        pEnumerator->Release();

    CoUninitialize();

    return retVal;
}

void queryAndPrintResult(std::wstring query, std::wstring propNameOfResultObject)
{
    WmiQueryResult res;
    res = getWmiQueryResult(query, propNameOfResultObject);

    if (res.Error != WmiQueryError::None) {
        std::wcout << "Got this error while executing query: " << std::endl;
        std::wcout << res.ErrorDescription << std::endl;
        return; // Exitting function
    }

    for (const auto& item : res.ResultList) {
        std::wcout << item << std::endl;
    }
}

int main(int argc, char **argv)
{

    // Get OS and partition
    // queryAndPrintResult(L"SELECT * FROM Win32_OperatingSystem", L"Name");

    // Get list of running processes
    // queryAndPrintResult(L"Select * From Win32_Process", L"Name");

    // Get serial number of Hard Drive
    queryAndPrintResult(L"SELECT SerialNumber FROM Win32_PhysicalMedia", L"SerialNumber");

    // Get id of CPU
    queryAndPrintResult(L"SELECT ProcessorId FROM Win32_Processor", L"ProcessorId");

    // Get desktops
    queryAndPrintResult(L"SELECT * FROM Win32_DesktopMonitor ", L"DeviceId");


    system("pause");
}

注意:
@matkatmusic 发现,如果您尝试 CoInitializeSecurity,则在 JUCE 框架 的后台线程上使用此函数将失败。并建议通过删除 CoInitializeSecurity() 调用,此函数将正确运行 WMI 查询。

【讨论】:

    【解决方案3】:

    对于 Windows: wmic path win32_physicalmedia get SerialNumber

    这里是如何以运行任何命令的 字符串 形式取回数据的示例。我们使用_popen 而不是上面建议的system

    #include <cstdio>
    #include <iostream>
    #include <memory>
    #include <stdexcept>
    #include <string>
    #include <array>
    
    exec("wmic path win32_physicalmedia get SerialNumber");
    
    std::string exec(const char* cmd) {
        std::array<char, 128> buffer;
        std::string result;
        std::shared_ptr<FILE> pipe(_popen(cmd, "r"), _pclose);
        if (!pipe) throw std::runtime_error("_popen() failed!");
        while (!feof(pipe.get())) {
            if (fgets(buffer.data(), 128, pipe.get()) != NULL)
                result += buffer.data();
        }
        return result;
    }
    

    【讨论】:

      【解决方案4】:

      对于不需要 root/sudo 访问权限的 Linux:

      安装 libudev-dev。 使用如下代码:

      #include <stdio.h>
      #include <string.h>
      #include <libudev.h>
      #include <sys/stat.h>
      
      
      int main()
      {
          struct udev            *ud      = NULL;
          struct stat             statbuf;
          struct udev_device     *device  = NULL;
          struct udev_list_entry *entry   = NULL;
      
          ud = udev_new();
          if (NULL == ud) {
              fprintf(stderr, "Failed to create udev.\n");
          } else {
              if (0 != stat("/dev/sda", &statbuf)) {
                  fprintf(stderr, "Failed to stat /dev/sda.\n");
              } else {
                  device = udev_device_new_from_devnum(ud, 'b', statbuf.st_rdev);
                  if (NULL == device) {
                      fprintf(stderr, "Failed to open /dev/sda.\n");
                  } else {
                      entry = udev_device_get_properties_list_entry(device);
                      while (NULL != entry) {
                          if (0 == strcmp(udev_list_entry_get_name(entry),
                                          "ID_SERIAL")) {
                              break;
                          }
      
                          entry = udev_list_entry_get_next(entry);
                      }
      
                      printf("Serial ID: %s\n", udev_list_entry_get_value(entry));
      
                      udev_device_unref(device);
                  }
              }
      
              (void)udev_unref(ud);
          }
      
          return 0;
      } 
      

      代码部分基于 libudev 文档,部分基于 udevadm 的源代码。

      【讨论】:

        【解决方案5】:

        Linux:参见 /sys/class/ata_device/dev*/id

        在我的系统上有四个用户可读的文件,其中包含设备信息的十六进制转储;其中两个全为零,另外两个包含有关磁盘和 DVD 的信息; DVD 没有序列号,磁盘序列从偏移量 0x20 开始。

        【讨论】:

          猜你喜欢
          • 2018-05-15
          • 2017-02-22
          • 2015-07-05
          • 1970-01-01
          • 1970-01-01
          • 2011-02-25
          • 2022-11-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多