This code is based off a DirectX SDK sample (getting video RAM), but was rewritten by myself rather than just being a copy and paste job. While doing that, I reworked it to be a little bit more generally useful.
It's not an all-purpose WMI query engine, but is eminently suitable for simple queries that return single values.
So let's dive in.
First thing I did was declare these useful macros in quakedef.h, as a lot of WMI storage info is returned in bytes:
Code: Select all
#define BYTES_TO_MEGS(b) ((b) / 1048576)
#define K_TO_MEGS(b) ((b) / 1024)
#define BYTES_TO_K(b) ((b) / 1024)
Code: Select all
#include <wbemidl.h>
class WMIQuery
{
public:
WMIQuery (void);
VARIANT ExecQuery (const BSTR WMIClassName, const BSTR WMIPropName);
~WMIQuery (void);
private:
IWbemLocator *pIWbemLocator;
IWbemServices *pIWbemServices;
HRESULT hrCoInitialize;
BSTR pNameSpace;
};
Code: Select all
#include "quakedef.h"
#pragma comment (lib, "wbemuuid.lib")
typedef BOOL (WINAPI *PfnCoSetProxyBlanket)
(
IUnknown *pProxy,
DWORD dwAuthnSvc,
DWORD dwAuthzSvc,
OLECHAR *pServerPrincName,
DWORD dwAuthnLevel,
DWORD dwImpLevel,
RPC_AUTH_IDENTITY_HANDLE pAuthInfo,
DWORD dwCapabilities
);
WMIQuery::WMIQuery (void)
{
// safe defaults
this->pIWbemLocator = NULL;
this->pIWbemServices = NULL;
// result handle for setup
HRESULT hr;
// attempt to initialize COM - if this fails, we assume that COM has already been initialized
// elsewhere rather than that anything dramatic or bad happened - it's 2008 and we don't
// really expect something as basic as COM initialization to fail any more...
this->hrCoInitialize = CoInitialize (NULL);
// connect to default namespace on local computer
this->pNameSpace = SysAllocString (L"\\\\.\\root\\cimv2");
// create a locator instance
hr = CoCreateInstance (CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &this->pIWbemLocator);
// WMI not working or something else bad happened
if (FAILED (hr) || !this->pIWbemLocator) return;
// connect to the COM server
hr = pIWbemLocator->ConnectServer (this->pNameSpace, NULL, NULL, 0L, 0L, NULL, NULL, &this->pIWbemServices);
// WMI not working or something else bad happened
if (FAILED (hr) || !this->pIWbemServices) return;
// load ole32.dll - calling CoSetProxyBlanket is broken in the API, as is creating an IID_IClientSecurity thingie, so instead
// we load the dll, GetProcAddress on it, and do it this way - ugleeeeeee!
HINSTANCE hInstOle32 = LoadLibrary ("ole32.dll");
if (!hInstOle32) return;
// set up the client security proxy now
PfnCoSetProxyBlanket pfnCoSetProxyBlanket = (PfnCoSetProxyBlanket) GetProcAddress (hInstOle32, "CoSetProxyBlanket");
if (pfnCoSetProxyBlanket)
{
pfnCoSetProxyBlanket
(
this->pIWbemServices,
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_NONE,
NULL,
RPC_C_AUTHN_LEVEL_CALL,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
0
);
}
FreeLibrary (hInstOle32);
}
VARIANT WMIQuery::ExecQuery (const BSTR WMIClassName, const BSTR WMIPropName)
{
VARIANT var;
var.intVal = -1;
// something went wrong...
if (!this->pNameSpace) return var;
if (!this->pIWbemLocator) return var;
if (!this->pIWbemServices) return var;
// initial setup
IEnumWbemClassObject *pIEnumWbemClassObject = NULL;
// create an enumerator for this class instance
HRESULT hr = this->pIWbemServices->CreateInstanceEnum (WMIClassName, 0, NULL, &pIEnumWbemClassObject);
// make sure it worked
if (SUCCEEDED (hr) && pIEnumWbemClassObject)
{
// alloc space for 10 object pointers
IWbemClassObject *pIWbemClassObject[10] = {NULL};
DWORD uReturned = 0;
// get the first 10 (or less if there are less) instances of this class object
pIEnumWbemClassObject->Reset ();
hr = pIEnumWbemClassObject->Next (5000, 10, pIWbemClassObject, &uReturned);
// did we get them?
if (SUCCEEDED (hr))
{
// yes
for (UINT uClassObj = 0; uClassObj < uReturned; uClassObj++)
{
// clear down the variant
VariantClear (&var);
// get the memory and release the object
hr = pIWbemClassObject[uClassObj]->Get (WMIPropName, 0L, &var, NULL, NULL);
pIWbemClassObject[uClassObj]->Release ();
}
}
// clean up
pIEnumWbemClassObject->Release ();
}
return var;
}
WMIQuery::~WMIQuery (void)
{
// release COM objects
if (this->pIWbemServices) this->pIWbemServices->Release ();
if (this->pIWbemLocator) this->pIWbemLocator->Release ();
// release the namespace string
if (this->pNameSpace) SysFreeString (pNameSpace);
// if COM initialized in here we must uninitialize it to maintain integrity
if (SUCCEEDED (this->hrCoInitialize)) CoUninitialize ();
}
Code: Select all
void GetAdapterRAM (void)
{
WMIQuery *TheWMI = new WMIQuery ();
int NumCPUs = TheWMI->ExecQuery (L"Win32_ComputerSystem", L"NumberOfProcessors").intVal;
int AdapterRAM = BYTES_TO_MEGS ((TheWMI->ExecQuery (L"Win32_VideoController", L"AdapterRAM")).intVal);
int CPUSpeed = (TheWMI->ExecQuery (L"Win32_Processor", L"MaxClockSpeed")).intVal;
delete TheWMI;
}