COM에서 이벤트 처리
COM 이벤트 처리에서 각각 지정된 특성과 특성을 사용하여 event_source
이벤트 원본 및 event_receiver
이벤트 수신기를 type
=com
설정합니다. 이러한 특성은 사용자 지정, 디스패치 및 이중 인터페이스에 적절한 코드를 삽입합니다. 삽입된 코드를 사용하면 특성이 지정된 클래스가 COM 연결 지점을 통해 이벤트를 발생시키고 이벤트를 처리할 수 있습니다.
참고 항목
네이티브 C++의 이벤트 특성은 표준 C++와 호환되지 않습니다. 규칙 모드를 지정할 /permissive-
때 컴파일되지 않습니다.
이벤트 선언
이벤트 소스 클래스에서 인터페이스 선언의 __event
키워드(keyword) 사용하여 해당 인터페이스의 메서드를 이벤트로 선언합니다. 해당 인터페이스의 이벤트는 이를 인터페이스 메서드로 호출할 때 발생합니다. 이벤트 인터페이스의 메서드에는 매개 변수가 0개 이상 있을 수 있습니다(모두 매개 변수에 있어야 합니다). 반환 형식은 void 또는 모든 정수 계열 형식이 될 수 있습니다.
이벤트 처리기 정의
이벤트 수신기 클래스에서 이벤트 처리기를 정의합니다. 이벤트 처리기는 처리할 이벤트와 일치하는 서명(반환 형식, 호출 규칙 및 인수)이 있는 메서드입니다. COM 이벤트의 경우 호출 규칙이 일치하지 않아도 됩니다. 자세한 내용은 아래의 레이아웃 종속 COM 이벤트를 참조하세요.
이벤트 처리기를 이벤트에 연결
또한 이벤트 수신기 클래스에서는 내장 함수 __hook
를 사용하여 이벤트를 이벤트 처리기와 연결하고 __unhook
이벤트 처리기에서 이벤트를 연결 해제합니다. 한 이벤트 처리기에 여러 이벤트를 후크하거나 한 이벤트에 여러 이벤트 처리기를 후크할 수 있습니다.
참고 항목
일반적으로 COM 이벤트 수신기가 이벤트 소스 인터페이스 정의에 액세스할 수 있게 만드는 두 가지 방법이 있습니다. 첫 번째 방법은 아래와 같이 공용 헤더 파일을 공유하는 것입니다. 두 번째는 가져오기 한정자에서 embedded_idl
#import 사용하여 이벤트 원본 형식 라이브러리가 특성 생성 코드가 유지된 .tlh 파일에 기록되도록 하는 것입니다.
이벤트 발생
이벤트를 발생 하려면 이벤트 소스 클래스에서 키워드(keyword) 선언 __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;
}
출력
MyHandler1 was called with value 123.
MyHandler2 was called with value 123.
레이아웃 종속 COM 이벤트
레이아웃 종속성은 COM 프로그래밍에만 문제가 됩니다. 네이티브 및 관리되는 이벤트 처리에서 처리기의 서명(반환 형식, 호출 규칙 및 인수)은 해당 이벤트와 일치해야 하지만 처리기 이름은 해당 이벤트와 일치할 필요가 없습니다.
그러나 COM 이벤트 처리에서 매개 변수 event_receiver
를 true
layout_dependent
/>로 설정하면 이름과 서명 일치가 적용됩니다. 이벤트 수신기 및 후크 이벤트에 있는 처리기의 이름과 서명은 정확히 일치해야 합니다.
호출 규칙 및 스토리지 클래스(가상, 정적 등)로 설정false
되면 layout_dependent
발생 이벤트 메서드와 후킹 메서드(대리자) 간에 혼합 및 일치시킬 수 있습니다. 을 갖는 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
}
};
참고 항목
피드백
https://aka.ms/ContentUserFeedback
출시 예정: 2024년 내내 콘텐츠에 대한 피드백 메커니즘으로 GitHub 문제를 단계적으로 폐지하고 이를 새로운 피드백 시스템으로 바꿀 예정입니다. 자세한 내용은 다음을 참조하세요.다음에 대한 사용자 의견 제출 및 보기