调用提供程序方法

提供程序方法是由 Windows Management Instrumentation (WMI) 提供程序实现的方法。 该方法位于提供程序定义的类中,用于表示来自软件或硬件的数据。 例如,Win32_Service 类具有启动、停止、继续、暂停和更改服务的方法。

提供程序方法不应与以下类型的方法混淆:

使用脚本调用提供程序方法

VBScript、PowerShell 或 Perl 等任何自动化语言都可以调用 WMI 方法。 部分语言可以使用直接访问,但其他语言必须使用 SWbemServices.ExecMethod 间接执行提供程序方法。

以下过程介绍如何使用脚本 API 和直接访问调用提供程序方法。

若要使用脚本 API 和直接访问调用提供程序方法

  1. 将此方法用于 VBScript 或 PowerShell。

  2. 确定是否实现了想执行的方法。

    某些类定义了提供程序不支持的方法。 如果未实现方法,则无法执行该方法。 可以通过检查方法是否具有 Implemented 限定符来确定方法是否实现。 有关详细信息,请参阅 WMI 限定符访问 WMI 限定符。 还可以通过运行不受支持的 Wbemtest.exe 实用工具(该实用工具在安装了 WMI 的任何操作系统上都可用)来确定提供程序类方法是否设置 Implemented 限定符。

  3. 确定要执行的方法是静态方法还是非静态方法。

    静态方法仅适用于 WMI 类,不适用于类的特定实例。 例如,Win32_Process 类的 Create 方法是静态方法,因为它用于创建没有此类实例的新进程。 非静态方法仅适用于类的实例。 例如,Win32_Process 类的 Terminate 方法是非静态方法,因为只有当进程实例存在时终止进程才有意义。 可以通过检查 Static 限定符是否与方法关联来确定方法是否为静态。

  4. 检索包含要执行的方法的类或实例。

    有关详细信息,请参阅检索 WMI 类或实例数据

  5. 设置方法可能需要的任何安全设置。

    通常可以通过检查方法的 Privileges 限定符中的值来确定方法所需的特权。 例如,Win32_OperatingSystemShutdown 方法要求设置“SeShutdownPrivilege”特权。 有关详细信息,请参阅执行特权操作

  6. 调用方法并检查返回值以确定方法是否成功。

以下代码示例创建一个记事本进程,并使用直接访问获取进程 ID。

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

以下过程介绍如何使用脚本 API 和 SWbemServices.ExecMethod 调用提供程序方法。

若要使用脚本 API 和 SWbemServices.ExecMethod 调用提供程序方法

  1. 检索 WMI 类定义以执行静态方法。 检索 WMI 类实例以执行非静态方法。
  2. 使用 SWbemObjectSet.Item 方法从类或实例的 SWbemObject.Methods_ 集合中检索要执行的方法。
  3. 获取方法的 InParameters 对象,并按照构造 InParameters 对象中所述设置参数。
  4. 调用 SWbemServices.ExecMethod 方法执行并将返回值分配给 SWbemObject 对象以存储输出参数。
  5. 检查输出参数对象中的值,验证方法是否正确执行。

以下 VBScript 代码示例通过调用 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

以下过程介绍如何使用 C++ 调用提供程序方法。

若要使用 C++ 调用提供程序方法

  1. 连接到 WMI。

    若要在 WMI 中调用方法,首先必须与 WMI 命名空间建立有效连接。 有关详细信息,请参阅使用 C++ 创建 WMI 应用程序为 WMI 应用程序初始化 COM

    以下示例演示如何连接到 WMI。 有关 WMI 提供程序调用中安全问题的详细信息,请参阅维护 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);
  1. 调用 IWbemServices::GetObject 以检索要调用的方法的类定义。

    GetObject方法返回一个指向类定义的 IWbemClassObject 指针。

    hr = pNamespace->GetObject(ClassPath, 0, NULL, &pClass, NULL);
  1. 对于需要输入参数的方法,请调用 IWbemClassObject::GetMethod 方法以获取输入参数类对象。

    GetMethod 返回一个指向输入参数类的 IWbemClassObject 指针。

    hr = pClass->GetMethod(MethodName, 0, &pInClass, NULL);
  1. 通过调用 IWbemClassObject::SpawnInstance 方法生成输入参数类的实例。
    hr = pInClass->SpawnInstance(0, &pInInst);
  1. 通过调用 IWbemClassObject::Put 方法设置输入参数类的属性。
    VARIANT var;
    var.vt = VT_BSTR;
    var.bstrVal= SysAllocString(L"hello");
    hr = pInInst->Put(ArgName, 0, &var, 0);
    VariantClear(&var);
  1. 通过调用 IWbemServices::ExecMethodIWbemServices::ExecMethodAsync 调用该方法。

    对于 ExecMethod,WMI 返回调用中的任何输出参数。 对于 ExecMethodAsync,WMI 通过调用 IWbemObjectSink 返回任何输出参数。 有关详细信息,请参阅调用方法

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

以下代码是调用提供程序方法的完整示例。

#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;
}

调用方法