공급자 메서드 호출

공급자 메서드는 WMI(Windows Management Instrumentation) 공급자로 구현하는 메서드입니다. 이 메서드는 공급자가 소프트웨어 또는 하드웨어의 데이터를 나타내기 위해 정의한 클래스에 있습니다. 예를 들어 Win32_Service 클래스에는 서비스를 시작, 중지, 다시 시작, 일시 중지 및 변경하는 메서드가 있습니다.

공급자 메서드를 다음 유형의 메서드와 혼동해선 안 됩니다.

Scripting을 사용하여 공급자 메서드 호출

VBScript, PowerShell 또는 Perl을 비롯한 모든 자동화 언어는 WMI 메서드를 호출할 수 있습니다. 직접 액세스를 사용할 수 있는 언어가 아닌 언어는 SWbemServices.ExecMethod를 사용하여 공급자 메서드를 간접적으로 실행해야 합니다.

다음 절차에서는 Scripting API를 사용하여 공급자 메서드를 호출하는 방법과 직접 액세스를 사용하여 호출하는 방법을 설명합니다.

Scripting API 및 직접 액세스를 사용하여 공급자 메서드를 호출하는 방법

  1. VBScript 또는 PowerShell에는 이 방법을 사용합니다.

  2. 실행할 메서드가 구현되었는지 확인합니다.

    공급자가 지원하지 않는 메서드가 정의된 클래스가 있습니다. 구현되지 않은 메서드는 실행할 수 없습니다. 구현된 한정자가 메서드에 있는지 확인하면 메서드 구현 여부를 확인할 수 있습니다. 자세한 내용은 WMI 한정자WMI 한정자 액세스를 참조하세요. WMI가 설치된 모든 운영 체제에서 사용할 수 있는, 지원되지 않는 Wbemtest.exe 유틸리티를 실행하여 공급자 클래스 메서드가 구현된 한정자를 설정했는지 확인할 수도 있습니다.

  3. 실행하려는 메서드가 정적 메서드인지 비정적 메서드인지 확인합니다.

    정적 메서드는 WMI 클래스에만 적용되며 클래스의 특정 인스턴스에는 적용되지 않습니다. 예를 들어 Win32_Process 클래스의 Create 메서드는 이 클래스의 인스턴스 없이 새 프로세스를 만드는 데 사용하기 때문에 정적 메서드입니다. 비정적 메서드는 클래스의 인스턴스에만 적용됩니다. 예를 들어 Win32_Process 클래스의 Terminate 메서드는 해당 프로세스의 인스턴스가 있는 경우에만 프로세스를 종료해야 하기 때문에 비정적 메서드입니다. 정적 한정자가 메서드와 연결되어 있는지 확인하면 메서드가 정적인지 확인할 수 있습니다.

  4. 실행할 메서드가 포함된 클래스나 인스턴스를 검색합니다.

    자세한 내용은 WMI 클래스 또는 인스턴스 데이터 검색을 참조하세요.

  5. 메서드에 필요할 수 있는 보안 설정을 지정합니다.

    대부분의 경우 메서드의 Privileges 한정자에 있는 값을 검사하면 메서드에 필요한 권한을 확인할 수 있습니다. 예를 들어 Win32_OperatingSystem 클래스 Shutdown 메서드를 사용하려면 "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

다음 절차에서는 Scripting API와 SWbemServices.ExecMethod를 사용하여 공급자 메서드를 호출하는 방법을 설명합니다.

Scripting 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::ExecMethod 또는 IWbemServices::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;
}

메서드 호출