Calling a Provider Method

A provider method is a method that is implemented by a Windows Management Instrumentation (WMI) provider. The method is found in a class defined by a provider to represent data from software or hardware. For example, the Win32_Service class has methods to start, stop, resume, pause, and change services.

Provider methods should not be confused with the following types of methods:

Calling a Provider Method Using Scripting

Any automation language, such as VBScript, PowerShell, or Perl, can call a WMI method. Some languages can use direct access, but others must use SWbemServices.ExecMethod to execute the provider method indirectly.

The following procedure describes how to call a provider method using the Scripting API and using direct access.

To call a provider method using the Scripting API and direct access

  1. Use this approach for VBScript or PowerShell.

  2. Determine if the method you want to execute is implemented.

    Some classes have methods defined that are not supported by a provider. If a method is not implemented, you cannot execute it. You can determine if a method is implemented by checking if the method has the Implemented qualifier. For more information, see WMI Qualifiers and Accessing a WMI Qualifier. You can also determine if a provider class method has the Implemented qualifier set by running the unsupported Wbemtest.exe utility, available on any operating system with WMI installed.

  3. Determine if the method you want to execute is a static method or a nonstatic method.

    Static methods apply only to WMI classes and not to specific instances of a class. For example, the Create method of the Win32_Process class is a static method because use it to create a new process without an instance of this class. Nonstatic methods apply only to instances of a class. For example, the Terminate method of the Win32_Process class is a nonstatic method because it only makes sense to terminate a process if an instance of that process exists. You can determine if a method is static by checking if the Static qualifier is associated with the method.

  4. Retrieve the class or instance that contains the method you want to execute.

    For more information, see Retrieving WMI Class or Instance Data.

  5. Set up any security settings that the method may require.

    You can often determine the privileges that a method requires by examining the values in the Privileges qualifier of the method. For example, the Win32_OperatingSystem class Shutdown method requires you to set the "SeShutdownPrivilege" privilege. For more information, see Executing Privileged Operations.

  6. Call the method and examine the return value to determine if the method was successful.

The following code example creates a Notepad process and gets the process ID using direct access.

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer _
    & "\root\cimv2:Win32_Process")

Error = objWMIService.Create("notepad.exe", null, _
    null, intProcessID)
If Error = 0 Then
    Wscript.Echo "Notepad was started with a process ID of " _
       & intProcessID & "."
Else
    Wscript.Echo "Notepad could not be started due to error " _
       & Error & "."
End If  

try
{ 
    $myProcess = ([wmiclass]"win32_process").create("notepad.exe", $null, $null) 
}
catch 
{
    "Notepad could not be started due to the following error:" 
    $error[0]
    return 
}
#else
"Notepad was started with a process ID of " + $myProcess.ProcessID

The following procedure describes how to call a provider method using the Scripting API and the SWbemServices.ExecMethod.

To call a provider method using the Scripting API and SWbemServices.ExecMethod

  1. Retrieve the WMI class definition to execute a static method. Retrieve the WMI class instance to execute a nonstatic method.
  2. Retrieve the method to execute from the SWbemObject.Methods_ collection of your class or instance by using the SWbemObjectSet.Item method.
  3. Obtain an InParameters object for the method and set up the parameters as described in Constructing InParameters Objects.
  4. Call the SWbemServices.ExecMethod method to execute and assign the return value to an SWbemObject object to store the output parameters.
  5. Check the values in the output parameters object to verify that the method executed correctly.

The following VBScript code example performs the same operation as the previous script by the indirect approach through calling SWBemServices.ExecMethod.

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer _
    & "\root\cimv2")

Set objProcess = objWMIService.Get("Win32_Process")

' Obtain an InParameters object specific to 
'   the Win32_Process.Create method.
Set objInParam = _
    objProcess.Methods_("Create").inParameters.SpawnInstance_()

' Add the input parameters. 
objInParam.Properties_.item("CommandLine") = "Notepad"
objInParam.Properties_.item("CurrentDirectory") = NULL
objInParam.Properties_.item("ProcessStartupInformation") = NULL


Set objOutParams = objProcess.ExecMethod_("Create", objInParam) 
If Error = 0 Then
    Wscript.Echo "Notepad was started with a process ID of " _
       & objOutParams.ProcessId 
Else
    Wscript.Echo "Notepad could not be started due to error " & _
       objOutParams.ReturnValue
End If

The following procedure describes how to call a provider method using C++.

To call a provider method using C++

  1. Connect to WMI.

    To call a method in WMI, first you must have a working connection to a WMI namespace. For more information, see Creating a WMI Application Using C++ and Initializing COM for a WMI Application.

    The following example shows how to connect to WMI. For more information about security issues in WMI provider calls, see Maintaining WMI Security.

    HRESULT hr = CoInitialize(0);
        hr  =  CoInitializeSecurity(
                NULL, 
                -1, 
                NULL, 
                NULL,
                RPC_C_AUTHN_LEVEL_DEFAULT, 
                RPC_C_IMP_LEVEL_IMPERSONATE, 
                NULL, 
                EOAC_NONE, 
                NULL); 
        hr = CoCreateInstance(CLSID_WbemLocator, 0, 
                CLSCTX_INPROC_SERVER,
                IID_IWbemLocator, (LPVOID *) &pLocator);
        hr = pLocator->ConnectServer(path, NULL, NULL, 
                NULL, 0, NULL, NULL, &pNamespace);
  1. Call IWbemServices::GetObject to retrieve the definition of the class of the method you want to call.

    The GetObject method returns an IWbemClassObject pointer that points to the class definition.

    hr = pNamespace->GetObject(ClassPath, 0, NULL, &pClass, NULL);
  1. For methods that require input parameters, call the IWbemClassObject::GetMethod method to get the input parameter class object.

    GetMethod returns an IWbemClassObject pointer that points to the input parameter class.

    hr = pClass->GetMethod(MethodName, 0, &pInClass, NULL);
  1. Generate an instance of the input parameter class with a call to the IWbemClassObject::SpawnInstance method.
    hr = pInClass->SpawnInstance(0, &pInInst);
  1. Set the properties of the input parameter class with a call to the IWbemClassObject::Put method.
    VARIANT var;
    var.vt = VT_BSTR;
    var.bstrVal= SysAllocString(L"hello");
    hr = pInInst->Put(ArgName, 0, &var, 0);
    VariantClear(&var);
  1. Invoke the method with a call to IWbemServices::ExecMethod or IWbemServices::ExecMethodAsync.

    For ExecMethod, WMI returns any output parameters in the call. For ExecMethodAsync, WMI returns any output parameters through a call to IWbemObjectSink. For more information, see Calling a Method.

    hr = pNamespace->ExecMethod(ClassPath, MethodName, 0, NULL, pInInst, &pOutInst, NULL);

The following code is a complete example for calling a provider method.

#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")

int main(int iArgCnt, char ** argv)
{
    IWbemLocator *pLocator = NULL;
    IWbemServices *pNamespace = 0;
    IWbemClassObject * pClass = NULL;
    IWbemClassObject * pOutInst = NULL;
    IWbemClassObject * pInClass = NULL;
    IWbemClassObject * pInInst = NULL;
  
    BSTR path = SysAllocString(L"root\\default");
    BSTR ClassPath = SysAllocString(L"TestMeth");
    BSTR MethodName = SysAllocString(L"Echo");
    BSTR ArgName = SysAllocString(L"sInArg");
    BSTR Text;

    // Initialize COM and connect to WMI.

    HRESULT hr = CoInitialize(0);
    hr  =  CoInitializeSecurity(NULL, -1, NULL, NULL,RPC_C_AUTHN_LEVEL_DEFAULT, 
                                RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); 
    hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
                          IID_IWbemLocator, (LPVOID *) &pLocator);
    hr = pLocator->ConnectServer(path, NULL, NULL, NULL, 0, NULL, NULL, &pNamespace);

    // Get the class object for the method definition.

    hr = pNamespace->GetObject(ClassPath, 0, NULL, &pClass, NULL);

    // Get the input-argument class object and 
    // create an instance.

    hr = pClass->GetMethod(MethodName, 0, &pInClass, NULL); 
    hr = pInClass->SpawnInstance(0, &pInInst);

    // Set the property.

    VARIANT var;
    var.vt = VT_BSTR;
    var.bstrVal= SysAllocString(L"hello");
    hr = pInInst->Put(ArgName, 0, &var, 0);
    VariantClear(&var);

    // Call the method.

    hr = pNamespace->ExecMethod(ClassPath, MethodName, 0, NULL, pInInst, &pOutInst, NULL);
    
    // Display the results. Note that the return 
    // value is in the property "ReturnValue"
    // and the returned string is in the 
    // property "sOutArg".

    hr = pOutInst->GetObjectText(0, &Text);
    printf("\nThe object text is:\n%S", Text);

    // Free up resources.

    SysFreeString(path);
    SysFreeString(ClassPath);
    SysFreeString(MethodName);
    SysFreeString(ArgName);
    SysFreeString(Text);
    pClass->Release();
    pInInst->Release();
    pInClass->Release();
    pOutInst->Release();
    pLocator->Release();
    pNamespace->Release();
    CoUninitialize();
    printf("Terminating normally\n");
    return 0;
}

Calling a Method