Gestione degli eventi in COM
In gestione degli eventi COM, è stato impostato un'origine eventi e utilizzare un ricevitore di eventi un event_source e event_receiver attributi, rispettivamente, specificando type=COM.Questi attributi è invece possibile inserire il codice appropriato per personalizzata, inviano e interfacce duali consentono di classi a cui si applica per generare gli eventi e gestire eventi dai punti di connessione COM.
Dichiarazione di eventi
in una classe di origine evento, utilizzare __event parola chiave in una dichiarazione dell'interfaccia per dichiarare che i metodi di interfaccia come eventi.Gli eventi dell'interfaccia vengono generati quando vengono definite come metodi di interfaccia.Metodi nelle interfacce eventi possono contenere zero o più parametri (che se vengono in parametri).Il tipo restituito può essere void o un tipo integrale.
Definizione di gestori degli eventi
In una classe del ricevitore di eventi, definire i gestori eventi, ovvero metodi con firme (tipi restituiti, convenzioni di chiamata e argomenti) che corrispondono l'evento che gestiranno.Per eventi COM, convenzioni di chiamata non devono essere uguali; vedere Eventi dipendenti di layout COM in per i dettagli.
Hook dei gestori eventi agli eventi
Inoltre in una classe del ricevitore di eventi, utilizzare la funzione intrinseca __hook per associare gli eventi ai gestori eventi e __unhook per dissociare gli eventi dai gestori eventi.È possibile associare più eventi a un gestore eventi, o a diversi gestori eventi a un evento.
[!NOTA]
In genere, sono disponibili due tecniche per consentire un ricevitore di eventi COM alle definizioni di interfaccia di accesso di origine evento.Il primo, come mostrato di seguito, è di condividere un file di intestazione comune.il secondo è di utilizzare #import con embedded_idl importare il qualificatore, in modo che la libreria dei tipi di origine evento viene scritta nel file con estensione tlh con il codice attributo-generato mantenuto.
eventi di infornamento
Per generare un evento, è sufficiente chiamare un metodo nell'interfaccia dichiarata con __event classe di origine di parola chiave nell'evento.Se i gestori sono stati agganciati all'evento, i gestori verranno chiamati.
Codice dell'evento COM
Nell'esempio seguente viene illustrato come generare un evento in una classe COM.Per compilare ed eseguire l'esempio, fare riferimento ai commenti nel codice.
// 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;
Quindi il server:
// 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;
}
};
Quindi il client:
// 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.
Eventi dipendenti di layout COM
La dipendenza del layout è solo un problema per la programmazione COM.In codice nativo e gestione degli eventi gestita, le firme (tipo restituito, convenzione di chiamata e argomenti) dei gestori devono corrispondere ai relativi eventi, ma i nomi del gestore eventi non devono corrispondere ai relativi eventi.
Tuttavia, nella gestione degli eventi COM, se si imposta layout_dependent parametro di event_receiver in true, il nome e il corrispondente della firma viene applicato.Ciò significa che i nomi e le firme del ricevitore dei gestori nel caso devono corrispondere esattamente ai nomi e le firme degli eventi ai quali vengono agganciati.
quando layout_dependent è impostato su false, la convenzione di chiamata e la classe di archiviazione (virtuale, statico, e così via) possono essere combinati e una corrispondenza tra il metodo dell'evento di infornamento e i metodi hook che consentono di (i delegati).È leggermente più efficiente disporre layout_dependent=true.
Si supponga, ad esempio IEventSource viene definito disporre dei seguenti metodi:
[id(1)] HRESULT MyEvent1([in] int value);
[id(2)] HRESULT MyEvent2([in] int value);
Si presupponga origine evento ha il formato seguente:
[coclass, event_source(com)]
class CSource : public IEventSource {
public:
__event __interface IEvents;
HRESULT FireEvent() {
MyEvent1(123);
MyEvent2(123);
return S_OK;
}
};
Quindi, nel ricevitore, qualsiasi gestore agganciato a un metodo in IEventSource deve corrispondere al nome e la stessa firma, come segue:
[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
}
};