비동기 이벤트 알림 받기

비동기 이벤트 알림은 애플리케이션이 시스템 리소스를 독점하지 않고 이벤트를 지속적으로 모니터링할 수 있는 기술입니다. 비동기 이벤트 알림에는 다른 비동기 호출과 동일한 보안 제한이 있습니다. 대신 반동기 호출을 수행할 수 있습니다. 자세한 내용은 메서드 호출을 참조하세요.

클라이언트로 라우팅되는 비동기 이벤트의 큐는 매우 커질 가능성이 있습니다. 따라서 WMI는 메모리 부족이 발생하지 않도록 시스템 차원의 정책을 구현합니다. WMI는 이벤트를 느리게 하거나 큐가 특정 크기를 초과하면 큐에서 이벤트를 삭제하기 시작합니다.

WMI는 Win32_WMISetting 클래스의 LowThresholdOnEventsHighThresholdOnEvents 속성을 사용하여 메모리 부족 회피에 대한 제한을 설정합니다. 최소값은 WMI가 이벤트 알림 속도를 늦추기 시작해야 하는 경우를 나타내고, 최대값은 이벤트 삭제를 시작할 시기를 나타냅니다. 낮은 임계값과 높은 임계값의 기본값은 1000000(10MB) 및 2000000(20MB)입니다. 또한 이벤트를 삭제하기 전에 WMI가 대기해야 하는 시간을 설명하도록 MaxWaitOnEvents 속성을 설정할 수 있습니다. MaxWaitOnEvents의 기본값은 2000 또는 2초입니다.

VBScript에서 비동기 이벤트 알림 받기

이벤트 알림을 수신하는 스크립팅 호출은 기본적으로 동일한 보안 문제가 있는 모든 비동기 호출과 동일합니다. 자세한 내용은 VBScript를 사용하여 비동기 호출 만들기를 참조하세요.

VBScript에서 비동기 이벤트 알림을 받으려면

  1. WScript.CreateObject를 호출하고 "WbemScripting"의 progid 및 SWbemSink의 개체 형식을 지정하여 싱크 개체를 만듭니다. 싱크 개체가 알림을 받습니다.

  2. 처리하려는 각 이벤트에 대한 서브루틴을 작성합니다. 다음 표에서는 SWbemSink 이벤트를 나열합니다.

    이벤트 의미
    OnObjectReady 개체의 반환을 싱크에 보고합니다. 이 호출을 사용하면 작업이 완료될 때까지 매번 하나의 개체가 반환됩니다.
    Oncompleted 비동기 호출이 완료되면 보고합니다. 이 이벤트는 작업이 무기한인 경우 발생하지 않습니다.
    OnObjectPut 비동기 put 작업의 완료를 보고합니다. 이 이벤트는 인스턴스 또는 저장된 클래스의 개체 경로를 반환합니다.
    OnProgress 진행 중인 비동기 호출의 상태를 보고합니다. 모든 공급자가 중간 진행률 보고서를 지원하지는 않습니다.
    취소 이 개체 싱크와 연결된 미해결 비동기 작업을 모두 취소합니다.

     

다음 VBScript 코드 예제에서는 10초 폴링 간격으로 프로세스 삭제를 알 수 있습니다. 이 스크립트에서 서브루틴 SINK_OnObjectReady 이벤트 발생을 처리합니다. 이 예제에서 싱크 개체의 이름은 "Sink"이지만 원하는 대로 이 개체의 이름을 지정할 수 있습니다.

strComputer = "." 
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2") 
Set MySink = WScript.CreateObject( _
    "WbemScripting.SWbemSink","SINK_")

objWMIservice.ExecNotificationQueryAsync MySink, _
    "SELECT * FROM __InstanceDeletionEvent" _
    & " WITHIN 10 WHERE TargetInstance ISA 'Win32_Process'"


WScript.Echo "Waiting for events..."

While (True)
    Wscript.Sleep(1000)
Wend

Sub SINK_OnObjectReady(objObject, objAsyncContext)
    Wscript.Echo "__InstanceDeletionEvent event has occurred."
End Sub

Sub SINK_OnCompleted(objObject, objAsyncContext)
    WScript.Echo "Event call complete."
End Sub

C++에서 비동기 이벤트 알림 받기

비동기 알림을 수행하려면 WMI(Windows Management Instrumentation)에서 이벤트를 모니터링하고 수신하기 위한 별도의 스레드만 만듭니다. 해당 스레드가 메시지를 받으면 스레드는 주 애플리케이션에 알 줍니다.

별도의 스레드를 헌납하면 이벤트가 도착할 때까지 기다리는 동안 주 프로세스에서 다른 작업을 수행할 수 있습니다. 알림을 비동기식으로 전달하면 성능이 향상되지만 보안이 원하는 것보다 적을 수 있습니다. C++에서는 IWbemUnsecuredApartment 인터페이스를 사용하거나 보안 설명자에 대한 액세스 검사를 수행할 수 있습니다. 자세한 내용은 비동기 호출에서 보안 설정을 참조하세요.

비동기 이벤트 알림을 설정하려면

  1. 비동기 알림을 초기화하기 전에 메모리 부족 회피 매개 변수가 Win32_WMISetting 올바르게 설정되었는지 확인합니다.

  2. 받을 이벤트의 종류를 결정합니다.

    WMI는 내장 및 내재 이벤트를 지원합니다. 내장 이벤트는 WMI에 의해 미리 정의된 이벤트인 반면, 내장 이벤트는 타사 공급자가 정의한 이벤트입니다. 자세한 내용은 수신할 이벤트 유형 결정(Determining of Event)을 참조하세요.

다음 절차에서는 C++에서 비동기 이벤트 알림을 받는 방법을 설명합니다.

C++에서 비동기 이벤트 알림을 받으려면

  1. CoInitializeEx 및 CoInitializeSecurity 함수에 대한 호출을 사용하여 애플리케이션을 설정합니다.

    CoInitializeEx를 호출하면 COM이 초기화되지만 CoInitializeSecurity는 WMI에 소비자 프로세스를 호출할 수 있는 권한을 부여합니다. 또한 CoInitializeEx 함수는 비동기 알림에 필요한 다중 스레드 애플리케이션을 프로그래밍할 수 있는 기능을 부여합니다. 자세한 내용은 WMI 보안 유지 관리를 참조하세요.

    이 항목의 코드는 올바르게 컴파일하려면 다음 참조 및 #include 문이 필요합니다.

    #define _WIN32_DCOM
    #include <iostream>
    using namespace std;
    #include <wbemidl.h>
    

    다음 코드 예제에서는 CoInitializeEx 및 CoInitializeSecurity에 대한 호출을 사용하여 임시 이벤트 소비자를 설정하는 방법을 설명합니다.

    void main(int argc, char **argv)
    {
        HRESULT hr = 0;
        hr = CoInitializeEx (0, COINIT_MULTITHREADED);
        hr = CoInitializeSecurity (NULL, 
           -1, 
           NULL, 
           NULL,   
           RPC_C_AUTHN_LEVEL_NONE, 
           RPC_C_IMP_LEVEL_IMPERSONATE, 
           NULL,
           EOAC_NONE,
           NULL); 
    
        if (FAILED(hr))
        {
           CoUninitialize();
           cout << "Failed to initialize security. Error code = 0x"
               << hex << hr << endl;
           return;
        }
    
    // ...
    }
    
  2. IWbemObjectSink 인터페이스를 통해 싱크 개체를 만듭니다.

    WMI는 IWbemObjectSink 를 사용하여 이벤트 알림을 보내고 비동기 작업 또는 이벤트 알림에 대한 상태를 보고합니다.

  3. IWbemServices::ExecNotificationQueryAsync 메서드에 대한 호출을 사용하여 이벤트 소비자를 등록합니다.

    pResponseHandler 매개 변수가 이전 단계에서 만든 싱크 개체를 가리키는지 확인합니다.

    등록의 목적은 필요한 알림만 수신하는 것입니다. 불필요한 알림을 받으면 처리 및 배달 시간이 낭비됩니다. WMI의 필터링 기능을 최대한 활용하지 않습니다.

    그러나 임시 소비자는 둘 이상의 이벤트 유형을 받을 수 있습니다. 이 경우 임시 소비자는 각 이벤트 유형에 대해 IWbemServices::ExecNotificationQueryAsync 를 별도로 호출해야 합니다. 예를 들어 소비자는 새 프로세스를 만들 때(인스턴스 생성 이벤트 또는 __InstanceCreationEvent) 알림이 필요하고 특정 레지스트리 키( RegistryKeyChangeEvent와 같은 레지스트리 이벤트)를 변경해야 할 수 있습니다. 따라서 소비자는 인스턴스 생성 이벤트를 등록하기 위해 ExecNotificationQueryAsync 를 한 번 호출하고 레지스트리 이벤트에 등록하기 위해 ExecNotificationQueryAsync 를 호출합니다.

    여러 이벤트에 등록하는 이벤트 소비자를 만들도록 선택하는 경우 동일한 싱크에 여러 클래스를 등록하지 않아야 합니다. 대신 등록된 이벤트의 각 클래스에 대해 별도의 싱크를 사용합니다. 전용 싱크를 사용하면 처리가 간소화되고 유지 관리가 지원되므로 다른 싱크에 영향을 주지 않고 하나의 등록을 취소할 수 있습니다.

  4. 이벤트 소비자에서 필요한 작업을 수행합니다.

    이 단계는 대부분의 코드를 포함해야 하며 사용자 인터페이스에 이벤트를 표시하는 등의 활동을 포함해야 합니다.

  5. 완료되면 IWbemServices::CancelAsyncCall 이벤트에 대한 호출을 사용하여 임시 이벤트 소비자의 등록을 취소합니다.

    CancelAsyncCall 호출의 성공 또는 실패 여부에 관계없이 개체 참조 수가 0에 도달할 때까지 싱크 개체를 삭제하지 마세요. 자세한 내용은 메서드 호출을 참조하세요.