How do I get the disk drive serial number in C/C++
For Windows:
wmic path win32_physicalmedia get SerialNumber
Here is example how to get back the data as a string running any command. we're using _popen
instead of system
suggested above
#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;
}
There are a few ways to do this. You could make calls using system to get the information.
For Linux:
system("hdparm -i /dev/hda | grep -i serial");
Without using system:
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);
}
For Windows:
system("wmic path win32_physicalmedia get SerialNumber");
Without using system (Based on 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);
For Linux without requiring root/sudo access:
Install libudev-dev. Use code like that below:
#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;
}
The code is partly based on libudev documentation and partly on the source code for udevadm.
Here is a complete solution for Windows which wraps WMI calls without using cmd or system .
So you can easily get anything from WMI including hard drive serial number.
All you have to do is to call :
getWmiQueryResult(L"SELECT SerialNumber FROM Win32_PhysicalMedia", L"SerialNumber");
PS. It's based on official documentation and additionally does some better error handling and cleanup. Also you might want to use this or this for creating WQL queries.
#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");
}
Note:
@matkatmusic discovered that using this function on a background thread in the JUCE framework will fail if you try to CoInitializeSecurity. And suggests that by removing the CoInitializeSecurity() call, this function will correctly run the WMI query.