Как получить серийный номер диска в C/C++

На это уже ответили, но это решение на C#. Как мне сделать это на C или C++?

6 ответов

Решение

Есть несколько способов сделать это. Вы можете совершать звонки, используя систему для получения информации.

Для 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");

Без использования системы (на основе получения данных WMI):

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, которое упаковывает вызовы WMI без использования cmd или системы.
Таким образом, вы можете легко получить что угодно из WMI, включая серийный номер жесткого диска.

Все, что вам нужно сделать, это позвонить:

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

PS. Он основан на официальной документации и дополнительно улучшает обработку ошибок и их устранение. Также вы можете использовать это или это для создания запросов 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 --------------------------

        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");
}

Для Linux без доступа root/sudo:

Установите 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.

Для 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;
}

Linux: см. / Sys/class/ata_device/dev*/id

В моей системе есть четыре читаемых пользователем файла, содержащие шестнадцатеричные дампы информации об устройстве; два из них - все нули, два других содержат информацию о диске и DVD; DVD не имеет серийного номера, а серийный номер диска начинается со смещения 0x20.

Для Windows, если вам не нужен WMI, используйте DeviceIOControl(). Вот рабочая реализация, которую я использовал в течение многих лет.

      GetDiskSerialNumber("c:");

Реализация:

      std::string GetDiskSerialNumber(const std::string& pDevicePath)
{
    // open the device
    HANDLE hDevice = ::CreateFileA(devicePath.c_str(), 0, 0, NULL, OPEN_EXISTING, NULL, NULL);
    if (hDevice == INVALID_HANDLE_VALUE)
    {
        // unable to open disk
        M_LogT("GDSN - CF - FAILED - " << devicePath);
        return "";
    }

    // set the input data structure
    ::STORAGE_PROPERTY_QUERY storagePropertyQuery;
    ::ZeroMemory(&storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY));
    storagePropertyQuery.PropertyId = StorageDeviceProperty;
    storagePropertyQuery.QueryType  = PropertyStandardQuery;

    // get the necessary output buffer size
    STORAGE_DESCRIPTOR_HEADER storageDescriptorHeader = {0};
    DWORD dwBytesReturned = 0;
    if (!::DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY, &storagePropertyQuery,
            sizeof(STORAGE_PROPERTY_QUERY), &storageDescriptorHeader, sizeof(STORAGE_DESCRIPTOR_HEADER),
            &dwBytesReturned, NULL))
    {
        DWORD error = ::GetLastError();

        ::CloseHandle(hDevice);

        M_LogWarnT("MGDSNV - FAILED - " << M_WinError(error));

        return "";
    }

    // has serial number?
    if (!storageDescriptorHeader.Size)
        return "";

    // alloc the output buffer
    const DWORD dwOutBufferSize = storageDescriptorHeader.Size;
    std::unique_ptr<BYTE[]> pOutBuffer(new BYTE[dwOutBufferSize]);

    ::ZeroMemory(pOutBuffer.get(), dwOutBufferSize);

    // het the storage device descriptor
    if (!::DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY, &storagePropertyQuery,
            sizeof(STORAGE_PROPERTY_QUERY), pOutBuffer.get(), dwOutBufferSize, &dwBytesReturned, NULL))
    {
        DWORD error = ::GetLastError();
        ::CloseHandle(hDevice);

        LogWarnT("MGDSNV - FAILED - " << M_WinError(error));
        return "";
    }

    // cleanup
    ::CloseHandle(hDevice);

    std::string serial;

    // output buffer points to a STORAGE_DEVICE_DESCRIPTOR structure followed by additional
    // info like vendor ID, product ID, serial number, and so on.
    const STORAGE_DEVICE_DESCRIPTOR* pDeviceDescriptor = (STORAGE_DEVICE_DESCRIPTOR*)pOutBuffer.get();
    if (pDeviceDescriptor->SerialNumberOffset && *(pOutBuffer.get() + pDeviceDescriptor->SerialNumberOffset))
        // get the serial number
        serial = std::string(reinterpret_cast<char*>(pOutBuffer.get() + pDeviceDescriptor->SerialNumberOffset));

    return serial;
}
Другие вопросы по тегам