You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
    }
    // ... 后续处理代码
}

可能的问题原因

  1. 权限不足:Msvm_*类是Hyper-V相关的WMI类,必须以管理员权限运行程序才能访问,普通用户权限下查询会返回空结果。
  2. 命名空间错误:这些类不在默认的root\cimv2命名空间,而是位于root\virtualization\v2(Windows 8及以后版本)或者root\virtualization(Windows 7/Server 2008 R2)。如果你的代码还是连接到root\cimv2,肯定查不到数据。
  3. 缺少查询条件/环境: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 15:07:48