Gestion des événements dans COM
Dans la gestion des événements COM, vous avez installé une source d'événements et un récepteur d'événements à l'aide de les attributs d' event_source et d' event_receiver , respectivement, en spécifiant type=COM.Ces attributs injectent un code approprié pour le personnalisé, l'ont, et des interfaces doubles à autoriser les classes auxquelles ils sont appliqués pour déclencher des événements et gèrent les événements via des points de connexion COM.
Déclaration d'événements
Dans une classe de source d'événements, utilisez le mot clé de __event sur une déclaration d'interface pour déclarer que les méthodes de l'interface en tant qu'événements.Les événements de cette interface sont déclenchés lorsque celle-ci est appelée comme des méthodes d'interface.Les méthodes sur des interfaces d'événement peut contenir zéro ou plus de paramètres (qui doivent toutes être des paramètres de dans ).le type de retour peut être void ou n'importe quel type intégral.
Définition de gestionnaires d'événements
Dans une classe de récepteur d'événements, vous définissez des gestionnaires d'événements, qui sont des méthodes avec des signatures (types de retour, conventions d'appel, et arguments) qui correspondent l'événement qu'ils géreront.Pour les événements COM, les conventions d'appel ne doivent pas correspondre ; consultez l' Événements COM de dépendant de disposition ci-dessous pour plus de détails.
Le raccordement des gestionnaires d'événements aux événements
Également dans une classe de récepteur d'événements, vous utilisez la fonction intrinsèque __hook pour associer des événements aux gestionnaires d'événements et __unhook pour dissocier des événements des gestionnaires d'événements.Vous pouvez connecter plusieurs événements à un gestionnaire d'événements, ou plusieurs gestionnaires d'événements à un événement.
[!REMARQUE]
En général, il existe deux techniques de permettre un récepteur d'événements COM aux définitions d'interface de l'événement d'accès.Le premier, comme indiqué ci-dessous, est de partager un fichier d'en-tête communs.Le deuxième est d'utiliser #import avec le qualificateur d'importation d' embedded_idl , afin que la bibliothèque de types de source d'événement soit écrite dans le fichier .tlh avec le code attribut-généré conservé.
Événements de mise à déclencher
Pour déclencher un événement, appelez simplement une méthode dans l'interface déclarée avec la classe de source de mot clé d' __event dans l'événement.Si les gestionnaires ont été accrochés à l'événement, les gestionnaires sont appelés.
Code d'événement COM
l'exemple suivant montre comment déclencher un événement dans une classe COM.Pour compiler et exécuter l'exemple, consultez les commentaires du code.
// 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;
Puis le serveur :
// 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;
}
};
Puis le 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;
}
Sortie
MyHandler1 was called with value 123.
MyHandler2 was called with value 123.
Événements COM de dépendant de disposition
La dépendance de disposition est uniquement un problème pour la programmation COM.En code natif et gestion des événements managée, les signatures (type de retour, convention d'appel, et arguments) des gestionnaires doivent satisfaire leurs événements, mais les noms de gestionnaire ne doivent pas correspondre à leurs événements.
Toutefois, dans la gestion des événements COM, lorsque vous affectez au paramètre layout_dependent d' event_receiver à true, au nom et à la correspondance de signature est appliquée.Cela signifie que les noms et les signatures du récepteur de gestionnaires dans l'événement doivent correspondre exactement les noms et les signatures des événements auxquels ils sont accrochés.
Si layout_dependent est défini à false, la convention d'appel et la classe de stockage (virtuel, statique, etc.) peut être associée et mise en correspondance entre la méthode d'événement de mise à déclencher et les méthodes de raccordement (ses délégués).il est légèrement plus efficace d'avoir le layout_dependent=true.
Par exemple, supposons qu' IEventSource est défini pour disposer les méthodes suivantes :
[id(1)] HRESULT MyEvent1([in] int value);
[id(2)] HRESULT MyEvent2([in] int value);
Supposez que la source d'événement a la forme suivante :
[coclass, event_source(com)]
class CSource : public IEventSource {
public:
__event __interface IEvents;
HRESULT FireEvent() {
MyEvent1(123);
MyEvent2(123);
return S_OK;
}
};
Ensuite, en cas le récepteur, tout gestionnaire accroché à une méthode dans IEventSource doit faire correspondre son nom et signature, comme suit :
[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
}
};