Получение асинхронных уведомлений о событиях

Асинхронное уведомление о событиях — это метод, позволяющий приложению постоянно отслеживать события без монополизации системных ресурсов. Асинхронные уведомления о событиях имеют те же ограничения безопасности, что и другие асинхронные вызовы. Вместо этого можно выполнять полусинхронные вызовы. Дополнительные сведения см. в разделе "Вызов метода".

Очередь асинхронных событий, перенаправленных клиенту, может увеличиваться исключительно большим. Таким образом, WMI реализует системную политику, чтобы избежать нехватки памяти. WMI либо замедляет события, либо начинает удалять события из очереди, когда очередь увеличивается до определенного размера.

WMI использует свойства LowThresholdOnEvents и HighThresholdOnEvents класса Win32_WMISetting , чтобы задать ограничения на избегание нехватки памяти. Минимальное значение указывает, когда WMI должен начать уведомление о событиях замедления, а максимальное значение указывает, когда следует начать удаление событий. Значения по умолчанию для низких и высоких пороговых значений : 1000000 (10 МБ) и 2000000 (20 МБ). Кроме того, можно задать свойство MaxWaitOnEvents , чтобы описать время ожидания WMI перед удалением событий. Значение по умолчанию для MaxWaitOnEvents — 2000 или 2 секунды.

Получение асинхронных уведомлений о событиях в VBScript

Вызовы сценариев для получения уведомлений о событиях по сути одинаковы, как и все асинхронные вызовы с одинаковыми проблемами безопасности. Дополнительные сведения см. в разделе "Выполнение асинхронного вызова с помощью VBScript".

Получение асинхронных уведомлений о событиях в VBScript

  1. Создайте объект приемника, вызвав WScript.CreateObject и указав прогид WbemScripting и тип объекта 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++

Для выполнения асинхронного уведомления создается отдельный поток исключительно для мониторинга и получения событий из инструментария управления Windows (WMI). Когда этот поток получает сообщение, поток уведомляет основное приложение.

Определив отдельный поток, вы разрешаете основному процессу выполнять другие действия во время ожидания прибытия события. Асинхронная доставка уведомлений повышает производительность, но может обеспечить меньшую безопасность, чем требуется. В C++ можно использовать интерфейс IWbemUnsecuredApartment или выполнять проверки доступа для дескрипторов безопасности. Дополнительные сведения см. в разделе "Настройка безопасности для асинхронного вызова".

Настройка асинхронных уведомлений о событиях

  1. Перед инициализацией асинхронных уведомлений убедитесь, что параметры предотвращения нехватки памяти правильно заданы в Win32_WMISetting.

  2. Определите, какие события вы хотите получить.

    WMI поддерживает встроенные и экстринсические события. Внутреннее событие — это событие, предопределенное WMI, тогда как экстринсическое событие — это событие, определенное сторонним поставщиком. Дополнительные сведения см. в разделе "Определение типа события для получения".

В следующей процедуре описывается получение асинхронных уведомлений о событиях в 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 успешно или завершается сбоем, не удаляйте объект приемника до тех пор, пока число ссылок на объект не достигнет нуля. Дополнительные сведения см. в разделе "Вызов метода".