Ereignisbehandlung in COM
In COM-Ereignisbehandlung installierten Sie einen Ereignisquellen- und Ereignisempfänger mithilfe der event_source und event_receiver-Attribute type=COMerzeugt haben.Diese Attribute fügen Sie den Code für ein benutzerdefiniertes vorwärts und duale Schnittstellen weiter, um die Klassen auf die sie angewendet werden, um Ereignisse und Behandeln von Ereignissen durch COM-Verbindungspunkte auszulösen.
Deklarieren von Ereignissen
In einer Ereignisquellen - Klasse verwenden Sie das __event-Schlüsselwort für eine Schnittstellendeklaration, dass die Methoden der Schnittstelle als Ereignisse zu deklarieren.Mithilfe dieser Schnittstelle werden Ereignisse ausgelöst, wenn Sie sie als Schnittstellenmethoden aufgerufen wird.Methoden für Ereignisschnittstellen können null oder mehr Parameter haben (die in wenn alle Parameter sind).Der Rückgabetyp kann ungültig oder ein ganzzahliger Typ sein.
Definieren von Ereignishandlern
In einer Ereignisempfänger Klasse definieren Sie Ereignishandler, die Methoden mit Signaturen (Rückgabetypen, Argumente und Aufrufkonventionen), die Übereinstimmung, das sie sind das Ereignis behandelt.Um COM-Ereignisse müssen Aufrufkonventionen nicht übereinstimmen. Ausführliche Informationen finden Sie unten Abhängige COM Lay-out von Ereignissen .
Ereignishandler für Ereignisse haken
Auch in einer Ereignisempfänger Klasse, verwenden Sie die systeminterne Funktion, um __hook-Ereignissen mit Ereignishandlern und __unhook zuzuordnen, um Ereignisse von den Ereignishandlern zu trennen.Sie können mehrere Ereignisse zu verknüpfen oder einem Ereignishandler zu einigen Ereignishandlern für ein Ereignis.
Hinweis |
---|
Normalerweise gibt es zwei Möglichkeiten, ein COM-Ereignis empfänger für den Zugriff auf ereignisquellen-Schnittstellendefinitionen zu ermöglichen.Das erste, wie unten dargestellt, ist eine allgemeine Headerdatei freizugeben.Das zweite Wert ist, #import mit dem embedded_idl Import qualifizierer zu verwenden, sodass die Ereignisquellen typbibliothek auf die TLH-Datei mit dem ATTRIBUTE-generierten beibehaltenen Code geschrieben wird. |
Auslösen-Ereignisse
Um ein Ereignis auszulösen, rufen Sie einfach eine Methode in der Schnittstelle an, die im Fall von der Klasse deklariert wurde __event-Schlüsselworts Sources.Wenn Handler an das Ereignis gehakt wurden, werden die Handler aufgerufen.
COM-Ereigniscode
Im folgenden Beispiel wird gezeigt, wie ein Ereignis in einer COM-Klasse auslöst.Um das Beispiel zu kompilieren und auszuführen, finden Sie in den Kommentaren im Code an.
// 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;
Und dann der 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;
}
};
Und dann der 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.
Abhängige COM Lay-out von Ereignissen
Lay-outs abhängigkeit ist nur ein Problem für COM-Programmierung.In systemeigenem und verwaltetem in der Ereignisbehandlung müssen die Signaturen (Aufrufkonvention, Rückgabetyp und die Argumente) der Handler deren Ereignisse entsprechen, aber die Handler Namen müssen deren Ereignisse nicht übereinstimmen.
In COM-Ereignisbehandlung, wenn Sie legen das layout_dependent-Parameter aus event_receiver zu true, um Namen und Signatur übereinstimmen erzwungen werden.Dies bedeutet, dass die Namen und Signatur des Empfängers der Handler im Ereignisprotokoll die Namen und die Signaturen der Ereignisse genau übereinstimmen müssen, auf die sie gehakt werden.
Wenn layout_dependent, wird auf falseder Aufrufkonvention und Speicherklasse (virtual statisch usw.) kann zwischen der Auslösung Klickereignis Methode und ihre Methoden (hakenden den Delegaten) kombiniert und entsprochen werden.Es ist etwas effizienter, layout_dependent=truehaben.
Angenommen, IEventSource definiert wird, um die folgenden Methoden:
[id(1)] HRESULT MyEvent1([in] int value);
[id(2)] HRESULT MyEvent2([in] int value);
Angenommen, die Ereignisquelle das folgende Format aufweist:
[coclass, event_source(com)]
class CSource : public IEventSource {
public:
__event __interface IEvents;
HRESULT FireEvent() {
MyEvent1(123);
MyEvent2(123);
return S_OK;
}
};
Anschließend muss im Ereignisprotokoll Empfänger, jeder Handler an eine Methode in IEventSource gehakt wird, ihren Namen und Signatur übereinstimmen:
[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
}
};