Windows平台下如何用C++识别系统所在的物理主驱动器
如何在Windows中定位系统所在的物理驱动器
问题背景
我需要在Windows系统中找出操作系统所在的物理驱动器。目前已通过WMI获取物理驱动器与型号的对应关系,但由于C:盘符并不总是对应PHYSICALDRIVE0,因此需要实现盘符到物理驱动器的准确匹配。
现有代码
#include <windows.h> #include <iostream> #include <comdef.h> #include <Wbemidl.h> int main() { HRESULT hres; // Initialize COM library hres = CoInitializeEx(0, COINIT_MULTITHREADED); if (FAILED(hres)) { std::cout << "Failed to initialize COM library. Error code = 0x" << std::hex << hres << std::endl; return 1; } // Initialize security 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)) { std::cout << "Failed to initialize security. Error code = 0x" << std::hex << hres << std::endl; CoUninitialize(); return 1; } // Obtain the initial locator to WMI IWbemLocator *pLoc = NULL; hres = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc); if (FAILED(hres)) { std::cout << "Failed to create IWbemLocator object. Error code = 0x" << std::hex << hres << std::endl; CoUninitialize(); return 1; } // Connect to WMI namespace IWbemServices *pSvc = NULL; hres = pLoc->ConnectServer( _bstr_t(L"ROOT\\CIMV2"), NULL, // User name NULL, // Password 0, // Locale NULL, // Security flags 0, // Authority 0, // Context object &pSvc // IWbemServices proxy ); if (FAILED(hres)) { std::cout << "Could not connect. Error code = 0x" << std::hex << hres << std::endl; pLoc->Release(); CoUninitialize(); return 1; } // 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)) { std::cout << "Could not set proxy blanket. Error code = 0x" << std::hex << hres << std::endl; pSvc->Release(); pLoc->Release(); CoUninitialize(); return 1; } // Use the IWbemServices pointer to make requests of WMI IEnumWbemClassObject* pEnumerator = NULL; hres = pSvc->ExecQuery( bstr_t("WQL"), bstr_t("SELECT DeviceID, Model FROM Win32_DiskDrive"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator); if (FAILED(hres)) { std::cout << "Query for disk drives failed. Error code = 0x" << std::hex << hres << std::endl; pSvc->Release(); pLoc->Release(); CoUninitialize(); return 1; // Program has failed. } // Get the data from the query IWbemClassObject *pclsObj = NULL; ULONG uReturn = 0; while (pEnumerator) { HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); if(0 == uReturn) { break; } VARIANT vtDeviceID; VARIANT vtModel; // Get the value of the DeviceID and Model properties hr = pclsObj->Get(L"DeviceID", 0, &vtDeviceID, 0, 0); hr = pclsObj->Get(L"Model", 0, &vtModel, 0, 0); std::wcout << "Device ID : " << vtDeviceID.bstrVal << ", Model : " << vtModel.bstrVal << std::endl; VariantClear(&vtDeviceID); VariantClear(&vtModel); pclsObj->Release(); } // Cleanup pSvc->Release(); pLoc->Release(); pEnumerator->Release(); CoUninitialize(); return 0; }
当前输出
Device ID : \\.\PHYSICALDRIVE5, Model : Microsoft Virtual Disk Device ID : \\.\PHYSICALDRIVE3, Model : NORELSYS 1081 SD USB Device Device ID : \\.\PHYSICALDRIVE2, Model : ADATA SX8200PNP Device ID : \\.\PHYSICALDRIVE0, Model : CT480BX500SSD1 Device ID : \\.\PHYSICALDRIVE4, Model : NORELSYS 1081 TF USB Device Device ID : \\.\PHYSICALDRIVE1, Model : ADATA SP550
核心问题
我的系统实际位于PHYSICALDRIVE2,如何通过编程实现系统盘符(C:)与对应物理驱动器的匹配?
补充说明
- 最终需求是读取磁盘序列号用于安全验证,但Win32_DiskDrive的查询顺序不确定(环境中存在无序列号的虚拟磁盘),因此无法依赖查询顺序定位系统盘。
- 已获取目标磁盘的详细信息:
Disk Information Dump:
Model: ADATA SX8200PNP
Serial Number: 2Jxxxxxxxxxx _00000001.
Interface Type: SCSI
Media Type: Fixed hard disk media
Connected as: \.\PHYSICALDRIVE2
解决方案
核心思路是通过WMI的关联类建立系统盘符→磁盘分区→物理驱动器的映射关系,具体步骤如下:
- 查询
Win32_OperatingSystem获取系统所在的盘符(如C:) - 通过
Win32_LogicalDiskToPartition关联逻辑盘符到对应的磁盘分区 - 通过
Win32_DiskDriveToDiskPartition关联磁盘分区到对应的物理驱动器 - 最终匹配得到系统所在的PHYSICALDRIVE编号
修改后的完整代码
#include <windows.h> #include <iostream> #include <comdef.h> #include <Wbemidl.h> #include <string> #pragma comment(lib, "wbemuuid.lib") // 辅助函数:从WMI对象中获取字符串属性值 std::wstring GetWmiStringProperty(IWbemClassObject* pObj, const wchar_t* propertyName) { VARIANT vtProp; VariantInit(&vtProp); HRESULT hr = pObj->Get(propertyName, 0, &vtProp, nullptr, nullptr); if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR && vtProp.bstrVal != nullptr) { std::wstring value(vtProp.bstrVal); VariantClear(&vtProp); return value; } VariantClear(&vtProp); return L""; } int main() { HRESULT hres; // 初始化COM库 hres = CoInitializeEx(0, COINIT_MULTITHREADED); if (FAILED(hres)) { std::cout << "初始化COM库失败,错误码: 0x" << std::hex << hres << std::endl; return 1; } // 初始化安全设置 hres = CoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL ); if (FAILED(hres) && hres != RPC_E_TOO_LATE) { std::cout << "初始化安全设置失败,错误码: 0x" << std::hex << hres << std::endl; CoUninitialize(); return 1; } // 创建WMI定位器 IWbemLocator* pLoc = NULL; hres = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLoc ); if (FAILED(hres)) { std::cout << "创建IWbemLocator失败,错误码: 0x" << std::hex << hres << std::endl; CoUninitialize(); return 1; } // 连接到WMI命名空间 IWbemServices* pSvc = NULL; hres = pLoc->ConnectServer( _bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &pSvc ); if (FAILED(hres)) { std::cout << "连接WMI失败,错误码: 0x" << std::hex << hres << std::endl; pLoc->Release(); CoUninitialize(); return 1; } // 设置代理安全 blanket hres = CoSetProxyBlanket( pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE ); if (FAILED(hres)) { std::cout << "设置代理安全失败,错误码: 0x" << std::hex << hres << std::endl; pSvc->Release(); pLoc->Release(); CoUninitialize(); return 1; } // 步骤1:获取系统盘符(如C:) std::wstring systemDrive; IEnumWbemClassObject* pOsEnumerator = NULL; hres = pSvc->ExecQuery( bstr_t("WQL"), bstr_t("SELECT SystemDrive FROM Win32_OperatingSystem"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pOsEnumerator ); if (SUCCEEDED(hres)) { IWbemClassObject* pOsObj = NULL; ULONG uReturn = 0; if (pOsEnumerator->Next(WBEM_INFINITE, 1, &pOsObj, &uReturn) == WBEM_S_NO_ERROR && uReturn > 0) { systemDrive = GetWmiStringProperty(pOsObj, L"SystemDrive"); pOsObj->Release(); } pOsEnumerator->Release(); } if (systemDrive.empty()) { std::cout << "无法获取系统盘符" << std::endl; pSvc->Release(); pLoc->Release(); CoUninitialize(); return 1; } std::wcout << L"系统盘符: " << systemDrive << std::endl; // 步骤2:获取系统盘符对应的分区DeviceID std::wstring partitionDeviceID; IEnumWbemClassObject* pLogicalToPartEnumerator = NULL; std::wstring logicalQuery = L"ASSOCIATORS OF {Win32_LogicalDisk.DeviceID=\"" + systemDrive + L"\"} WHERE AssocClass=Win32_LogicalDiskToPartition"; hres = pSvc->ExecQuery( bstr_t("WQL"), bstr_t(logicalQuery.c_str()), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pLogicalToPartEnumerator ); if (SUCCEEDED(hres)) { IWbemClassObject* pPartObj = NULL; ULONG uReturn = 0; if (pLogicalToPartEnumerator->Next(WBEM_INFINITE, 1, &pPartObj, &uReturn) == WBEM_S_NO_ERROR && uReturn > 0) { partitionDeviceID = GetWmiStringProperty(pPartObj, L"DeviceID"); pPartObj->Release(); } pLogicalToPartEnumerator->Release(); } if (partitionDeviceID.empty()) { std::cout << "无法获取系统盘符对应的分区" << std::endl; pSvc->Release(); pLoc->Release(); CoUninitialize(); return 1; } std::wcout << L"对应分区: " << partitionDeviceID << std::endl; // 步骤3:获取分区对应的物理驱动器 std::wstring systemPhysicalDrive; IEnumWbemClassObject* pPartToDriveEnumerator = NULL; std::wstring driveQuery = L"ASSOCIATORS OF {Win32_DiskPartition.DeviceID=\"" + partitionDeviceID + L"\"} WHERE AssocClass=Win32_DiskDriveToDiskPartition"; hres = pSvc->ExecQuery( bstr_t("WQL"), bstr_t(driveQuery.c_str()), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pPartToDriveEnumerator ); if (SUCCEEDED(hres)) { IWbemClassObject* pDriveObj = NULL; ULONG uReturn = 0; if (pPartToDriveEnumerator->Next(WBEM_INFINITE, 1, &pDriveObj, &uReturn) == WBEM_S_NO_ERROR && uReturn > 0) { systemPhysicalDrive = GetWmiStringProperty(pDriveObj, L"DeviceID"); std::wstring model = GetWmiStringProperty(pDriveObj, L"Model"); std::wstring serialNumber = GetWmiStringProperty(pDriveObj, L"SerialNumber"); std::wcout << L"系统所在物理驱动器: " << systemPhysicalDrive << std::endl; std::wcout << L"驱动器型号: " << model << std::endl; std::wcout << L"驱动器序列号: " << serialNumber << std::endl; pDriveObj->Release(); } pPartToDriveEnumerator->Release(); } if (systemPhysicalDrive.empty()) { std::cout << "无法获取系统所在的物理驱动器" << std::endl; } // 清理资源 pSvc->Release(); pLoc->Release(); CoUninitialize(); return 0; }
代码说明
- 新增辅助函数:
GetWmiStringProperty简化WMI属性的读取和内存清理 - 系统盘符获取:通过
Win32_OperatingSystem的SystemDrive属性直接获取系统所在盘符,无需硬编码C: - 两次关联查询:
- 用
Win32_LogicalDiskToPartition找到盘符对应的磁盘分区(如Disk #2, Partition #0) - 再用
Win32_DiskDriveToDiskPartition找到分区对应的物理驱动器(如\\.\PHYSICALDRIVE2)
- 用
- 直接输出目标信息:同时获取并输出物理驱动器的型号、序列号,满足安全验证的需求
内容的提问来源于stack exchange,提问作者Markstar
相关产品推荐
相关产品推荐

