【问题标题】:WMI: Getting weird value from Win32_OperatingSystem tableWMI:从 Win32_OperatingSystem 表中获取奇怪的值
【发布时间】:2021-11-29 18:45:48
【问题描述】:

我在将 WMI 与 C++ 结合使用时遇到了问题。

这是我第一次使用它,所以我使用了基本的documentation example。但是运行它对我不起作用。

我试图从 Win32_OperatingSystem 中提取操作系统名称,但是当我显示它时,我得到了0x9a2fec

然后我尝试使用 MaxNumberOfProcesses,得到“-1”。

我使用的是 Windows 10,但我不知道发生了什么。

我的代码:

#include <iostream>
#define _WIN32_DCOM
#include <windows.h>
#include <Wbemidl.h>
#include <comdef.h>

# pragma comment(lib, "wbemuuid.lib")

bool initializeCom(){
    // Step 1: --------------------------------------------------
    // Initialize COM. ------------------------------------------

    HRESULT hres =  CoInitializeEx(0, COINIT_MULTITHREADED); 
    if (FAILED(hres))
    {
    std::cout << "Failed to initialize COM library. Error code = 0x" 
        << std::hex << hres << std::endl;
    return false;                  // Program has failed.
    }

    // Step 2: --------------------------------------------------
    // Set general COM security levels --------------------------

    hres =  CoInitializeSecurity(
        nullptr, 
        -1,                          // COM authentication
        nullptr,                        // Authentication services
        nullptr,                        // Reserved
        RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication 
        RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation  
    nullptr,                        // Authentication info
        EOAC_NONE,                   // Additional capabilities 
        nullptr                         // Reserved
        );

    if (FAILED(hres))
    {
        std::cout << "Failed to initialize security. Error code = 0x" 
            << std::hex << hres << std::endl;
        CoUninitialize();
        return false;                    // Program has failed.
    }
    return true;
}

bool setUpWBEM(IWbemLocator*& wbemLocator, IWbemServices*& wbemServices){
    // Step 3: ---------------------------------------------------
    // Obtain the initial locator to WMI -------------------------
    HRESULT hres = CoCreateInstance(
        CLSID_WbemLocator,             
        0, 
        CLSCTX_INPROC_SERVER, 
        IID_IWbemLocator, (LPVOID *) &wbemLocator);

    if (FAILED(hres))
    {
        std::cout << "Failed to create IWbemLocator object."
            << " Err code = 0x"
            << std::hex << hres << std::endl;
        CoUninitialize();
        return false;                 // Program has failed.
    }

    // Step 4: -----------------------------------------------------
    // Connect to WMI through the IWbemLocator::ConnectServer method

    // Connect to the root\cimv2 namespace with
    // the current user and obtain pointer wbemServices
    // to make IWbemServices calls.

    hres = wbemLocator->ConnectServer(
         _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
         nullptr,                    // User name. NULL = current user
         nullptr,                    // User password. NULL = current
         0,                       // Locale. NULL indicates current
         0,                    // Security flags.
         0,                       // Authority (for example, Kerberos)
         0,                       // Context object 
        &wbemServices            // pointer to IWbemServices proxy
         );

    if (FAILED(hres))
    {
        std::cout << "Could not connect. Error code = 0x" << std::hex << hres << std::endl;
        wbemLocator->Release();     
        CoUninitialize();
        return false;                // Program has failed.
    }

    std::cout << "Connected to ROOT\\CIMV2 WMI namespace" << std::endl;


    // Step 5: --------------------------------------------------
    // Set security levels on the proxy -------------------------

    hres = CoSetProxyBlanket(
       wbemServices,                // Indicates the proxy to set
       RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
       RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
       nullptr,                        // Server principal name 
       RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx 
       RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
       nullptr,                        // client identity
       EOAC_NONE                    // proxy capabilities 
    );

    if (FAILED(hres))
    {
        std::cout << "Could not set proxy blanket. Error code = 0x" 
            << std::hex << hres << std::endl;
        wbemServices->Release();
        wbemLocator->Release();     
        CoUninitialize();
        return false;               // Program has failed.
    }

    return true;
}

int main() {

    std::cout << "HelloWorld" << std::endl;
    IWbemLocator* wbemLocator{nullptr};
    IWbemServices* wbemServices{nullptr};

    try{
        if(!initializeCom())
            throw "initializeCom failed";

        if(!setUpWBEM(wbemLocator,wbemServices))
            throw "setUpWBEM failed";

        // Step 6: --------------------------------------------------
        // Use the IWbemServices pointer to make requests of WMI ----

        BSTR bstr_wql = SysAllocString(L"WQL" );
        BSTR bstr_sql = SysAllocString(L"SELECT * FROM Win32_OperatingSystem" ); 

        // For example, get the name of the operating system
        IEnumWbemClassObject* pEnumerator{nullptr};
        HRESULT hres = wbemServices->ExecQuery(
            bstr_wql, 
            bstr_sql,
            WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 
            nullptr,
            &pEnumerator);
    
        if (FAILED(hres))
        {
            std::cout << "Query for operating system name failed."
                << " Error code = 0x" 
                << std::hex << hres << std::endl;
            wbemServices->Release();
            wbemLocator->Release();
            CoUninitialize();
            throw "ExecQuery failed";;               // Program has failed.
        }

        // Step 7: -------------------------------------------------
        // Get the data from the query in step 6 -------------------

        IWbemClassObject *pclsObj{nullptr};
        ULONG uReturn = 0;

        while (pEnumerator)
        {
            HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, 
                &pclsObj, &uReturn);

            if(0 == uReturn)
            {
                break;
            }

            VARIANT vtProp;

            // Get the value of the Name property
            hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);

            if(FAILED(hr))
                std::cout << "Failed to get name " << std::endl;

            std::cout << " OS Name : " << vtProp.bstrVal << std::endl;
            VariantClear(&vtProp);
        
            pclsObj->Release();
        }

        // Cleanup
        // ========
    
        wbemServices->Release();
        wbemLocator->Release();
        pEnumerator->Release();
        CoUninitialize();

    } catch(const std::string& error){
        std::cout << error << std::endl;
    }
    return 0;
}

如果你有任何想法,请告诉我。

【问题讨论】:

    标签: c++ windows winapi operating-system wmi


    【解决方案1】:

    问题出在程序的(几乎)最后阶段:显示检索到的“操作系统名称”的代码:

    std::cout << " OS Name : " << vtProp.bstrVal << std::endl; // Prints pointer address
    

    这里的问题是BSTR 类型使用wchar_t* 作为其缓冲区1std::cout 流(std::ostream 类的对象)没有&lt;&lt; 重载采用 wchar_t* 参数(它有一个用于 char*) - 所以它使用采用 const void* 的版本(作为最佳匹配),它打印地址本身,而不是指出 -串起来。

    在您的情况下,有一个简单的解决方法:使用std::wcout 流(std::wostream 对象),而不是2确实有一个@987654334采用wchar_t* 参数的@重载:

    std::wcout << L" OS Name : " << vtProp.bstrVal << std::endl; // Prints the wchar_t* string
    

    在我的平台上,只需用上面的内容替换您的输出行,将显示的输出从指针值(如您所见)更改为以下内容:

    OS Name : Microsoft Windows 10 Pro|C:\WINDOWS|\Device\Harddisk0\Partition3
    

    我不确定这是否正是您想要的,但这似乎是一个很大的改进。我相信您可以轻松添加代码以将该字符串编辑为您想要的确切格式。


    1 请注意,尽管BSTR 类型被定义为wchar_t*,但在某些方面它并不完全相同。请参阅this answer 了解更多信息。

    2 在重新阅读您链接的文档时,我看到那里使用了wcout,用于显示操作系统名称。

    【讨论】:

    • 关于 MaxNumberOfProcesses 的问题 - 该值作为 无符号 32 位整数返回,而您的 -1 实际上是 UINT_MAX。这表明没有实际的最大进程数。请参阅 Hans Passant 的 this comment
    • 效果很好,非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多