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

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

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

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

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

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

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

  1. Создайте объект приемника, вызвав WScript.CreateObject и указав progid 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). Когда поток получает сообщение, поток уведомляет приложение main.

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

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

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

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

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

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