Recepción de notificaciones de eventos asincrónicos

La notificación de eventos asincrónicos es una técnica que permite a una aplicación supervisar de forma constante los eventos sin monopolizar los recursos del sistema. Las notificaciones de eventos asincrónicos tienen las mismas limitaciones de seguridad que otras llamadas asincrónicas. En su lugar, puede realizar llamadas semisincrónicas. Para más información, consulte Llamada a un método.

La cola de eventos asincrónicos enrutados a un cliente tiene la posibilidad de crecer hasta un tamaño excepcionalmente grande. Por lo tanto, WMI implementa una directiva de todo el sistema para evitar quedarse sin memoria. WMI ralentiza los eventos o comienza a quitar eventos de la cola cuando la cola crece más allá de un tamaño determinado.

WMI usa las propiedades LowThresholdOnEvents y HighThresholdOnEvents de la clase Win32_WMISetting para establecer límites en la prevención de memoria insuficiente. El valor mínimo indica cuándo debe WMI comenzar a ralentizar la notificación de eventos, y el valor máximo indica cuándo empezar a quitar eventos. Los valores predeterminados para los umbrales bajos y altos son 1000000 (10 MB) y 2000000 (20 MB). Además, puede establecer la propiedad MaxWaitOnEvents para describir la cantidad de tiempo que WMI debe esperar antes de quitar eventos. El valor predeterminado de MaxWaitOnEvents es 2000 o 2 segundos.

Recepción de notificaciones de eventos asincrónicos en VBScript

Las llamadas de scripting para recibir notificaciones de eventos son básicamente las mismas que todas las llamadas asincrónicas con los mismos problemas de seguridad. Para más información, consulte Realización de una llamada asincrónica con VBScript.

Para recibir notificaciones de eventos asincrónicos en VBScript

  1. Cree un objeto receptor llamando a WScript.CreateObject y especificando el progid de "WbemScripting" y el tipo de objeto de SWbemSink. El objeto receptor recibe las notificaciones.

  2. Escriba una subrutina para cada evento que quiera controlar. En la tabla siguiente se enumeran los eventos SWbemSink.

    Evento Significado
    OnObjectReady Informa de la devolución de un objeto al receptor. El uso de esta llamada devuelve un objeto cada vez que se completa la operación.
    OnCompleted Informa cuando se completa una llamada asincrónica. Este evento nunca se produce si la operación es indefinida.
    OnObjectPut Informa de la finalización de una operación put asincrónica. Este evento devuelve la ruta de acceso del objeto de la instancia o la clase guardada.
    OnProgress Notifica el estado de una llamada asincrónica que está en curso. No todos los proveedores admiten informes de progreso provisionales.
    Cancelar Cancela todas las operaciones asincrónicas pendientes asociadas a este receptor de objetos.

     

En el siguiente ejemplo de código de VBScript se notifica la eliminación de procesos con un intervalo de sondeo de 10 segundos. En este script, la subrutina SINK_OnObjectReady controla la repetición del evento. En el ejemplo, el objeto receptor se denomina "Sink", pero puede asignar un nombre a este objeto como prefiera.

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

Recepción de notificaciones de eventos asincrónicos en C++

Para realizar notificaciones asincrónicas, crea un subproceso independiente únicamente para supervisar y recibir eventos de Instrumental de administración de Windows (WMI). Cuando ese subproceso recibe un mensaje, el subproceso lo notifica a la aplicación principal.

Al dedicar un subproceso independiente, permite que el proceso principal realice otras actividades mientras espera a que llegue un evento. La entrega asincrónica de notificaciones mejora el rendimiento, pero puede proporcionar menos seguridad de la que desea. En C++, tiene la opción de usar la interfaz IWbemUnsecuredApartment o realizar comprobaciones de acceso en descriptores de seguridad. Para más información, consulte Establecimiento de la seguridad en una llamada asincrónica.

Para configurar notificaciones de eventos asincrónicas

  1. Antes de inicializar las notificaciones asincrónicas, asegúrese de que los parámetros de prevención de memoria insuficiente están correctamente establecidos en Win32_WMISetting.

  2. Determine el tipo de eventos que desea recibir.

    WMI admite eventos intrínsecos y extrínsecos. Un evento intrínseco es un evento predefinido por WMI, mientras que un evento extrínseco es un evento definido por un proveedor de terceros. Para más información, consulte Determinación del tipo de evento que se va a recibir.

En el procedimiento siguiente se describe cómo recibir notificaciones de eventos asincrónicos en C++.

Para recibir notificaciones de eventos asincrónicos en C++

  1. Configure la aplicación con llamadas a las funciones CoInitializeEx y CoInitializeSecurity.

    Al llamar a CoInitializeEx, se inicializa COM, mientras que CoInitializeSecurity concede a WMI el permiso para llamar al proceso del consumidor. La función CoInitializeEx también le concede la capacidad de programar una aplicación multiproceso, necesaria para la notificación asincrónica. Para más información, consulte Mantenimiento de la seguridad de WMI.

    El código de este tema requiere las siguientes referencias e instrucciones #include para compilarse correctamente.

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

    En el ejemplo de código siguiente se describe cómo configurar el consumidor de eventos temporales con llamadas a CoInitializeEx y 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. Cree un objeto receptor mediante la interfaz IWbemObjectSink.

    WMI utiliza IWbemObjectSink para enviar notificaciones de eventos y notificar el estado de una operación o notificación de eventos asincrónicas.

  3. Registre el consumidor de eventos con una llamada al método IWbemServices::ExecNotificationQueryAsync.

    Asegúrese de que el parámetro pResponseHandler apunta al objeto receptor creado en el paso anterior.

    El propósito del registro es recibir solo las notificaciones necesarias. La recepción de notificaciones superfluas hace perder tiempo de procesamiento y de entrega y no utiliza al máximo la capacidad de filtrado de WMI.

    Sin embargo, un consumidor temporal puede recibir más de un tipo de evento. En este caso, un consumidor temporal debe realizar llamadas independientes a IWbemServices::ExecNotificationQueryAsync para cada tipo de evento. Por ejemplo, un consumidor podría requerir una notificación cuando se crean nuevos procesos (un evento de creación de instancia o __InstanceCreationEvent) y para cambios en determinadas claves del Registro (un evento del Registro como RegistryKeyChangeEvent). Por lo tanto, el consumidor realiza una llamada a ExecNotificationQueryAsync a fin de registrarse para los eventos de creación de instancias y otra llamada a ExecNotificationQueryAsync a fin de registrarse para los eventos del Registro.

    Si decide crear un consumidor de eventos que se registre para varios eventos, debe evitar registrar varias clases con el mismo receptor. Utilice, en su lugar, un receptor independiente para cada clase de evento registrado. Tener un receptor dedicado simplifica el procesamiento y ayuda en el mantenimiento, lo que le permite cancelar un registro sin afectar a los demás.

  4. Realice las actividades necesarias en el consumidor de eventos.

    Este paso debe contener la mayoría del código e incluir actividades como mostrar eventos en una interfaz de usuario.

  5. Cuando termine, anule el registro del consumidor de eventos temporales con una llamada al evento IWbemServices::CancelAsyncCall.

    Independientemente de si la llamada a CancelAsyncCall se realiza de forma correcta o se produce un error, no elimine el objeto receptor hasta que el recuento de referencias de objetos llegue a cero. Para más información, consulte Llamada a un método.