Empfangen von asynchronen Ereignisbenachrichtigungen

Durch asynchrone Ereignisbenachrichtigungen kann eine Anwendung Ereignisse ständig überwachen, ohne Systemressourcen zu beanspruchen. Für asynchrone Ereignisbenachrichtigungen gelten die gleichen Sicherheitseinschränkungen wie für andere asynchrone Aufrufe. Sie können stattdessen semisynchrone Aufrufe verwenden. Weitere Informationen finden Sie unter Aufrufen einer Methode.

Die Warteschlange der asynchronen Ereignisse, die an einen Client weitergeleitet werden, kann außergewöhnlich lang werden. Daher implementiert WMI eine systemweite Richtlinie, um dafür zu sorgen, dass immer genügend Arbeitsspeicher zur Verfügung steht. WMI verlangsamt entweder die Ereignisse oder beginnt mit dem Löschen von Ereignissen aus der Warteschlange, wenn die Warteschlange eine bestimmte Größe überschreitet.

WMI verwendet die Eigenschaften LowThresholdOnEvents und HighThresholdOnEvents der Win32_WMISetting-Klasse, um Grenzwerte für die Vermeidung von Arbeitsspeichermangel festzulegen. Der Mindestwert gibt an, wann WMI mit der Verlangsamung der Ereignisbenachrichtigung beginnen soll, und der Höchstwert gibt an, wann mit dem Löschen von Ereignissen begonnen werden soll. Die Standardwerte für die niedrigen und hohen Schwellenwerte sind „1000000“ (10 MB) und „2000000“ (20 MB). Darüber hinaus können Sie die MaxWaitOnEvents-Eigenschaft festlegen, um anzugeben, wie lange WMI warten soll, bevor Ereignisse gelöscht werden. Der Standardwert für MaxWaitOnEvents lautet „2000“, also 2 Sekunden.

Empfangen von asynchronen Ereignisbenachrichtigungen in VBScript

Die Skriptaufrufe zum Empfangen von Ereignisbenachrichtigungen entsprechen im Wesentlichen allen asynchronen Aufrufen mit denselben Sicherheitsproblemen. Weitere Informationen finden Sie unter Erstellen eines asynchronen Aufrufs mit VBScript.

So empfangen Sie asynchrone Ereignisbenachrichtigungen in VBScript

  1. Erstellen Sie ein Senkenobjekt, indem Sie WScript.CreateObject aufrufen und die ProgID „WbemScripting“ und den Objekttyp SWbemSink angeben. Das Senkenobjekt empfängt die Benachrichtigungen.

  2. Schreiben Sie für jedes zu verarbeitende Ereignis eine Unterroutine. In der folgenden Tabelle sind die SWbemSink-Ereignisse aufgeführt.

    Ereignis Bedeutung
    OnObjectReady Meldet die Rückgaben eines Objekts an die Senke. Mit diesem Aufruf wird jedes Mal ein Objekt zurückgegeben, bis der Vorgang abgeschlossen ist.
    OnCompleted Meldet, wenn ein asynchroner Aufruf abgeschlossen ist. Bei unendlichen Vorgängen tritt dieses Ereignis nie ein.
    OnObjectPut Meldet den Abschluss eines asynchronen „Put“-Vorgangs. Dieses Ereignis gibt den Objektpfad der Instanz oder der gespeicherten Klasse zurück.
    OnProgress Meldet den Status eines asynchronen Aufrufs, der gerade ausgeführt wird. Nicht alle Anbieter unterstützen Zwischenstatusberichte.
    Abbrechen Bricht alle ausstehenden asynchronen Vorgänge ab, die dieser Objektsenke zugeordnet sind.

     

Im folgenden VBScript-Codebeispiel wird über das Löschen von Prozessen mit einem Abrufintervall von 10 Sekunden informiert. In diesem Skript verarbeitet die Unterroutine „SINK_OnObjectReady“ das Auftreten des Ereignisses. Im Beispiel lautet der Name des Senkenobjekts „Sink“. Sie können dieses Objekt jedoch beliebig umbenennen.

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

Empfangen von asynchronen Ereignisbenachrichtigungen in C++

Zur Ausführung einer asynchronen Benachrichtigung erstellen Sie einen separaten Thread ausschließlich zum Überwachen und Empfangen von Ereignissen von der Windows-Verwaltungsinstrumentation (Windows Management Instrumentation, WMI). Wenn dieser Thread eine Nachricht empfängt, wird Ihre Hauptanwendung benachrichtigt.

Durch die Zuweisung eines separaten Threads erlauben Sie Ihrem Hauptprozess, andere Aktivitäten auszuführen, während auf das Eintreten eines Ereignisses gewartet wird. Die asynchrone Übermittlung von Benachrichtigungen verbessert zwar die Leistung, bietet aber möglicherweise weniger Sicherheit als gewünscht. In C++ haben Sie die Möglichkeit, die IWbemUnsecuredApartment-Schnittstelle zu verwenden oder Zugriffsüberprüfungen für Sicherheitsbeschreibungen durchzuführen. Weitere Informationen finden Sie unter Festlegen der Sicherheit für einen asynchronen Aufruf.

So richten Sie asynchrone Ereignisbenachrichtigungen ein

  1. Stellen Sie vor dem Initialisieren asynchroner Benachrichtigungen sicher, dass die Parameter für die Vermeidung von Arbeitsspeichermangel in Win32_WMISetting richtig festgelegt sind.

  2. Legen Sie fest, welche Art von Ereignissen Sie empfangen möchten.

    WMI unterstützt systeminterne und extrinsische Ereignisse. Ein systeminternes Ereignis ist ein von WMI vordefiniertes Ereignis, während es sich bei einem extrinsischen Ereignis um ein von einem Drittanbieter definiertes Ereignis handelt. Weitere Informationen finden Sie unter Bestimmen des zu empfangenden Ereignistyps.

Im Folgenden wird beschrieben, wie Sie asynchrone Ereignisbenachrichtigungen in C++ empfangen.

So empfangen Sie asynchrone Ereignisbenachrichtigungen in C++

  1. Richten Sie Ihre Anwendung mit Aufrufen der Funktionen CoInitializeEx und CoInitializeSecurity ein.

    Durch Aufrufen von CoInitializeEx wird COM initialisiert, während CoInitializeSecurity WMI die Berechtigung zum Aufrufen des Prozesses des Consumers erteilt. Die CoInitializeEx-Funktion ermöglicht Ihnen auch das Programmieren einer Multithreadanwendung, die für asynchrone Benachrichtigungen erforderlich ist. Weitere Informationen finden Sie unter Verwalten der WMI-Sicherheit.

    Der Code in diesem Thema erfordert die folgenden Verweise und #include-Anweisungen für eine ordnungsgemäße Kompilierung.

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

    Im folgenden Codebeispiel ist die Einrichtung des temporären Ereignisconsumers mit Aufrufen von CoInitializeEx und CoInitializeSecurity beschrieben.

    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. Erstellen Sie ein Senkenobjekt über die IWbemObjectSink-Schnittstelle.

    WMI verwendet IWbemObjectSink, um Ereignisbenachrichtigungen zu senden und den Status eines asynchronen Vorgangs oder einer asynchronen Ereignisbenachrichtigung zu melden.

  3. Registrieren Sie Ihren Ereignisconsumer mit einem Aufruf der IWbemServices::ExecNotificationQueryAsync-Methode.

    Stellen Sie sicher, dass der Parameter pResponseHandler auf das im vorherigen Schritt erstellte Senkenobjekt verweist.

    Der Zweck der Registrierung besteht darin, nur die erforderlichen Benachrichtigungen zu empfangen. Durch den Empfang überflüssiger Benachrichtigungen wird Verarbeitungs- und Übermittlungszeit verschwendet und die Filterfunktion von WMI nicht optimal genutzt.

    Ein temporärer Consumer kann jedoch mehrere Ereignistypen empfangen. In diesem Fall muss ein temporärer Consumer für jeden Ereignistyp separate Aufrufe von IWbemServices::ExecNotificationQueryAsync senden. Beispielsweise kann ein Consumer eine Benachrichtigung erfordern, wenn neue Prozesse erstellt werden (ein Instanzerstellungsereignis oder __InstanceCreationEvent) und bei Änderungen an bestimmten Registrierungsschlüsseln (ein Registrierungsereignis wie RegistryKeyChangeEvent). Daher erfolgt durch den Consumer ein Aufruf von ExecNotificationQueryAsync zur Registrierung für Instanzerstellungsereignisse und ein weiterer Aufruf von ExecNotificationQueryAsync zur Registrierung für Registrierungsereignisse.

    Wenn Sie einen Ereignisconsumer erstellen möchten, der sich für mehrere Ereignisse registriert, sollten Sie die Registrierung mehrerer Klassen mit derselben Senke vermeiden. Verwenden Sie stattdessen für jede Klasse von registrierten Ereignissen eine separate Senke. Eine dedizierte Senke vereinfacht die Verarbeitung und erleichtert die Wartung, sodass Sie eine Registrierung abbrechen können, ohne die anderen zu beeinträchtigen.

  4. Führen Sie alle erforderlichen Aktivitäten in Ihrem Ereignisconsumer aus.

    Dieser Schritt sollte den größten Teil Ihres Codes enthalten und Aktivitäten wie das Anzeigen von Ereignissen auf einer Benutzeroberfläche umfassen.

  5. Wenn Sie fertig sind, heben Sie die Registrierung des temporären Ereignisconsumers mit einem Aufruf des Ereignisses IWbemServices::CancelAsyncCall auf.

    Unabhängig davon, ob der Aufruf von CancelAsyncCall erfolgreich ist oder fehlschlägt, dürfen Sie das Senkenobjekt erst löschen, wenn die Objektverweisanzahl Null (0) erreicht. Weitere Informationen finden Sie unter Aufrufen einer Methode.