Control de eventos en COM
En el control de eventos COM, configure un receptor del origen de eventos y eventos mediante los atributos de event_source y de event_receiver , respectivamente, especificando type=COM.Estos atributos insertan el código adecuado para custom, se envían, y las interfaces duales para permitir las clases a las que se aplican para desencadenar eventos y eventos de identificador a través de puntos de conexión COM.
Declarar eventos
En una clase de origen de eventos, utilice la palabra clave de __event en una declaración de interfaz para declarar que los métodos de la interfaz como eventos.Los eventos de esa interfaz se desencadenan cuando se los llama como métodos de interfaz.Los métodos de las interfaces de eventos pueden tener cero o más parámetros (que si todos son parámetros de en ).El tipo de valor devuelto puede ser cualquier entero tipo void o.
Definir controladores de eventos
En una clase de receptor de eventos, se definen los controladores de eventos, que son métodos con firmas (tipos de valor devuelto, convenciones de llamada, y argumentos) que coinciden con el evento que controlará.para los eventos COM, las convenciones de llamada no tienen que coincidir; vea Eventos COM dependientes de diseño más adelante los detalles.
Enlazar controladores de eventos a eventos
También en una clase de receptor de eventos, se usa la función intrínseca __hook para asociar eventos a controladores de eventos y __unhook para ser eventos de los controladores de eventos.Puede enlazar varios eventos a un controlador de eventos, o varios controladores de eventos a un evento.
[!NOTA]
Normalmente, hay dos técnicas de permitir que un receptor de eventos COM tiene acceso a definiciones de interfaz del origen de eventos.El primer, como se muestra a continuación, es compartir un archivo de encabezado común.El segundo es utilizar #import con el calificador de importación de embedded_idl , escribir la biblioteca de tipos de origen de eventos al archivo .tlh con el código atributo-generado retenido.
Eventos bounce
Para desencadenar un evento, llamar a un método en la interfaz declarada con la palabra clave de __event en la clase del origen de eventos.Si se ha enlazado a los controladores al evento, llamará a los controladores.
Código de eventos COM
El ejemplo siguiente se muestra cómo activar un evento en una clase COM.Para compilar y ejecutar el ejemplo, vea los comentarios del código.
// evh_server.h
#pragma once
[ dual, uuid("00000000-0000-0000-0000-000000000001") ]
__interface IEvents {
[id(1)] HRESULT MyEvent([in] int value);
};
[ dual, uuid("00000000-0000-0000-0000-000000000002") ]
__interface IEventSource {
[id(1)] HRESULT FireEvent();
};
class DECLSPEC_UUID("530DF3AD-6936-3214-A83B-27B63C7997C4") CSource;
Y el servidor:
// evh_server.cpp
// compile with: /LD
// post-build command: Regsvr32.exe /s evh_server.dll
#define _ATL_ATTRIBUTES 1
#include <atlbase.h>
#include <atlcom.h>
#include "evh_server.h"
[ module(dll, name="EventSource", uuid="6E46B59E-89C3-4c15-A6D8-B8A1CEC98830") ];
[coclass, event_source(com), uuid("530DF3AD-6936-3214-A83B-27B63C7997C4")]
class CSource : public IEventSource {
public:
__event __interface IEvents;
HRESULT FireEvent() {
__raise MyEvent(123);
return S_OK;
}
};
Y el cliente:
// evh_client.cpp
// compile with: /link /OPT:NOREF
#define _ATL_ATTRIBUTES 1
#include <atlbase.h>
#include <atlcom.h>
#include <stdio.h>
#include "evh_server.h"
[ module(name="EventReceiver") ];
[ event_receiver(com) ]
class CReceiver {
public:
HRESULT MyHandler1(int nValue) {
printf_s("MyHandler1 was called with value %d.\n", nValue);
return S_OK;
}
HRESULT MyHandler2(int nValue) {
printf_s("MyHandler2 was called with value %d.\n", nValue);
return S_OK;
}
void HookEvent(IEventSource* pSource) {
__hook(&IEvents::MyEvent, pSource, &CReceiver::MyHandler1);
__hook(&IEvents::MyEvent, pSource, &CReceiver::MyHandler2);
}
void UnhookEvent(IEventSource* pSource) {
__unhook(&IEvents::MyEvent, pSource, &CReceiver::MyHandler1);
__unhook(&IEvents::MyEvent, pSource, &CReceiver::MyHandler2);
}
};
int main() {
// Create COM object
CoInitialize(NULL);
{
IEventSource* pSource = 0;
HRESULT hr = CoCreateInstance(__uuidof(CSource), NULL, CLSCTX_ALL, __uuidof(IEventSource), (void **) &pSource);
if (FAILED(hr)) {
return -1;
}
// Create receiver and fire event
CReceiver receiver;
receiver.HookEvent(pSource);
pSource->FireEvent();
receiver.UnhookEvent(pSource);
}
CoUninitialize();
return 0;
}
Output
MyHandler1 was called with value 123.
MyHandler2 was called with value 123.
Eventos COM dependientes de diseño
La dependencia de diseño solo es un problema para la programación COM.En código nativo y control de eventos administrado, las firmas (tipo de valor devuelto, convención de llamada, y argumentos) de los controladores deben coincidir sus eventos, pero los nombres de controlador no tienen que coincidir sus eventos.
Sin embargo, en el control de eventos COM, cuando establezca el parámetro layout_dependent de event_receiver a TRUE, el nombre y a la coincidencia de firma aplican.Esto significa que los nombres y las firmas de los controladores del receptor de eventos deben coincidir exactamente con los nombres y las firmas de los eventos que están enlazados a.
Cuando es layout_dependent se establece en Falso, la convención de llamada y la clase de almacenamiento (virtual, estático, etc.) se pueden mezclar y coincidir entre el método y los métodos que enlazan (los delegados) del evento bounce.Es ligeramente más eficaz tener layout_dependent=TRUE.
por ejemplo, suponga que IEventSource es definido tener los métodos siguientes:
[id(1)] HRESULT MyEvent1([in] int value);
[id(2)] HRESULT MyEvent2([in] int value);
Suponga que el origen de eventos tiene el formato siguiente:
[coclass, event_source(com)]
class CSource : public IEventSource {
public:
__event __interface IEvents;
HRESULT FireEvent() {
MyEvent1(123);
MyEvent2(123);
return S_OK;
}
};
A continuación, en el receptor de eventos, cualquier controlador enlazado a un método en IEventSource debe coincidir con el nombre y firma, como sigue:
[coclass, event_receiver(com, true)]
class CReceiver {
public:
HRESULT MyEvent1(int nValue) { // name and signature matches MyEvent1
...
}
HRESULT MyEvent2(E c, char* pc) { // signature doesn't match MyEvent2
...
}
HRESULT MyHandler1(int nValue) { // name doesn't match MyEvent1 (or 2)
...
}
void HookEvent(IEventSource* pSource) {
__hook(IFace, pSource); // Hooks up all name-matched events
// under layout_dependent = true
__hook(&IFace::MyEvent1, pSource, &CReceive::MyEvent1); // valid
__hook(&IFace::MyEvent2, pSource, &CSink::MyEvent2); // not valid
__hook(&IFace::MyEvent1, pSource, &CSink:: MyHandler1); // not valid
}
};