Zpracování událostí v modelu COM
V modelu COM zpracování událostí, nastavte události zdroj a událost přijímač pomocí Zdroj_události a event_receiver atributy, určení type=com.Tyto atributy nastříkne příslušný kód vlastní, odeslání a duální rozhraní povolit tříd, na které se vztahují požární události a zpracování událostí COM body připojení.
Deklarace události
Třída události zdroje použít položky __event klíčové slovo v deklaraci rozhraní deklarovat metody tohoto rozhraní jako události.Události rozhraní jsou aktivována při volání jako metody rozhraní.Metody rozhraní události může mít nula nebo více parametrů (které musí být v parametry).Návratový typ může být typu void nebo všechny nedílnou.
Definování obslužné rutiny událostí
Třída události přijímač definujete obslužné rutiny událostí, které jsou metody s podpisy (návratové typy volání úmluv a argumenty), které odpovídají událost, která se budou zpracovávat.Pro události COM konvence volání nemusí odpovídat; Viz Rozložení závislé události COM pod podrobnosti.
Zapojení obslužné rutiny události
Také v přijímač třída události funkci vnitřní __hook přidružit obslužné rutiny události a __unhook k oddělit z obslužné rutiny události.Lze připojit několik událostí na obslužné rutiny události nebo několik obslužné rutiny události.
[!POZNÁMKA]
Obvykle jsou dvě techniky umožnit přístup definice rozhraní zdroje událostí událost přijímač COM.První, jak je uvedeno níže, je sdílet společný soubor záhlaví.Druhým je použití #import s embedded_idl import kvalifikátor, tak, aby typ knihovny pro zdroj události zápisu do souboru .tlh s kód generován atribut zachovány.
Při aktivaci události
Požární událost jednoduše volejte metodu v rozhraní s __event klíčové zdroje událostí třídy.Pokud obslužné rutiny jste byl připojený k události, se nazývá obslužných rutin.
Kód události COM
Následující příklad ukazuje, jak události COM třídy požáru.Kompilace a spuštění příkladu, naleznete v poznámkách v kódu.
// 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;
A potom 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;
}
};
A potom klienta:
// 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;
}
Výsledek
MyHandler1 was called with value 123.
MyHandler2 was called with value 123.
Rozložení závislé COM události
Rozložení závislost je problém pouze pro programování v modelu COM.V nativní a spravované události zpracování podpisů (návratový typ konvence volání a argumenty) obslužných rutin musí odpovídat jejich události, ale popisovač názvy nemají odpovídající jejich události.
V COM zpracování událostí, při nastavení však layout_dependent parametr event_receiver na true, jméno a podpis odpovídající vynucena.To znamená, že jména a podpisy obslužných rutin událostí přijímač musí přesně odpovídat jména a podpisy události, které jsou připojený.
Při layout_dependent je nastavena na false, volající úmluvy a úložiště tříd (virtuální, statické a atd.) můžete kombinaci a shodu mezi pálení metody událostí a hooking metody (své delegáty).Je mírně účinnější mít layout_dependent=true.
Předpokládejme například, že IEventSource je definován mít následující metody:
[id(1)] HRESULT MyEvent1([in] int value);
[id(2)] HRESULT MyEvent2([in] int value);
Předpokládejme, že zdroj události má následující tvar:
[coclass, event_source(com)]
class CSource : public IEventSource {
public:
__event __interface IEvents;
HRESULT FireEvent() {
MyEvent1(123);
MyEvent2(123);
return S_OK;
}
};
Všechny popisovače v přijímači událostí, připojený metody v IEventSource musí odpovídat jeho jméno a podpis, takto:
[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
}
};