This has been already answered but it's a C# solution. How do I do this in C or C++?
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);
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.
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;
}
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.
Linux: see /sys/class/ata_device/dev*/id
On my system there are four user-readable files containing hex dumps of device info; two of them are all zeros, two other contain info about disk and DVD; DVD has no serial number and disk serial starts at offset 0x20.
For Windows, if you don't want WMI, use DeviceIOControl(). Here is a working implementation that I have used for years.
GetDiskSerialNumber("c:");
Implementation:
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;
}
© 2022 - 2024 — McMap. All rights reserved.