이벤트 처리에 대 한 COM
COM에서 이벤트 처리를 사용 하 여 이벤트 소스와 이벤트 수신기를 설정 하 여 해당 event_source 및 event_receiver 각각 지정 특성 type=com.이들이 특성은 적절 한 코드를 사용자 지정, 디스패치 및 이중 인터페이스의 클래스는 COM 연결 지점을 통해 이벤트를 처리 하 고 이벤트 적용 삽입 합니다.
이벤트 선언
이벤트 소스 클래스에서 사용 하는 __event 키워드에는 해당 인터페이스의 메서드를 이벤트로 선언 하는 인터페이스 선언입니다.해당 인터페이스의 이벤트를 해당 인터페이스 메서드로 호출 시 발생 합니다.이벤트 인터페이스의 메서드는 0 개 이상의 매개 변수가 있을 수 있습니다 (모두 해야 하는 에서 매개 변수)입니다.반환 형식은 void 또는 모든 정수 계열 형식이 될 수 있습니다.
이벤트 처리기 정의
이벤트 수신기 클래스에서 처리 하려는 이벤트와 시그니처 (반환 형식, 호출 규칙 및 인수) 메서드는 이벤트 처리기를 정의 합니다.COM 이벤트에 대 한 호출 규칙이 일치 하지 않아도 됩니다. 참조 하십시오 레이아웃 종속 COM 이벤트 아래의 세부 사항에 대 한.
이벤트에 이벤트 처리기 후크
또한 이벤트 수신기 클래스에서 내장 함수를 사용 하면 __hook 이벤트와 이벤트 처리기를 연결 하 고 __unhook 이벤트 처리기에서 이벤트 연결을 해제 하려면.이벤트 처리기에 여러 이벤트 또는 여러 이벤트 처리기를 이벤트에 연결할 수 있습니다.
[!참고]
일반적으로 COM 이벤트 수신기에서 이벤트 소스 인터페이스 정의 액세스할 수 있도록 하는 두 가지 방법입니다.첫째, 아래와 같이 공용 헤더 파일을 공유할 것입니다.두 번째 사용 하는 것 # import 에 embedded_idl 이벤트 원본 형식 라이브러리 특성으로 생성 된 코드와 보존.tlh 파일에 쓸 수 없도록 한정자를 가져옵니다.
이벤트를 발생 시키는
이벤트를 발생 시키는 메서드를 선언 하는 인터페이스에 호출 하기만 하면 됩니다 있는 __event 키워드는 이벤트 원본 클래스입니다.처리기가 이벤트에 후크된 경우 처리기가 호출 됩니다.
COM 이벤트 코드
다음 예제는 COM 클래스에서 이벤트를 발생 시키는 방법을 보여 줍니다.컴파일 및이 예제를 실행 하려면 코드의 주석을 참조 하십시오.
// 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;
및 다음 서버:
// 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;
}
};
및 다음 클라이언트:
// 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.
레이아웃 종속 COM 이벤트
레이아웃 종속 COM 프로그래밍에만 있는 문제입니다.네이티브 및 관리 되는 이벤트 처리를 해당 이벤트 처리기의 시그니처 (반환 형식, 호출 규칙 및 인수)과 일치 해야 하지만 처리기 이름은 이벤트와 일치할 필요는 없습니다.
그러나 설정할 때 COM 이벤트 처리에 layout_dependent 매개 변수를 event_receiver 에 true, 이름 및 시그니처가 일치 하는 적용.이벤트 이름 및 시그니처를 연결 된 이벤트의 수신기 정확 하 게 일치 해야 합니다 이름 및 시그니처는 처리기의 따라서.
때 layout_dependent 으로 설정 false, 호출 규칙 및 저장소 클래스 (가상, 정적, 등)을 혼합 하 사이 일치 하는 이벤트 메서드와 후크 메서드 (대리자)입니다.하는 것이 보다 효율적입니다 layout_dependent=true.
예를 들어 IEventSource 는 다음과 같은 메서드를 정의 합니다.
[id(1)] HRESULT MyEvent1([in] int value);
[id(2)] HRESULT MyEvent2([in] int value);
이벤트 소스의 형식은 다음과 같습니다 한다고 가정 합니다.
[coclass, event_source(com)]
class CSource : public IEventSource {
public:
__event __interface IEvents;
HRESULT FireEvent() {
MyEvent1(123);
MyEvent2(123);
return S_OK;
}
};
이벤트 수신기에서 처리기 후크 다음 메서드를 IEventSource 이름 및 시그니처는 다음과 같이 일치 해야 합니다.
[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
}
};