Recebendo notificações de evento assíncronas

A notificação de evento assíncrono é uma técnica que permite que um aplicativo monitore constantemente eventos sem monopolizar recursos do sistema. As notificações de evento assíncronas têm as mesmas limitações de segurança que outras chamadas assíncronas têm. Em vez disso, você pode fazer chamadas semissíncronas. Para obter mais informações, consulte Chamar um método.

A fila de eventos assíncronos roteados para um cliente tem o potencial de crescer excepcionalmente grande. Portanto, o WMI implementa uma política em todo o sistema para evitar ficar sem memória. O WMI reduz a velocidade dos eventos ou começa a remover eventos da fila quando a fila cresce além de um determinado tamanho.

O WMI usa as propriedades LowThresholdOnEvents e HighThresholdOnEvents da classe Win32_WMISetting para definir limites para evitar a perda de memória. O valor mínimo indica quando o WMI deve começar a diminuir a notificação do evento e o valor máximo indica quando iniciar a remoção de eventos. Os valores padrão para os limites baixo e alto são 10000000 (10 MB) e 2000000 (20 MB). Além disso, você pode definir a propriedade MaxWaitOnEvents para descrever a quantidade de tempo que o WMI deve aguardar antes de descartar eventos. O valor padrão para MaxWaitOnEvents é 2000 ou 2 segundos.

Recebendo notificações de evento assíncronas no VBScript

As chamadas de script para receber notificações de evento são essencialmente as mesmas que todas as chamadas assíncronas com os mesmos problemas de segurança. Para obter mais informações, consulte Como fazer uma chamada assíncrona com o VBScript.

Para receber notificações de evento assíncronas no VBScript

  1. Crie um objeto de coletor chamando WScript.CreateObject e especificando o progid de "WbemScripting" e o tipo de objeto de SWbemSink. O objeto coletor recebe as notificações.

  2. Escreva uma sub-rotina para cada evento que você deseja manipular. A tabela a seguir lista os eventos SWbemSink .

    Evento Significado
    OnObjectReady Relata os retornos de um objeto para o coletor. O uso dessa chamada retorna um objeto cada vez até que a operação seja concluída.
    OnCompleted Relata quando uma chamada assíncrona é concluída. Esse evento nunca ocorrerá se a operação for indefinida.
    OnObjectPut Relata a conclusão de uma operação de colocação assíncrona. Esse evento retorna o caminho do objeto da instância ou da classe salva.
    OnProgress Relata o status de uma chamada assíncrona que está em andamento. Nem todos os provedores dão suporte a relatórios de progresso provisório.
    Cancelar Cancela todas as operações assíncronas pendentes associadas a esse coletor de objetos.

     

O exemplo de código VBScript a seguir notifica a exclusão de processos com um intervalo de sondagem de 10 segundos. Nesse script, a sub-rotina SINK_OnObjectReady manipula a ocorrência do evento. No exemplo, o objeto coletor é chamado "Coletor", no entanto, você pode nomear esse objeto como quiser.

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

Recebendo notificações de evento assíncronas no C++

Para executar uma notificação assíncrona, crie um thread separado exclusivamente para monitorar e receber eventos de Windows Instrumentação de Gerenciamento (WMI). Quando esse thread recebe uma mensagem, o thread notifica seu aplicativo principal.

Ao dedicar um thread separado, você permite que seu processo principal execute outras atividades enquanto aguarda a chegada de um evento. A entrega assíncrona de notificações melhora o desempenho, mas pode fornecer menos segurança do que você deseja. No C++, você tem a opção de usar a interface IWbemUnsecuredApartment ou executar verificações de acesso em descritores de segurança. Para obter mais informações, consulte Configurando a segurança em uma chamada assíncrona.

Para configurar notificações de evento assíncronas

  1. Antes de inicializar quaisquer notificações assíncronas, verifique se os parâmetros de prevenção fora da memória estão definidos corretamente em Win32_WMISetting.

  2. Determine que tipo de eventos você deseja receber.

    O WMI dá suporte a eventos intrínsecos e extrínsecos. Um evento intrínseco é um evento predefinido pelo WMI, enquanto um evento extrínseco é um evento definido por um provedor de terceiros. Para obter mais informações, consulte Determinar o tipo de evento a receber.

O procedimento a seguir descreve como receber notificações de evento assíncronas no C++.

Para receber notificações de evento assíncronas no C++

  1. Configure seu aplicativo com chamadas para as funções CoInitializeEx e CoInitializeSecurity .

    Chamar CoInitializeEx inicializa COM, enquanto o CoInitializeSecurity concede ao WMI a permissão para chamar o processo do consumidor. A função CoInitializeEx também concede a você a capacidade de programar um aplicativo multithreaded, o que é necessário para notificação assíncrona. Para obter mais informações, consulte Manter a segurança do WMI.

    O código neste tópico requer que as seguintes referências e instruções #include sejam compiladas corretamente.

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

    O exemplo de código a seguir descreve como configurar o consumidor de eventos temporários com chamadas para CoInitializeEx e 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. Crie um objeto coletor por meio da interface IWbemObjectSink .

    O WMI usa IWbemObjectSink para enviar notificações de evento e relatar o status em uma operação assíncrona ou notificação de evento.

  3. Registre seu consumidor de eventos com uma chamada para o método IWbemServices::ExecNotificationQueryAsync .

    Verifique se o parâmetro pResponseHandler aponta para o objeto coletor criado na etapa anterior.

    A finalidade do registro é receber apenas as notificações necessárias. Receber notificações supérfluas desperdiça o processamento e o tempo de entrega; e não usa a capacidade de filtragem do WMI para o potencial máximo.

    No entanto, um consumidor temporário pode receber mais de um tipo de evento. Nesse caso, um consumidor temporário deve fazer chamadas separadas para IWbemServices::ExecNotificationQueryAsync para cada tipo de evento. Por exemplo, um consumidor pode exigir notificação quando novos processos são criados (um evento de criação de instância ou __InstanceCreationEvent) e para alterações em determinadas chaves do Registro (um evento do Registro, como RegistryKeyChangeEvent). Portanto, o consumidor faz uma chamada para ExecNotificationQueryAsync para registrar eventos de criação de instância e outra chamada para ExecNotificationQueryAsync para se registrar em eventos do Registro.

    Se você optar por criar um consumidor de eventos que se registra para vários eventos, evite registrar várias classes com o mesmo coletor. Em vez disso, use um coletor separado para cada classe de evento registrado. Ter um coletor dedicado simplifica o processamento e ajuda na manutenção, permitindo que você cancele um registro sem afetar os outros.

  4. Execute todas as atividades necessárias no consumidor do evento.

    Esta etapa deve conter a maior parte do código e incluir atividades como exibir eventos em uma interface do usuário.

  5. Quando terminar, cancele o registro do consumidor de eventos temporários com uma chamada para o evento IWbemServices::CancelAsyncCall .

    Independentemente de a chamada para CancelAsyncCall ter êxito ou falhar, não exclua o objeto coletor até que a contagem de referência de objeto atinja zero. Para obter mais informações, consulte Chamar um método.