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

C++使用WMI获取用户名时遭遇COM初始化顺序错误

C++中使用WMI获取用户名时的COM初始化错误问题

我在C++中尝试使用WMI获取计算机用户名时遇到了错误:

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

当调换CoInitialize()与CoInitializeSecurity()的调用顺序后,又出现如下错误:

Error: CoInitialize has not been called.

相关代码如下:

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(); 

请问这是什么原因?


问题原因及解决办法

这两个错误的核心是COM安全初始化的时机规则:

  • 第一个错误:调用CoInitialize()后,COM会自动为当前线程初始化默认安全设置,之后再手动调用CoInitializeSecurity()就会触发错误——因为COM安全设置一旦初始化(自动或手动)就无法修改。
  • 第二个错误:CoInitializeSecurity()必须在单线程单元(STA)上下文调用,调用前必须先完成线程的COM初始化(CoInitialize()或CoInitializeEx()),直接调用会导致COM上下文未就绪。

正确处理方式

  1. 严格控制初始化顺序:先调用CoInitializeEx()(推荐,明确指定STA模式)或CoInitialize(),立即调用CoInitializeSecurity(),中间不能有任何其他COM操作(比如CoCreateInstance()),否则COM会自动初始化安全设置,导致后续手动调用失败。
  2. 忽略特定错误:CoInitializeSecurity()返回RPC_E_TOO_LATE时,说明COM已自动初始化安全设置,可忽略该错误继续执行。
  3. 修正字符串转义:代码中L"ROOT\CIMv2"的反斜杠需转义为L"ROOT\\CIMv2",否则会被解析为转义字符导致WMI连接失败。

修正后的关键代码片段

// 初始化COM,明确指定STA模式
HRESULT hres = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (FAILED(hres)) {
    // 错误处理逻辑...
    return 1;
}

// 立即初始化安全,忽略RPC_E_TOO_LATE错误
hres = CoInitializeSecurity(
    NULL,
    -1,
    NULL,
    NULL,
    RPC_C_AUTHN_LEVEL_DEFAULT,
    RPC_C_IMP_LEVEL_IMPERSONATE,
    NULL,
    EOAC_NONE,
    NULL);
if (FAILED(hres) && hres != RPC_E_TOO_LATE) {
    // 错误处理逻辑...
    CoUninitialize();
    return 1;
}

// 后续执行CoCreateInstance等COM操作
IWbemLocator* pLoc = NULL;
hres = CoCreateInstance(
    CLSID_WbemLocator,
    0,
    CLSCTX_INPROC_SERVER,
    IID_IWbemLocator,
    (LPVOID*)&pLoc);
// ...其余逻辑

内容的提问来源于stack exchange,提问作者Miranda Qi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 08:25:30