Miranda Qi
Miranda Qi

Reputation: 19

Error when use WMI to get username in C++

I'm getting an error when I try to use WMI to get the computer's username:

Error: Security must be initialized before any interfaces are marshalled or unmarshalled. It cannot be changed once initialized.

When I reverse the order between CoInitialize() and CoInitializeSecurity(), I get this error:

Error: CoInitialize has not been called.

Code is below:

HRESULT hres;
std::string userNametest;

// Initialize COM
hres = CoInitialize(NULL);
    if (FAILED(hres)) {
        _com_error err(hres);
        LPCTSTR errMsg = err.ErrorMessage();
        std::wstring w = errMsg;
        userNametest = std::string(w.begin(), w.end());
        CoUninitialize();
        if (jadedevlog.is_open()) {
            jadedevlog << "Error: " << userNametest << endl;
            jadedevlog.close();
        }
        return 1;
    }
        // Initialize security
    hres = CoInitializeSecurity(
        NULL,
        -1,
        NULL,
        NULL,
        RPC_C_AUTHN_LEVEL_DEFAULT,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        NULL,
        EOAC_NONE,
        NULL);
        if (FAILED(hres)) {
            _com_error err(hres);
            LPCTSTR errMsg = err.ErrorMessage();
            std::wstring w = errMsg;
            userNametest = std::string(w.begin(), w.end());
           
            if (jadedevlog.is_open()) {
                jadedevlog << "Error: " << userNametest << endl;
                jadedevlog.close();
            }
            CoUninitialize();
            return 1;
        }
            // Obtain the initial locator to WMI
            IWbemLocator* pLoc = NULL;
            hres = CoCreateInstance(
                CLSID_WbemLocator,
                0,
                CLSCTX_INPROC_SERVER,
                IID_IWbemLocator,
                (LPVOID*)&pLoc);

            if (FAILED(hres)) {
                CoUninitialize();
                userNametest = "fail to create WbemLocator"; // Failed to create WbemLocator
                if (jadedevlog.is_open()) {
                    jadedevlog << "Error: " << userNametest << endl;
                    jadedevlog.close();
                }
                return 1;
            }
                // Connect to WMI through the IWbemLocator::ConnectServer method
                IWbemServices* pSvc = NULL;
                hres = pLoc->ConnectServer(
                    L"ROOT\\CIMv2",  // WMI namespace
                    NULL,
                    NULL,
                    0,
                    NULL,
                    0,
                    0,
                    &pSvc);

                if (FAILED(hres)) {
                    pLoc->Release();
                    CoUninitialize();
                  
                    userNametest = "Cant connect to WMI"; // Could not connect to WMI
                    if (jadedevlog.is_open()) {
                        jadedevlog << "Error: " << userNametest << endl;
                        jadedevlog.close();
                    }
                    return 1;
                }
                    // 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)) {
                        pSvc->Release();
                        pLoc->Release();
                        CoUninitialize();
                  
                        userNametest = "Could not set proxy blanket"; // Could not set proxy blanket
                        if (jadedevlog.is_open()) {
                            jadedevlog << "Error: " << userNametest << endl;
                            jadedevlog.close();
                        }
                        return 1;
                    }
                        // Use the IWbemServices pointer to make requests of WMI
                        IEnumWbemClassObject* pEnumerator = NULL;
                        hres = pSvc->ExecQuery(
                            L"WQL",
                            L"SELECT * FROM Win32_ComputerSystem",
                            WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
                            NULL,
                            &pEnumerator);

                        if (FAILED(hres)) {
                            pSvc->Release();
                            pLoc->Release();
                            CoUninitialize();
                          
                            userNametest = "fail to query for Win32_ComputerSystem"; // Query for Win32_ComputerSystem failed
                            if (jadedevlog.is_open()) {
                                jadedevlog << "Error: " << userNametest << endl;
                                jadedevlog.close();
                            }
                            return 1;
                        }
                            // Retrieve 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) {
                                    userNametest = "no more time";
                                    break; // No more items
                                }

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

                                int wslen = SysStringLen(vtProp.bstrVal);
                                int len = WideCharToMultiByte(CP_UTF8, 0, vtProp.bstrVal, wslen, nullptr, 0, nullptr, nullptr);
                                if (len <= 0)
                                    userNametest = "Convertion fail";  //convert from BSTR to string fails
                                std::string result(len, 0);
                                WideCharToMultiByte(CP_UTF8, 0, vtProp.bstrVal, wslen, &result[0], len, nullptr, nullptr);

                                VariantClear(&vtProp);
                                pclsObj->Release();
                                userNametest = result;
                            }

                            // Cleanup
                            pSvc->Release();
                            pLoc->Release();
                            pEnumerator->Release();
                            CoUninitialize(); 

What happened?

Upvotes: 0

Views: 132

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 597580

CoInitializeSecurity() can only be called one time per process. It will return RPC_E_TOO_LATE if it has already been called. Although this is an error condition (ie, FAILED() will return true for it), it is not a fatal condition, but you are treating it as if it were. If you invoke this code multiple times in a single process, you will need to ignore RPC_E_TOO_LATE when checking CoInitializeSecurity() for failure.

Similarly for RPC_E_CHANGED_MODE on CoInitialize(). It is an error condition, but not a fatal condition. It just means that CoInitialize/Ex() was already called by the calling thread using a different concurrency model than the current call is requesting. In that case, COM is already initialized on the calling thread, so you can move forward, just don't call CoIninitialize() when you are done since your call to CoInitialize() technically "failed".

Try this:

HRESULT hres;
...

// Initialize COM
hres = CoInitialize(NULL);
bool doCoUninit = SUCCEEDED(hres);
if (FAILED(hres) && (hres != RPC_E_CHANGED_MODE)) {
    ...
    return 1;
}

// Initialize security
hres = CoInitializeSecurity(...);
if (FAILED(hres) && (hres != RPC_E_TOO_LATE)) {
    ...
    if (doCoUninit)
        CoUninitialize();
    return 1;
}

...

if (doCoUninit)
    CoUninitialize(); 
...

Upvotes: 1

Related Questions