当我尝试使用 WMI 获取计算机的用户名时遇到错误:
错误:在编组或解组任何接口之前必须初始化安全性。一旦初始化就无法更改。
当我颠倒
CoInitialize()
和 CoInitializeSecurity()
之间的顺序时,出现此错误:
错误:CoInitialize尚未被调用。
代码如下:
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();
发生什么事了?
CoInitializeSecurity()
。如果它已经被调用线程调用,它将返回 RPC_E_TOO_LATE
。虽然这是一个错误条件(FAILED()
将返回 true),但它不是一个fatal条件,但你将其视为是。在这种情况下,处理 RPC_E_TOO_LATE
时,您应该忽略 CoInitializeSecurity()
。
与
RPC_E_CHANGED_MODE
上的CoInitialize()
相同。