Partilhar via


Recebendo notificações de eventos assíncronos

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

A fila de eventos assíncronos canalizados para um cliente tem o potencial de crescer de grande dimensão. Portanto, o WMI implementa uma política em todo o sistema para evitar a falta de memória. O WMI torna os eventos mais lentos ou começa a descartar eventos da fila quando a fila ultrapassa 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 começar a diminuir a notificação de eventos e o valor máximo indica quando começar a descartar 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 esperar antes de descartar eventos. O valor padrão para MaxWaitOnEvents é 2000 ou 2 segundos.

Recebendo notificações de eventos assíncronos no VBScript

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

Para receber notificações de eventos assíncronos no VBScript

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

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

    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.
    Concluído Informa quando uma chamada assíncrona é concluída. Esse evento nunca ocorre se a operação for indefinida.
    OnObjectPut Relata a conclusão de uma operação assíncrona de envio. Esse evento retorna o caminho do objeto da instância ou da classe salva.
    EmProgresso Relata o status de uma chamada assíncrona em andamento. Nem todos os fornecedores apoiam relatórios intercalares de progresso.
    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. Neste script, a sub-rotina SINK_OnObjectReady manipula a ocorrência do evento. No exemplo, o objeto do coletor é chamado "Sink", 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 eventos assíncronos em C++

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

Ao dedicar um tópico separado, você permite que seu processo principal realize outras atividades enquanto espera 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. 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 Definindo a segurança em uma chamada assíncrona.

Para configurar notificações de eventos assíncronos

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

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

    O WMI suporta 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 eventos assíncronos em C++.

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

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

    Chamar CoInitializeEx inicializa COM, enquanto CoInitializeSecurity concede ao WMI a permissão para chamar o processo do consumidor. A função CoInitializeEx também concede a capacidade de programar uma aplicação multi-thread, o que é necessário para a notificação assíncrona. Para obter mais informações, consulte Mantendo a segurança do WMI.

    O código neste tópico requer as seguintes referências e instruções #include para compilar 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 evento temporário 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 sink através da interface IWbemObjectSink.

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

  3. Registre seu consumidor de evento com uma chamada para o métodoIWbemServices::ExecNotificationQueryAsync.

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

    O objetivo do registo é receber apenas as notificações necessárias. Receber notificações supérfluas desperdiça tempo de processamento e entrega; e não utiliza a capacidade de filtragem do WMI em todo o potencial.

    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 registar eventos de criação de instância e outra chamada para ExecNotificationQueryAsync para se registar para eventos do Registro.

    Se você optar por criar um consumidor de eventos que se registre 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 uma pia dedicada simplifica o processamento e auxilia na manutenção, permitindo cancelar um registro sem afetar os outros.

  4. Execute todas as atividades necessárias no seu consumidor de eventos.

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

  5. Quando terminar, anule o registo do consumidor de evento temporário com uma chamada para 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ência de objeto atinja zero. Para obter mais informações, consulte chamando um método.