如何在C/ c++中获取磁盘驱动器序列号?
How do I get the disk drive serial number in C/C++
这个问题已经有了答案,但这是一个c#解决方案。我如何在C或c++中做到这一点?
有几种方法可以做到这一点。你可以用系统打电话来获取信息。
Linux的:
system("hdparm -i /dev/hda | grep -i serial");
不使用system:
static struct hd_driveid hd;
int fd;
if ((fd = open("/dev/hda", O_RDONLY | O_NONBLOCK)) < 0) {
printf("ERROR opening /dev/hdan");
exit(1);
}
if (!ioctl(fd, HDIO_GET_IDENTITY, &hd)) {
printf("%.20sn", hd.serial_no);
} else if (errno == -ENOMSG) {
printf("No serial number availablen");
} 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或system。
所以你可以很容易地从WMI得到任何东西,包括硬盘序列号。
你所要做的就是调用:
getWmiQueryResult(L"SELECT SerialNumber FROM Win32_PhysicalMedia", L"SerialNumber");
p。它基于官方文档,并且还做了一些更好的错误处理和清理。此外,您可能希望使用this或this来创建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 rootcimv2 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查询。
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;
}
对于不需要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: %sn", udev_list_entry_get_value(entry));
udev_device_unref(device);
}
}
(void)udev_unref(ud);
}
return 0;
}
代码部分基于libdev文档,部分基于udevadm的源代码。
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;
}
相关文章:
- 如何使用libusb获取驱动器名称?
- 如何获取有关Linux的磁盘信息
- 如何获取我的驱动器中具有特定扩展名的所有文件的列表
- 如何从驱动器字母中获取驱动器名称
- 使用Qstorageinfo获取网络驱动器的名称
- 获取闪存驱动器的读写速度
- 如何获取物理驱动器的卷 ID?
- 获取<whatever>包含正在运行的可执行文件的 USB 驱动器C++ /dev/
- 插入加密的 USB 驱动器后,如何使用 WMI 查找"启动器"逻辑磁盘?
- 在本地机器上获取可用的物理驱动器
- 挂载文件系统和挂载磁盘驱动器有什么区别
- 正在从驱动器号获取NTFS卷GUID
- 如何在C++中使用WMI获取硬盘的所有逻辑驱动器的可用空间
- 如何在Visual Studio Express 2013(C++)中获取特定驱动器的当前目录
- 如何在C++中找到连接到USB端口(HID或磁盘驱动器)的设备
- 在DOS 7.x中获取大型驱动器结构信息
- Windows XP:如何从磁盘驱动器号获取USB设备位置
- 如何在C/ c++中获取磁盘驱动器序列号?
- 获取磁盘示例代码的旋转速度
- 如何在linux上获取磁盘上的文件大小