Reputation: 19
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
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