Home > database >  WMI: Getting weird value from Win32_OperatingSystem table
WMI: Getting weird value from Win32_OperatingSystem table

Time:10-12

I faced an issue using WMI with C .

It is the first time I've used it so I took the basic documentation example. But running it doesn't work for me.

I tried to extract the OS Name from Win32_OperatingSystem but, when I display it, I got 0x9a2fec.

I tried then with MaxNumberOfProcesses, and I got "-1".

I am on Windows 10, and I have no idea what's going on.

My code:

#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;
}

If you have any idea, please tell me.

CodePudding user response:

The issue is in the (almost) last stage of your program: the code that displays the retrieved "OS Name":

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

The problem here is that the BSTR type uses a wchar_t* for its buffer1 and the std::cout stream (an object of the std::ostream class) doesn't have an << overload that takes a wchar_t* argument (it has one for char*) – so it uses the version that takes a const void* (as the best match), which prints the address itself, rather than the pointed-to string.

In your case, there is a simple fix: Use the std::wcout stream (a std::wostream object), instead2, which does have an << overload that takes a wchar_t* argument:

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

Simply replacing your output line with the above, on my platform, changed the displayed output from a pointer value (as you are seeing) to the following:

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

I'm not sure if that's exactly what you would like but it seems like a great improvement. I'm sure you can readily add code to edit that string into the exact format you want.


1 Note that, although the BSTR type is defined as a wchar_t*, it's not really quite the same thing, in some ways. See this answer for more information.

2 On re-reading the document you linked, I see that wcout is used there, for the display of the OS Name.

  • Related