WMI獲取硬碟型號和對應邏輯分割槽
阿新 • • 發佈:2018-12-27
專案中遇到需要統計windows平臺硬體資源的需求。採用WMI進行獲取,但在獲取硬碟型號以及對應的邏輯分割槽時被卡住了。
我們知道磁碟驅動器與硬碟是一對一的關係,而硬碟與邏輯磁碟是一對多關係。採用WMI中類Win32_DiskDrive能獲取磁碟驅動器資訊,Win32_LogicalDisk能獲取具體邏輯磁碟資訊(包括已使用大小,總大小等);而GetLogicalDriveStrings 與GetDiskFreeSpaceEx Win32 API能夠獲取與Win32_LogicalDisk相同的資訊。以上無法滿足需求,如何將磁碟驅動器的磁碟型號資訊與邏輯磁碟資訊對應呢?下面直接上程式碼(程式碼是我從MSDN上找的啦~。~,少量改寫)。
#define _WIN32_DCOM #include <iostream> using namespace std; #include <comdef.h> #include <Wbemidl.h> #pragma comment(lib, "wbemuuid.lib") BOOL wmi_run(); BOOL wmi_getDriveLetters(); BOOL wmi_close(); IWbemLocator *pLoc = NULL; IWbemServices *pSvc = NULL; int main(int argc, char **argv) { wmi_run(); wmi_getDriveLetters(); system("pause"); wmi_close(); } // // Step 1-5 at: // https://msdn.microsoft.com/en-us/library/aa390423(VS.85).aspx BOOL wmi_run() { HRESULT hres; // Step 1: -------------------------------------------------- // Initialize COM. ------------------------------------------ hres = CoInitializeEx(0, COINIT_MULTITHREADED); if (FAILED(hres)) { cout << "Failed to initialize COM library. Error code = 0x" << hex << hres << endl; return 1; // Program has failed. } // Step 2: -------------------------------------------------- // Set general COM security levels -------------------------- // Note: If you are using Windows 2000, you need to specify - // the default authentication credentials for a user by using // a SOLE_AUTHENTICATION_LIST structure in the pAuthList ---- // parameter of CoInitializeSecurity ------------------------ 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)) { cout << "Failed to initialize security. Error code = 0x" << hex << hres << endl; CoUninitialize(); return 1; // Program has failed. } // Step 3: --------------------------------------------------- // Obtain the initial locator to WMI ------------------------- //IWbemLocator *pLoc = NULL; hres = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)&pLoc); if (FAILED(hres)) { cout << "Failed to create IWbemLocator object." << " Err code = 0x" << hex << hres << endl; CoUninitialize(); return 1; // Program has failed. } // Step 4: ----------------------------------------------------- // Connect to WMI through the IWbemLocator::ConnectServer method //IWbemServices *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 (e.g. Kerberos) 0, // Context object &pSvc // pointer to IWbemServices proxy ); if (FAILED(hres)) { cout << "Could not connect. Error code = 0x" << hex << hres << endl; pLoc->Release(); CoUninitialize(); return 1; // Program has failed. } cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl; // 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)) { cout << "Could not set proxy blanket. Error code = 0x" << hex << hres << endl; pSvc->Release(); pLoc->Release(); CoUninitialize(); return 1; // Program has failed. } return 0; } // // get Drives, logical Drives and Driveletters BOOL wmi_getDriveLetters() { // Use the IWbemServices pointer to make requests of WMI. // Make requests here: HRESULT hres; IEnumWbemClassObject* pEnumerator = NULL; // get localdrives hres = pSvc->ExecQuery( bstr_t("WQL"), bstr_t("SELECT * FROM Win32_DiskDrive"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator); if (FAILED(hres)) { cout << "Query for processes failed. " << "Error code = 0x" << hex << hres << endl; pSvc->Release(); pLoc->Release(); CoUninitialize(); return FALSE; // Program has failed. } else { IWbemClassObject *pclsObj; ULONG uReturn = 0; while (pEnumerator) { hres = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); if (0 == uReturn) break; VARIANT vtProp; hres = pclsObj->Get(_bstr_t(L"DeviceID"), 0, &vtProp, 0, 0); // adjust string wstring tmp = vtProp.bstrVal; tmp = tmp.substr(4); // Size屬性可以獲取硬碟的大小哦(暫時註釋掉啦) // 如果需要使用的話,注意先判斷vtProp的型別,目前雖然VARIANT結構體內建多種型別, // 但目前只支援四種類型:VT_I4、VT_DISPATCH、VT_BSTR、VT_EMPTY // 對應獲取值得名稱:lVal、pdispVal、bstrVal、none // 例如:vtProp型別為VT_BSTR,獲取值為vtProp.bstrValue // 最後注意:獲取的值為寬字元,可以通過WideCharToMultiByte轉化為多字元 // pclsObj->Get(L"Size", 0, &vtProp, 0, 0); // 列印硬碟型號 pclsObj->Get(L"Caption", 0, &vtProp, 0, 0); if (!(vtProp.vt == VT_EMPTY || vtProp.vt == VT_I4 || vtProp.vt == VT_DISPATCH)) printf("硬碟型號:%ls\n", vtProp.bstrVal); wstring wstrQuery = L"Associators of {Win32_DiskDrive.DeviceID='\\\\.\\"; wstrQuery += tmp; wstrQuery += L"'} where AssocClass=Win32_DiskDriveToDiskPartition"; // reference drive to partition IEnumWbemClassObject* pEnumerator1 = NULL; hres = pSvc->ExecQuery( bstr_t("WQL"), bstr_t(wstrQuery.c_str()), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator1); if (FAILED(hres)) { cout << "Query for processes failed. " << "Error code = 0x" << hex << hres << endl; pSvc->Release(); pLoc->Release(); CoUninitialize(); return FALSE; // Program has failed. } else { IWbemClassObject *pclsObj1; ULONG uReturn1 = 0; while (pEnumerator1) { hres = pEnumerator1->Next(WBEM_INFINITE, 1, &pclsObj1, &uReturn1); if (0 == uReturn1) break; // 此處獲取的都是Win32_DiskPartition磁碟分割槽資訊 // 我們的需求不會使用到,保持不變即可 // reference logical drive to partition VARIANT vtProp1; hres = pclsObj1->Get(_bstr_t(L"DeviceID"), 0, &vtProp1, 0, 0); //printf("DeviceID:%ls\n",vtProp1.bstrVal); wstring wstrQuery = L"Associators of {Win32_DiskPartition.DeviceID='"; wstrQuery += vtProp1.bstrVal; wstrQuery += L"'} where AssocClass=Win32_LogicalDiskToPartition"; IEnumWbemClassObject* pEnumerator2 = NULL; hres = pSvc->ExecQuery( bstr_t("WQL"), bstr_t(wstrQuery.c_str()), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator2); if (FAILED(hres)) { cout << "Query for processes failed. " << "Error code = 0x" << hex << hres << endl; pSvc->Release(); pLoc->Release(); CoUninitialize(); return FALSE; // Program has failed. } else { // get driveletter IWbemClassObject *pclsObj2; ULONG uReturn2 = 0; while (pEnumerator2) { hres = pEnumerator2->Next(WBEM_INFINITE, 1, &pclsObj2, &uReturn2); if (0 == uReturn2) break; // 獲取的是Win32_LogicalDisk的資訊 // 例如:磁碟C,磁碟D都是同一硬碟的邏輯磁碟 // 可以在單獨獲取磁碟C、磁碟D的剩餘空間,總空間資訊 // 下面vtProp.bstrVal為上面獲取的硬碟的型號 // vtProp2.bstrVal為磁碟的碟符C或D // 分別獲取磁碟的總大小和剩餘大小。注意事項和硬碟部分描述一樣 // pclsObj2->Get(L"Size", 0, &vtProp2, 0, 0); // pclsObj2->Get(L"FreeSpace", 0, &vtProp2, 0, 0); VARIANT vtProp2; hres = pclsObj2->Get(_bstr_t(L"DeviceID"), 0, &vtProp2, 0, 0); // print result printf("硬碟型號:%ls\t磁碟碟符:%ls\n", vtProp.bstrVal, vtProp2.bstrVal); VariantClear(&vtProp2); } pclsObj1->Release(); } VariantClear(&vtProp1); pEnumerator2->Release(); } pclsObj->Release(); } VariantClear(&vtProp); pEnumerator1->Release(); } } pEnumerator->Release(); return TRUE; } BOOL wmi_close() { // Cleanup // ======== pSvc->Release(); pLoc->Release(); CoUninitialize(); return 0; // Program successfully completed. }
執行結果:
我的電腦上只有一塊硬碟,硬碟對應的邏輯磁碟分割槽分別為C、D。到此完成了。