C++中用Msvm类查询VM特性遇返回值异常,求帮助及示例代码
排查WMI查询Msvm类返回uReturn=0的问题
我之前用WMI的C示例代码查询Win32_OperatingSystem完全正常,但换成Msvm_SummaryInformation或者Msvm_VirtualSystemManagementService后,虽然ExecQuery的HRESULT返回成功,但调用IEnumWbemClassObject::Next()时uReturn一直是0,根本拿不到数据。试了好几种办法都没搞定,求帮忙排查,或者给个能用的Msvm_SummaryInformation的C示例。
我的关键代码片段如下:
// For example, get the name of the operating system IEnumWbemClassObject* pEnumerator = NULL; hres = pSvc->ExecQuery( bstr_t("WQL"), bstr_t("SELECT * FROM Msvm_SummaryInformation"), // Win32_OperatingSystem WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator); if (FAILED(hres)) { cout << "Query for operating system name failed." << " Error code = 0x" << hex << hres << endl; pSvc->Release(); pLoc->Release(); CoUninitialize(); return 1; // Program has failed. } // Step 7: ------------------------------------------------- // Get the data from the query in step 6 ------------------- IWbemClassObject *pclsObj = NULL; ULONG uReturn = 0; while (pEnumerator) { HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); if(0 == uReturn) // ==> This returns 0 { break; } // ... 后续处理代码 }
可能的问题原因
- 权限不足:
Msvm_*类是Hyper-V相关的WMI类,必须以管理员权限运行程序才能访问,普通用户权限下查询会返回空结果。 - 命名空间错误:这些类不在默认的
root\cimv2命名空间,而是位于root\virtualization\v2(Windows 8及以后版本)或者root\virtualization(Windows 7/Server 2008 R2)。如果你的代码还是连接到root\cimv2,肯定查不到数据。 - 缺少查询条件/环境:
Msvm_SummaryInformation关联的是Hyper-V虚拟机实例,若系统中没有创建任何虚拟机,直接SELECT *会返回空结果;部分场景下还需要指定InstanceID等条件定位特定虚拟机。
可用的Msvm_SummaryInformation C++示例
下面是一个完整的示例,包含正确的命名空间连接、权限设置和查询逻辑:
#define _WIN32_DCOM #include <iostream> #include <comdef.h> #include <Wbemidl.h> #pragma comment(lib, "wbemuuid.lib") int main(int argc, char** argv) { HRESULT hres; // 初始化COM库 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; } // 设置COM安全级别 hres = CoInitializeSecurity( NULL, -1, // 认证服务 NULL, // 认证列表 NULL, // 保留 RPC_C_AUTHN_LEVEL_DEFAULT, // 默认认证级别 RPC_C_IMP_LEVEL_IMPERSONATE, // 模拟级别 NULL, // 认证信息 EOAC_NONE, // 附加能力 NULL // 保留 ); if (FAILED(hres)) { std::cout << "Failed to initialize security. Error code = 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 << "Failed to create IWbemLocator object. Error code = 0x" << std::hex << hres << std::endl; CoUninitialize(); return 1; } // 连接到Hyper-V的WMI命名空间 IWbemServices* pSvc = NULL; hres = pLoc->ConnectServer( _bstr_t(L"root\\virtualization\\v2"), // Hyper-V WMI命名空间(Win8+) NULL, // 用户名 NULL, // 密码 0, // 本地语言 NULL, // 安全标志 0, // 权威 0, // 上下文对象 &pSvc // 服务指针 ); if (FAILED(hres)) { std::cout << "Could not connect. Error code = 0x" << std::hex << hres << std::endl; pLoc->Release(); CoUninitialize(); return 1; } std::cout << "Connected to root\\virtualization\\v2 WMI namespace" << std::endl; // 设置代理安全级别 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 << "Could not set proxy blanket. Error code = 0x" << std::hex << hres << std::endl; pSvc->Release(); pLoc->Release(); CoUninitialize(); return 1; } // 查询Msvm_SummaryInformation IEnumWbemClassObject* pEnumerator = NULL; hres = pSvc->ExecQuery( bstr_t("WQL"), bstr_t("SELECT * FROM Msvm_SummaryInformation"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator); if (FAILED(hres)) { std::cout << "Query failed. Error code = 0x" << std::hex << hres << std::endl; pSvc->Release(); pLoc->Release(); CoUninitialize(); return 1; } // 遍历查询结果 IWbemClassObject* pclsObj = NULL; ULONG uReturn = 0; while (pEnumerator) { HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); if (0 == uReturn) { break; } // 获取虚拟机名称 VARIANT vtProp; hr = pclsObj->Get(L"ElementName", 0, &vtProp, 0, 0); if (SUCCEEDED(hr)) { if (vtProp.vt == VT_BSTR) { std::wcout << L"Virtual Machine Name: " << vtProp.bstrVal << std::endl; } VariantClear(&vtProp); } // 获取虚拟机状态 hr = pclsObj->Get(L"EnabledState", 0, &vtProp, 0, 0); if (SUCCEEDED(hr)) { if (vtProp.vt == VT_I4) { std::cout << "Enabled State: " << vtProp.lVal << std::endl; } VariantClear(&vtProp); } pclsObj->Release(); } // 清理资源 pEnumerator->Release(); pSvc->Release(); pLoc->Release(); CoUninitialize(); return 0; }
注意事项
- 必须以管理员身份运行这个程序,否则会返回空结果。
- 如果你的系统是Windows 7/Server 2008 R2,把命名空间改成
root\virtualization。 - 如果没有创建任何Hyper-V虚拟机,查询结果依然会是空的,这属于正常情况。
内容的提问来源于stack exchange,提问作者Santhosh Kumar
相关产品推荐
相关产品推荐

