I'm not sure why am I getting this strange result. Can someone please shed some light on this?
I'm using WMI calls from a C++ program to export the 'Application' part of the Windows Event Log.
This is done from a local service and the code works fine under Windows 7. The problem happens when I run it on Windows XP. For some weird reason the ExecMethod() of the WMI interface returns HRESULT=0x80041003, which is Access denied.
But if I put the exact same code into a simple user process and run it from there, everything works great. How could that be, the code fails to run from a more privileged local service but works from a simple user process?
PS. I'd appreciate any ideas because I've been working on this for several days to no avail....
PS2. I enabled the following privileges (like if I need to do this for the local service) and that still didn't help:
SE_SECURITY_NAME
SE_BACKUP_NAME
EDIT: I guess adding a sample code wouldn't hurt. (Sorry for the long chunk, but this darn WMI/COM isn't a beauty either....) I marked the spot where I get an error below:
// Initialize COM. ------------------------------------------
hr = CoInitializeEx(0, COINIT_MULTITHREADED);
if(SUCCEEDED(hr))
{
// Set general COM security levels --------------------------
// Note: If you are using Windows 2000, you need to specify -
// the default authentication credentials for a user by using
// a SOLE_AUTHENTICATION_LIST structure in the pAuthList ----
// parameter of CoInitializeSecurity ------------------------
hr = CoInitializeSecurity(
NULL,
-1, // COM authentication
NULL, // Authentication services
NULL, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
NULL, // Authentication info
EOAC_NONE, // Additional capabilities
NULL // Reserved
);
if(SUCCEEDED(hr))
{
// Obtain the initial locator to WMI -------------------------
IWbemLocator *pLoc = NULL;
hr = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *) &pLoc);
if(SUCCEEDED(hr))
{
// Connect to WMI through the IWbemLocator::ConnectServer method
IWbemServices *pSvc = NULL;
// Connect to the root\cimv2 namespace with
// the current user and obtain pointer pSvc
// to make IWbemServices calls.
hr = pLoc->ConnectServer(
_bstr_t(L"\\\\.\\ROOT\\CIMV2"), // Object path of WMI namespace
NULL, // User name. NULL = current user
NULL, // User password. NULL = current
0, // Locale. NULL indicates current
NULL, // Security flags.
0, // Authority (e.g. Kerberos)
0, // Context object
&pSvc // pointer to IWbemServices proxy
);
if(SUCCEEDED(hr))
{
// Set security levels on the proxy -------------------------
hr = 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(SUCCEEDED(hr))
{
// Use the IWbemServices pointer to make requests of WMI ----
// For example, get the name of the operating system
IEnumWbemClassObject* pEnumerator = NULL;
hr = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t("Select * from Win32_NTEventLogFile Where LogFileName='Application'"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator);
if(SUCCEEDED(hr))
{
IWbemClassObject *pclsObj = NULL;
int nCnt = -1;
//Go through all results
while (pEnumerator)
{
ULONG uReturn = 0;
hr = pEnumerator->Next(WBEM_INFINITE, 1,
&pclsObj, &uReturn);
if(0 == uReturn)
{
break;
}
//Go to next iteration
nCnt++;
// Get a reference to the Win32_Printer class so we can find
// the RenamePrinter method. This lets us create an object
// representing the input parameter block to be passed to the
// method when we call it.
IWbemClassObject *pNTEventLogFile = NULL;
IWbemClassObject *params = NULL;
IWbemClassObject *paramsInst = NULL;
hr = pSvc->GetObject( _bstr_t( L"Win32_NTEventLogFile" ), 0, NULL,
&pNTEventLogFile, NULL );
if(SUCCEEDED(hr))
{
hr = pNTEventLogFile->GetMethod( _bstr_t( "BackupEventLog" ), 0, ¶ms,
NULL );
if(SUCCEEDED(hr))
{
hr = params->SpawnInstance( 0, ¶msInst );
if(SUCCEEDED(hr))
{
// Now that we've got an instance representing the input
// parameters, we can fill in the parameter values
_bstr_t paramValue( L"C:\\Users\\UserName\\Documents\\application.evt" );
VARIANT paramVt;
paramVt.vt = VT_BSTR;
paramVt.bstrVal = paramValue;
hr = paramsInst->Put( L"ArchiveFileName", 0, ¶mVt, NULL );
if(SUCCEEDED(hr))
{
// Get the "this" pointer to our object instance so that we
// can call the RenamePrinter method on it
CIMTYPE type;
LONG flavor;
VARIANT var;
hr = pclsObj->Get( L"__PATH", 0, &var, &type, &flavor );
if(SUCCEEDED(hr))
{
// Execute the RenamePrinter method on our object instance
IWbemClassObject *results = NULL;
hr = pSvc->ExecMethod( var.bstrVal, _bstr_t( L"BackupEventLog" ), 0,
NULL, paramsInst, &results, NULL );
**///////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////// THIS IS WHERE hr = 0x80041003 or wbemErrAccessDenied
//////////////////////////////////////////////// only when this code is run from a local service
//////////////////////////////////////////////// on a Windows XP machine, but if I run the exact same
//////////////////////////////////////////////// code from a user process on XP machine, it works!
//////////////////////////////////////////////// Note that this works fine on Windows Vista/7 in any configuration.
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////**
if(SUCCEEDED(hr))
{
//Get result code from the BackupEventLog method
VARIANT vtProp;
hr = results->Get(L"ReturnValue", 0, &vtProp, 0, 0);
if(SUCCEEDED(hr))
{
if(vtProp.vt == VT_I4)
{
//Check
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa384808(v=vs.85).aspx
//0 = Success
//8 = Privilege missing
//21 = Invalid parameter
//80 = Archive file name already exists. This value is returned starting with Windows Vista.
int nResV = vtProp.intVal;
//_tprintf(_T("result2 : %d\n"), nResV);
}
else
{
//Error
}
//Free
VariantClear(&vtProp);
}
else
{
//Error
}
}
else
{
//Error
}
//Free
if(results)
{
results->Release();
results = NULL;
}
//Clear
VariantClear(&var);
}
else
{
//Error
}
//Clear
VariantClear(¶mVt);
}
else
{
//Error
}
}
else
{
//Error
}
}
else
{
//Error
}
}
else
{
//Error
}
//Free
if(pNTEventLogFile)
{
pNTEventLogFile->Release();
pNTEventLogFile = NULL;
}
if(params)
{
params->Release();
params = NULL;
}
if(paramsInst)
{
paramsInst->Release();
paramsInst = NULL;
}
if(pclsObj)
{
pclsObj->Release();
pclsObj = NULL;
}
}
//Free
if(pclsObj)
{
pclsObj->Release();
pclsObj = NULL;
}
}
else
{
//Error
}
//Free
if(pEnumerator)
{
pEnumerator->Release();
pEnumerator = NULL;
}
}
else
{
//Error
}
}
else
{
//Error
}
//Free
if(pSvc)
{
pSvc->Release();
pSvc = NULL;
}
}
else
{
//Error
}
//Free
if(pLoc)
{
pLoc->Release();
pLoc = NULL;
}
}
else
{
//Error
}
//Uninit
CoUninitialize();
}
else
{
//Error
}
I think I got it... For anyone else who doesn't want to waste 3 days looking for an answer here it is: on Windows XP replace RPC_C_IMP_LEVEL_IMPERSONATE with RPC_C_IMP_LEVEL_DELEGATE in the calls to CoInitializeSecurity() and CoSetProxyBlanket(). I don't know what exactly it does, but it makes the code above work! Yay!!!
Related
I am wanting to learn how to get asset tag and serial number from the bios of a local machine using c++. I have been searching online for almost an hour now and all I have come up with so far is a few script written in vb.
I am working on a Windows 7 computer, but would like it to work with Windows 8 as well.
You can use WMI
An example function would be something like the following source which I put together to obtain the serial number for a PC and it seems to work quite nicely. There is a fall back to pull a serial number from the Windows Registry however just ignore that as it is for a specialized environment.
# pragma comment(lib, "wbemuuid.lib")
static SHORT CDeviceConfigCheckSerialNumber (TCHAR *tcsSerialNo)
{
HRESULT hres;
IWbemLocator *pLoc = NULL;
*tcsSerialNo = 0; // initialze return string to empty string
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *) &pLoc);
if (FAILED(hres))
{
return 1; // Program has failed.
}
// Step 4: -----------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
IWbemServices *pSvc = NULL;
// Connect to the root\cimv2 namespace with
// the current user and obtain pointer pSvc
// to make IWbemServices calls.
hres = pLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
NULL, // User name. NULL = current user
NULL, // User password. NULL = current
0, // Locale. NULL indicates current
NULL, // Security flags.
0, // Authority (for example, Kerberos)
0, // Context object
&pSvc // pointer to IWbemServices proxy
);
if (FAILED(hres))
{
pLoc->Release();
return 2; // Program has failed.
}
// Step 5: --------------------------------------------------
// 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();
return 3; // Program has failed.
}
// Step 6: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ----
// For example, get the name of the operating system
IEnumWbemClassObject* pEnumerator = NULL;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
// bstr_t("SELECT * FROM Win32_SystemEnclosure"),
// bstr_t("SELECT * FROM Win32_BaseBoard"),
bstr_t("SELECT * FROM Win32_BIOS"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator);
if (FAILED(hres))
{
pSvc->Release();
pLoc->Release();
return 4; // Program has failed.
}
// Step 7: -------------------------------------------------
// Get the data from the query in step 6 -------------------
IWbemClassObject *pclsObj;
ULONG uReturn = 0;
SHORT sRetStatus = -100;
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"SerialNumber", 0, &vtProp, 0, 0);
if (!FAILED(hres)) {
switch (vtProp.vt) {
case VT_BSTR:
_tcscpy (tcsSerialNo, vtProp.bstrVal);
sRetStatus = 0;
break;
}
}
VariantClear(&vtProp);
pclsObj->Release();
}
pEnumerator->Release();
// Cleanup
// ========
pSvc->Release();
pLoc->Release();
// if the search for a serial number in the BIOS did not provide
// something then lets see if the NCR Retail Systems Manager has
// put a serial number into the Windows Registry.
if (sRetStatus != 0) {
ULONG ulCount = 0;
TCHAR lpszValue[256] = {0};
ScfGetRsmValue (L"SerialNumber", &ulCount, lpszValue);
if (ulCount > 0) {
_tcscpy (tcsSerialNo, lpszValue);
sRetStatus = 0;
}
}
return sRetStatus;
}
I have an old MFC application I need to rebuild.
It includes some code to read the current user's name and company. It accomplishes this by reading directly from the registry.
I really don't think this is a very reliable approach as future versions of Windows may change how and where some of this information is stored. So I would prefer to find an API call for this.
I managed to find the GetUserName function to get the user's name.
But is there any API to get the name of the registered user's company?
The following function is based on code I found in the MSDN article "Example: Getting WMI Data from the Local Computer" found at http://msdn.microsoft.com/en-us/library/aa390423%28v=vs.85%29.aspx.
bool GetRegisteredUserInformation(std::wstring ®isteredUser, std::wstring &organization)
{
// Step 1: --------------------------------------------------
// Initialize COM. ------------------------------------------
HRESULT hResult = ::CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hResult))
{
return false;
}
// Step 2: --------------------------------------------------
// Set general COM security levels --------------------------
hResult = CoInitializeSecurity(
nullptr, -1, nullptr, nullptr, RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE, nullptr);
if (FAILED(hResult))
{
::CoUninitialize();
return false;
}
// Step 3: ---------------------------------------------------
// Obtain the initial locator to WMI -------------------------
IWbemLocator *pLoc = nullptr;
hResult = CoCreateInstance(
CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *)&pLoc);
if (FAILED(hResult))
{
::CoUninitialize();
return false;
}
// Step 4: -----------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
IWbemServices *pSvc = nullptr;
// Connect to the root\cimv2 namespace with
// the current user and obtain pointer pSvc
// to make IWbemServices calls.
hResult = pLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"), nullptr, nullptr, 0, 0, 0, 0, &pSvc);
if (FAILED(hResult))
{
pLoc->Release();
::CoUninitialize();
return false;
}
// Step 5: --------------------------------------------------
// Set security levels on the proxy -------------------------
hResult = CoSetProxyBlanket(
pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr,
RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE);
if (FAILED(hResult))
{
pSvc->Release();
pLoc->Release();
::CoUninitialize();
return false;
}
// Step 6: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ----
// For example, get the name of the operating system
IEnumWbemClassObject *pEnumerator = nullptr;
hResult = pSvc->ExecQuery(
bstr_t("WQL"), bstr_t("SELECT * FROM Win32_OperatingSystem"),
WBEM_FLAG_FORWARD_ONLY|WBEM_FLAG_RETURN_IMMEDIATELY,
nullptr, &pEnumerator);
if (FAILED(hResult))
{
pSvc->Release();
pLoc->Release();
::CoUninitialize();
return false;
}
// Step 7: -------------------------------------------------
// Get the data from the query in step 6 -------------------
IWbemClassObject *pclsObj;
ULONG uReturn = 0;
while (pEnumerator)
{
hResult = pEnumerator->Next(
WBEM_INFINITE, 1, &pclsObj, &uReturn);
if (0 == uReturn)
{
break;
}
VARIANT vtProp;
hResult = pclsObj->Get(L"RegisteredUser", 0, &vtProp, 0, 0);
if (SUCCEEDED(hResult) && VT_BSTR == vtProp.vt)
{
registeredUser = vtProp.bstrVal;
}
VariantClear(&vtProp);
hResult = pclsObj->Get(L"Organization", 0, &vtProp, 0, 0);
if (SUCCEEDED(hResult) && VT_BSTR == vtProp.vt)
{
organization = vtProp.bstrVal;
}
VariantClear(&vtProp);
pclsObj->Release();
}
// Cleanup
// ========
pSvc->Release();
pLoc->Release();
pEnumerator->Release();
::CoUninitialize();
if (!registeredUser.empty() || !organization.empty())
{
return true;
}
return false;
}
I need to get all processes for current user. Currently I have a function implemented using WMI that gets all active processes by All Users. I need to somehow get all processes by Current User.
If you go to Task Manager in Windows, Details tab, you will see all processes by All Users. But say you are in Visual Studio and you go to Debug/Attach To Process, this shows all processes by Current User. That's the list that I need.
Here is my solution of All Processes by All Users:
CComPtr<IEnumWbemClassObject> pEnumerator;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t("SELECT * FROM Win32_Process"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator);
Either a WMI or Win32 solution will be good enough. Thank you!!
OK, there is now short way. But here is the working solution if anyone is interested:
std::wstring GetProcessUserName(DWORD dwProcessId)
{
HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcessId);
if (processHandle != NULL)
{
HANDLE tokenHandle;
if (OpenProcessToken(processHandle, TOKEN_READ, &tokenHandle))
{
TOKEN_USER tokenUser;
ZeroMemory(&tokenUser, sizeof(TOKEN_USER));
DWORD tokenUserLength = 0;
PTOKEN_USER pTokenUser;
GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS::TokenUser, NULL,
0, &tokenUserLength);
pTokenUser = (PTOKEN_USER) new BYTE[tokenUserLength];
if (GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS::TokenUser, pTokenUser, tokenUserLength, &tokenUserLength))
{
TCHAR szUserName[_MAX_PATH];
DWORD dwUserNameLength = _MAX_PATH;
TCHAR szDomainName[_MAX_PATH];
DWORD dwDomainNameLength = _MAX_PATH;
SID_NAME_USE sidNameUse;
LookupAccountSid(NULL, pTokenUser->User.Sid, szUserName, &dwUserNameLength, szDomainName, &dwDomainNameLength, &sidNameUse);
delete pTokenUser;
return std::wstring(szUserName);
}
}
}
return std::wstring();
}
std::unordered_map<std::wstring, std::vector<DWORD>> GetAllRunningProcessesForCurrentUser()
{
std::unordered_map<std::wstring, std::vector<DWORD>> processHash;
HRESULT hres;
// Initialize COM. ------------------------------------------
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
return processHash;
}
do {
// Obtain the initial locator to WMI -------------------------
CComPtr<IWbemLocator> pLoc;
hres = pLoc.CoCreateInstance(CLSID_WbemLocator);
if (FAILED(hres))
{
break;
}
// Connect to WMI through the IWbemLocator::ConnectServer method
// Connect to the root\cimv2 namespace with
// the current user and obtain pointer pSvc
// to make IWbemServices calls.
CComPtr<IWbemServices> pSvc;
hres = pLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
NULL, // User name. NULL = current user
NULL, // User password. NULL = current
0, // Locale. NULL indicates current
NULL, // Security flags.
0, // Authority (for example, Kerberos)
0, // Context object
&pSvc // pointer to IWbemServices proxy
);
if (FAILED(hres))
{
break;
}
// 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))
{
break;
}
// Use the IWbemServices pointer to make requests of WMI ----
CComPtr<IEnumWbemClassObject> pEnumerator;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t("SELECT * FROM Win32_Process"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator);
if (FAILED(hres))
{
break;
}
// Get the data from the query in step 6 -------------------
CComPtr<IWbemClassObject> pclsObj;
while (pEnumerator)
{
ULONG uReturn = 0;
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
if (0 == uReturn)
{
break;
}
VARIANT vtProp;
VARIANT vtProp2;
hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);
hr = pclsObj->Get(L"ProcessId", 0, &vtProp2, NULL, NULL);
auto userName = GetProcessUserName(vtProp2.intVal);
TCHAR szActiveUserName[_MAX_PATH];
DWORD dwActiveUserNameLength = _MAX_PATH;
GetUserName(szActiveUserName, &dwActiveUserNameLength);
if (_tcscmp(userName.c_str(), szActiveUserName) == 0)
{
processHash[vtProp.bstrVal].push_back(vtProp2.intVal);
}
VariantClear(&vtProp2);
VariantClear(&vtProp);
pclsObj.Release();
}
} while (false);
CoUninitialize();
return processHash;
}
I've written some code to initialise COM and enumerate the network adapters attached to the PC by querying the Win32_NetworkAdapter class using WMI. The reason I need to use WMI is that the adapter I need to enumerate is disabled at the time but I still need to find out its InterfaceIndex, and using GetInterfaceInfo only detects enabled adapters. It all compiles and runs but at the line:
hr = pEnumerator->Next(WBEM_INFINITE, 1, &pClassObj, &ulReturnVal);
which is meant to retrieve the very first adapter, it returns no devices and a garbage HRESULT. I used the example on this page as my guidance.
CoInitialize(NULL); // Initialize COM
HRESULT hr = NULL;
hr = CoInitializeSecurity(
NULL, // security descriptor
-1, // use this simple setting
NULL, // use this simple setting
NULL, // reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // authentication level
RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level
NULL, // use this simple setting
EOAC_NONE, // no special capabilities
NULL); // reserved
if (FAILED(hr))
{
CoUninitialize();
return -1;
}
IWbemLocator *pLoc = 0;
hr = CoCreateInstance(CLSID_WbemLocator, 0,
CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc);
if (FAILED(hr))
{
CoUninitialize();
return -1; // Program has failed.
}
IWbemServices *pSvc = 0;
// Connect to the root\default namespace with the current user.
hr = pLoc->ConnectServer( _bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &pSvc);
if (FAILED(hr))
{
pLoc->Release();
CoUninitialize();
return -1; // Program has failed.
}
hr = CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL,
RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
if (FAILED(hr))
{
pSvc->Release();
pLoc->Release();
CoUninitialize();
return -1; // Program has failed.
}
IEnumWbemClassObject* pEnumerator = NULL;
hr = pSvc->ExecQuery(bstr_t("WQL"), bstr_t("SELECT * FROM Win32_NetworkAdapter"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
if (FAILED(hr))
{
pSvc->Release();
pLoc->Release();
CoUninitialize();
return -1;
}
IWbemClassObject *pClassObj;
ULONG ulReturnVal;
while ( pEnumerator )
{
hr = pEnumerator->Next(WBEM_INFINITE, 1, &pClassObj, &ulReturnVal);
// code would go here to obtain the adapter properties.
pClassObj->Release();
}
return -1;
The correction/solution was to use the RPC_C_IMP_LEVEL_DELEGATE parameter with CoInitializeSecurity and CoSetProxyBlanket rather than RPC_C_IMP_LEVEL_IMPERSONATE.
I am writing my own C++ code to read the computer model and manufacturer on a Windows computer by reading and parsing the registry key
HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/services/mssmbios/Data/SMBiosData
Is there any library function in Windows / C++ / Visual Studio that allows me to get this information directly?
The steps you need are explained on Creating a WMI Application Using C++. MSDN even includes a sample program. You just need to change two strings.
Change SELECT * FROM Win32_Process to SELECT * FROM Win32_ComputerSystem
Change Name to Manufacturer and then again for Model.
With the help of the Microsoft example code, I was able to create this method.
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
std::pair<CString,CString> getComputerManufacturerAndModel() {
// Obtain the initial locator to Windows Management on a particular host computer.
IWbemLocator *locator = nullptr;
IWbemServices *services = nullptr;
auto hResult = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)&locator);
auto hasFailed = [&hResult]() {
if (FAILED(hResult)) {
auto error = _com_error(hResult);
TRACE(error.ErrorMessage());
TRACE(error.Description().Detach());
return true;
}
return false;
};
auto getValue = [&hResult, &hasFailed](IWbemClassObject *classObject, LPCWSTR property) {
CString propertyValueText = "Not set";
VARIANT propertyValue;
hResult = classObject->Get(property, 0, &propertyValue, 0, 0);
if (!hasFailed()) {
if ((propertyValue.vt == VT_NULL) || (propertyValue.vt == VT_EMPTY)) {
} else if (propertyValue.vt & VT_ARRAY) {
propertyValueText = "Unknown"; //Array types not supported
} else {
propertyValueText = propertyValue.bstrVal;
}
}
VariantClear(&propertyValue);
return propertyValueText;
};
CString manufacturer = "Not set";
CString model = "Not set";
if (!hasFailed()) {
// Connect to the root\cimv2 namespace with the current user and obtain pointer pSvc to make IWbemServices calls.
hResult = locator->ConnectServer(L"ROOT\\CIMV2", nullptr, nullptr, 0, NULL, 0, 0, &services);
if (!hasFailed()) {
// Set the IWbemServices proxy so that impersonation of the user (client) occurs.
hResult = CoSetProxyBlanket(services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr, RPC_C_AUTHN_LEVEL_CALL,
RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE);
if (!hasFailed()) {
IEnumWbemClassObject* classObjectEnumerator = nullptr;
hResult = services->ExecQuery(L"WQL", L"SELECT * FROM Win32_ComputerSystem", WBEM_FLAG_FORWARD_ONLY |
WBEM_FLAG_RETURN_IMMEDIATELY, nullptr, &classObjectEnumerator);
if (!hasFailed()) {
IWbemClassObject *classObject;
ULONG uReturn = 0;
hResult = classObjectEnumerator->Next(WBEM_INFINITE, 1, &classObject, &uReturn);
if (uReturn != 0) {
manufacturer = getValue(classObject, (LPCWSTR)L"Manufacturer");
model = getValue(classObject, (LPCWSTR)L"Model");
}
classObject->Release();
}
classObjectEnumerator->Release();
}
}
}
if (locator) {
locator->Release();
}
if (services) {
services->Release();
}
CoUninitialize();
return { manufacturer, model };
}