It’s pretty rare that I wind up using WMI from a C++ application, but when I’ve done so in the past, it’s been a straightforward process. The documentation in MSDN is generally adequate, and their example projects tend to lead me in the right direction. However, I was helping a friend out with a side project and I needed to call an instance method of a WMI object. It turns out that MSDN’s documentation on the subject is sorely lacking, and their example product is misleading. They focus only on the easiest possible case — how to call a static method on an object.
It turns out that calling an instance method isn’t overly difficult. You just need to know the proper magic incantation to get it to work.
Assuming that you’ve gotten an IWbemClassObject from some form of query, you can ask for the __PATH variable from it. This is the key ingredient the documentation fails to discuss: the __PATH variable is WMI’s version of a “this” pointer. It uniquely identifies a computer, session, object class and object instance. Once you’ve gotten the __PATH variable, you can use that in a call to ExecMethod to execute a method on a specific instance. For example:
// 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 *printer = NULL; IWbemClassObject *params = NULL; IWbemClassObject *paramsInst = NULL; services->GetObject( _bstr_t( L"Win32_Printer" ), 0, NULL, &printer, NULL ); printer->GetMethod( _bstr_t( "RenamePrinter" ), 0, ¶ms, NULL ); params->SpawnInstance( 0, ¶msInst ); // Now that we've got an instance representing the input // parameters, we can fill in the parameter values _bstr_t paramValue( L"New Printer Name Goes Here" ); VARIANT paramVt; paramVt.vt = VT_BSTR; paramVt.bstrVal = paramValue; paramsInst->Put( L"NewPrinterName", 0, ¶mVt, NULL ); // Get the "this" pointer to our object instance so that we // can call the RenamePrinter method on it CIMTYPE type; LONG flavor; VARIANT var; objInstance->Get( L"__PATH", 0, &var, &type, &flavor ); // Execute the RenamePrinter method on our object instance IWbemClassObject *results = NULL; services->ExecMethod( var.bstrVal, _bstr_t( L"RenamePrinter" ), 0, NULL, paramsInst, &results, NULL );
(Obviously, I’ve elided the error checking and cleanup code — you’ll want to add that in to any production code you write.)
Once you’ve seen the solution, it makes sense. However, there was no indication on MSDN that the __PATH variable was what should be passed in as the first parameter to ExecMethod to represent the object. Hopefully this blog posting saves you some time!
tl;dr: the “this” pointer for an object in WMI is represented by the __PATH variable.