Manipulação de eventos no COM
Manipulação de eventos COM, você configurará um receptor de eventos e a fonte de eventos usando o event_source e event_receiver atributos, respectivamente, especificando type=com.Esses atributos injetar o código apropriado para custom, despacho e interfaces duplas para permitir que as classes para o qual são aplicadas para disparar eventos e manipular eventos por meio de pontos de conexão COM.
Declarando Eventos
Em uma classe de origem do evento, use o _ _ Event palavra-chave em uma declaração de interface para declarar os métodos dessa interface como eventos.Os eventos da interface são acionados quando chamá-los como métodos de interface.Métodos em interfaces de evento podem ter zero ou mais parâmetros (que deve ser na parâmetros).O tipo de retorno pode ser anulado ou integrante de qualquer tipo.
Definindo manipuladores de eventos
Em uma classe de receptor de evento, você pode definir manipuladores de eventos, que são os métodos com assinaturas (tipos de retorno, convenções e argumentos de chamada) que correspondem ao evento que manipulará por eles.Para os eventos COM, convenções de chamada não têm correspondentes; consulte Eventos COM dependentes do Layout abaixo para obter detalhes.
Manipuladores de eventos para eventos de gancho
Também em uma classe de receptor de evento, você utilizar a função intrínseca __hook para associar eventos a manipuladores de eventos e __unhook para dissociar eventos de manipuladores de eventos.Você pode conectar vários eventos para um manipulador de eventos ou vários manipuladores de eventos para um evento.
Observação |
---|
Normalmente, existem duas técnicas para permitir que um receptor de eventos COM acessar as definições de interface de origem do evento.O primeiro, como mostrado abaixo, é compartilhar um arquivo de cabeçalho comuns.A segunda é usar # Import com o embedded_idl importar qualificador, de modo que a biblioteca de tipos de fonte de evento é gravada no arquivo .tlh com o código gerado pelo atributo preservado. |
Eventos de acionamento.
Disparar um evento, basta chamar um método na interface do declarado com o __event palavra-chave além de eventos de classe de origem.Se manipuladores tiverem sido enganchados ao evento, o manipulador será chamado.
Evento COM código
O exemplo a seguir mostra como disparar um evento em uma classe COM.Para compilar e executar o exemplo, consulte os comentários no 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;
E, em seguida, o 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;
}
};
E, em seguida, o 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;
}
Saída
MyHandler1 was called with value 123.
MyHandler2 was called with value 123.
Eventos de layout COM dependente
Dependência de layout é apenas uma questão de programação COM.Na manipulação de eventos nativos e gerenciados, as assinaturas dos manipuladores (tipo de retorno, convenção de chamada e argumentos) devem corresponder aos seus eventos, mas os nomes de manipulador não precisam coincidir com os seus eventos.
No entanto, na manipulação de eventos COM, quando você definir a layout_dependent parâmetro do event_receiver para true, o nome e assinatura de correspondência é imposta.Isso significa que os nomes e assinaturas dos manipuladores no caso de receptor deve coincidir exatamente com os nomes e assinaturas dos eventos aos quais estão conectados.
Quando layout_dependent for definido como false, a chamada classe de armazenamento e de convenção (virtual, estática e assim por diante) pode ser misturada e combinada entre o acionamento método eventos e os métodos de gancho (seus representantes).É um pouco mais eficiente do que layout_dependent=true.
Por exemplo, suponha que IEventSource é definido para ter os seguintes métodos:
[id(1)] HRESULT MyEvent1([in] int value);
[id(2)] HRESULT MyEvent2([in] int value);
Suponha que a origem do evento tem a seguinte forma:
[coclass, event_source(com)]
class CSource : public IEventSource {
public:
__event __interface IEvents;
HRESULT FireEvent() {
MyEvent1(123);
MyEvent2(123);
return S_OK;
}
};
Em seguida, qualquer manipulador no receptor de eventos, conectados a um método em IEventSource deve corresponder ao seu nome e assinatura, da seguinte maneira:
[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
}
};