Receber notificações de eventos assíncronas

A notificação de evento assíncrona é 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. Em vez delas, você pode fazer chamadas semissíncronas. Para obter mais informações, consulte Chamar um método.

A fila de eventos assíncronos roteado para um cliente tem o potencial de crescer excepcionalmente. 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 falta de memória. O valor mínimo indica quando o WMI deve iniciar redução da velocidade da notificação de 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 1000000 (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.

Receber notificações de eventos assíncronos em VBScript

As chamadas de script para receber notificações de evento são essencialmente iguais a todas as chamadas assíncronas com os mesmos problemas de segurança. Para saber mais, confira Fazer uma chamada assíncrona com VBScript.

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

  1. Crie um objeto coletor chamando WScript.CreateObject e especificando o progid "WbemScripting" e o tipo de objeto 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 de 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 de VBScript a seguir notifica a exclusão de processos com um intervalo de sondagem de 10 segundos. Nesse script, a sub-rotina SINK_OnObjectReady cuida da ocorrência do evento. No exemplo, o objeto coletor é chamado de "Sink", no entanto, você pode nomear esse objeto como escolher.

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

Receber notificações de eventos assíncronos em C++

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

Ao dedicar um thread separado, você permite que o processo principal execute outras atividades enquanto aguarda a chegada de um evento. A entrega assíncrona de notificações aprimora o desempenho, mas pode fornecer menos segurança do que você deseja. Em 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 Configurar a segurança em uma chamada assíncrona.

Para configurar notificações de eventos assíncronas

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

  2. Determine o tipo de evento que 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 terceiro. 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 usando C++.

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

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

    Chamar CoInitializeEx inicializa o COM, enquanto CoInitializeSecurity concede ao WMI permissão para chamar o processo do consumidor. A função CoInitializeEx também permite 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 exigem que as referências e instruções #include a seguir 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 notificação de evento ou operação assíncrona.

  3. Registre o 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 em seu potencial máximo.

    No entanto, um consumidor temporário pode receber mais de um tipo de evento. Nesse caso, ele deve fazer chamadas separadas para IWbemServices::ExecNotificationQueryAsync para cada tipo de evento. Por exemplo, um consumidor pode exigir notificação quando 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 em vários eventos, evite registrar várias classes com o mesmo coletor. Em vez disso, use um coletor separado para cada classe de evento registrada. 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 a exibição de eventos para uma interface do usuário.

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

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