Udostępnij przez


Otrzymywanie asynchronicznych powiadomień o zdarzeniach

Powiadomienie o zdarzeniach asynchronicznych to technika, która umożliwia aplikacji ciągłe monitorowanie zdarzeń bez monopolizowania zasobów systemowych. Powiadomienia o zdarzeniach asynchronicznych mają te same ograniczenia zabezpieczeń, które mają inne wywołania asynchroniczne. Zamiast tego można wykonywać wywołania semisynchroniczne. Aby uzyskać więcej informacji, odnieś się do Wywoływanie metody.

Kolejka zdarzeń asynchronicznych kierowanych do klienta ma potencjał, aby znacząco się powiększyć. W związku z tym usługa WMI implementuje politykę dla całego systemu, aby uniknąć wyczerpania pamięci. Usługa WMI spowalnia zdarzenia lub zaczyna upuszczać zdarzenia z kolejki, gdy kolejka przekroczy określony rozmiar.

WMI używa właściwości LowThresholdOnEvents oraz HighThresholdOnEvents z klasy Win32_WMISetting, aby ustawić limity unikania braku pamięci. Wartość minimalna wskazuje, kiedy usługa WMI powinna zacząć zwalniać powiadomienia o zdarzeniach, a maksymalna wskazuje, kiedy zacząć odrzucanie zdarzeń. Wartości domyślne dla progów niskich i wysokich to 1000000 (10 MB) i 2000000 (20 MB). Ponadto można ustawić właściwość MaxWaitOnEvents, aby opisać czas oczekiwania usługi WMI przed usunięciem zdarzeń. Wartość domyślna MaxWaitOnEvents wynosi 2000 lub 2 sekundy.

Odbieranie asynchronicznych powiadomień o zdarzeniach w języku VBScript

Wywołania skryptów do odbierania powiadomień o zdarzeniach są zasadniczo takie same jak wszystkie wywołania asynchroniczne z tymi samymi problemami z zabezpieczeniami. Aby uzyskać więcej informacji, zobacz Tworzenie asynchronicznego wywołania za pomocą języka VBScript.

Aby otrzymywać powiadomienia o zdarzeniach asynchronicznych w języku VBScript

  1. Utwórz obiekt zlewu przez wywołanie WScript.CreateObject i określenie progID "WbemScripting" oraz typu obiektu SWbemSink. Obiekt ujścia odbiera powiadomienia.

  2. Napisz podproceduty dla każdego zdarzenia, które chcesz obsłużyć. W poniższej tabeli wymieniono zdarzenia SWbemSink.

    Zdarzenie Znaczenie
    OnObjectReady Zgłasza zwroty obiektu do ujścia. Użycie tego wywołania zwraca jeden obiekt za każdym razem, aż operacja zostanie ukończona.
    Zakończone Informuje o zakończeniu wywołania asynchronicznego. To zdarzenie nigdy nie występuje, jeśli operacja jest nieokreślona.
    OnObjectPut Zgłasza ukończenie operacji umieszczania asynchronicznego. To zdarzenie zwraca ścieżkę obiektu instancji lub klasy zapisanej.
    OnProgress Zgłasza stan asynchronicznego wywołania, które jest w toku. Nie wszyscy dostawcy obsługują tymczasowe raporty o postępach.
    Anuluj Anuluje wszystkie zaległe operacje asynchroniczne skojarzone z tym odbiornikiem obiektu.

     

Poniższy przykład kodu VBScript powiadamia o usunięciu procesów z 10-sekundowym interwałem sondowania. W tym skrypcie podprocedura SINK_OnObjectReady obsługuje wystąpienie zdarzenia. W tym przykładzie obiekt ujścia ma nazwę "Sink", jednak można nazwać ten obiekt zgodnie z wybranymi opcjami.

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

Odbieranie asynchronicznych powiadomień o zdarzeniach w języku C++

Aby wykonać powiadomienie asynchroniczne, należy utworzyć oddzielny wątek wyłącznie do monitorowania i odbierania zdarzeń z instrumentacji zarządzania Windows (WMI). Gdy ten wątek otrzyma komunikat, wątek powiadamia główną aplikację.

Poświęcając oddzielny wątek, można zezwolić głównemu procesowi na wykonywanie innych działań podczas oczekiwania na nadejście zdarzenia. Asynchroniczne dostarczanie powiadomień zwiększa wydajność, ale może zapewnić mniejsze bezpieczeństwo, niż chcesz. W języku C++ możesz użyć interfejsu IWbemUnsecuredApartment lub przeprowadzać sprawdzanie dostępu deskryptorów zabezpieczeń. Aby uzyskać więcej informacji, zobacz sekcję Ustawianie zabezpieczeń dla asynchronicznego wywołania.

Aby skonfigurować asynchroniczne powiadomienia o zdarzeniach

  1. Przed zainicjowaniem wszelkich powiadomień asynchronicznych upewnij się, że parametry unikania braku pamięci są poprawnie ustawione w Win32_WMISetting.

  2. Określ, jakiego rodzaju zdarzenia chcesz otrzymywać.

    Usługa WMI obsługuje zdarzenia wewnętrzne i zewnętrzne. Zdarzenie wewnętrzne jest zdarzeniem wstępnie zdefiniowanym przez usługę WMI, natomiast zdarzenie zewnętrzne jest zdarzeniem zdefiniowanym przez dostawcę innej firmy. Aby uzyskać więcej informacji, zobacz Określanie typu zdarzenia do otrzymania.

Poniższa procedura opisuje sposób odbierania asynchronicznych powiadomień o zdarzeniach w języku C++.

Aby otrzymywać powiadomienia o zdarzeniach asynchronicznych w języku C++

  1. Skonfiguruj aplikację przy użyciu wywołań funkcji CoInitializeEx i CoInitializeSecurity.

    Wywołanie CoInitializeEx inicjuje COM, podczas gdy CoInitializeSecurity przyznaje usłudze WMI uprawnienia do wywoływania w procesie konsumenta. Funkcja CoInitializeEx zapewnia również możliwość programowania aplikacji wielowątkowej, co jest niezbędne do powiadamiania asynchronicznego. Aby uzyskać więcej informacji, zobacz Obsługa zabezpieczeń usługi WMI.

    Kod w tym temacie wymaga następujących odwołań i instrukcji #include w celu poprawnego skompilowania.

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

    W poniższym przykładzie kodu opisano sposób konfigurowania tymczasowego odbiorcy zdarzeń za pomocą wywołań CoInitializeEx i 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. Utwórz obiekt ujścia za pomocą interfejsu IWbemObjectSink.

    Usługa WMI używa IWbemObjectSink do wysyłania powiadomień o zdarzeniach i zgłaszania stanu w odniesieniu do operacji asynchronicznej lub powiadomienia o zdarzeniach.

  3. Zarejestruj konsumenta zdarzeń za pomocą wywołania metody IWbemServices::ExecNotificationQueryAsync.

    Upewnij się, że parametr pResponseHandler wskazuje na obiekt ujścia utworzony w poprzednim kroku.

    Celem rejestracji jest odbieranie tylko wymaganych powiadomień. Odbieranie zbędnych powiadomień marnuje czas przetwarzania i dostarczania oraz nie wykorzystuje w pełni możliwości filtrowania WMI.

    Jednak użytkownik tymczasowy może odbierać więcej niż jeden typ zdarzenia. W takim przypadku użytkownik tymczasowy musi wykonywać oddzielne wywołania do IWbemServices::ExecNotificationQueryAsync dla każdego typu zdarzenia. Na przykład użytkownik może wymagać powiadomienia podczas tworzenia nowych procesów (zdarzenia tworzenia instancji lub __InstanceCreationEvent) oraz przy zmianach w niektórych kluczach rejestru (zdarzenie zmiany klucza rejestru, takie jak RegistryKeyChangeEvent). W związku z tym użytkownik wykonuje jedno wywołanie ExecNotificationQueryAsync, aby zarejestrować się na zdarzenia tworzenia instancji, a drugie wywołanie ExecNotificationQueryAsync, aby zarejestrować się na zdarzenia rejestru.

    Jeśli zdecydujesz się utworzyć odbiorcę zdarzeń, który rejestruje się dla wielu zdarzeń, należy unikać rejestrowania wielu klas za pomocą tego samego ujścia. Zamiast tego należy użyć oddzielnego ujścia dla każdej klasy zarejestrowanego zdarzenia. Posiadanie dedykowanego ujścia upraszcza przetwarzanie i ułatwia konserwację, umożliwiając anulowanie jednej rejestracji bez wpływu na inne.

  4. Wykonaj wszelkie niezbędne działania u odbiorcy zdarzeń.

    Ten krok powinien zawierać większość kodu i zawierać takie działania, jak wyświetlanie zdarzeń w interfejsie użytkownika.

  5. Po zakończeniu wyrejestruj tymczasowego konsumenta zdarzeń za pomocą wywołania IWbemServices::CancelAsyncCall.

    Niezależnie od tego, czy wywołanie metody CancelAsyncCall zakończy się powodzeniem lub niepowodzeniem, nie usuwaj obiektu ujścia, dopóki liczba odwołań do obiektu nie osiągnie zera. Aby uzyskać więcej informacji, zobacz Wywoływanie metody.