深刻解析C++法式中激起事宜和COM中的事宜處置。本站提示廣大學習愛好者:(深刻解析C++法式中激起事宜和COM中的事宜處置)文章只能為提供參考,不一定能成為您想要的結果。以下是深刻解析C++法式中激起事宜和COM中的事宜處置正文
本機 C++ 中的事宜處置
在處置本機 C ++ 事宜時,您分離應用 event_source 和 event_receiver 特征設置事宜源和事宜吸收器,並指定 type=native。這些特征許可運用它們的類在本機的非 COM 高低文中激起和處置事宜。
聲明事宜
在事宜源類中,對一個辦法聲明應用 __event症結字可將該辦法聲明為事宜。請確保聲明該辦法,但不要界說它;如許做會發生編譯器毛病,由於將該辦法轉換為事宜時編譯器會隱式界說它。本機事宜可所以帶有零個或多個參數的辦法。前往類型可所以 void 或任何整型。
界說事宜處置法式
在事宜吸收器類中,可界說事宜處置法式,這些處置法式是具有與它們將處置的事宜婚配的簽名(前往類型、挪用商定和參數)的辦法。
將事宜處置法式掛鉤到事宜
異樣在事宜吸收器類中,可以使用外部函數 __hook 將事宜與事宜處置法式聯系關系,並可以使用 __unhook 撤消事宜與事宜處置法式的聯系關系。您可將多個事宜掛鉤到一個事宜處置法式,或將多個事宜處置法式掛鉤到一個事宜。
激起事宜
若要激起事宜,只需挪用聲明為事宜源類中的事宜的辦法便可。假如處置法式已掛鉤到事宜,則將挪用處置法式。
本機 C++ 事宜代碼
以下示例演示若何在本機 C++ 中激起事宜。若要編譯並運轉此示例,請參考代碼中的正文。
示例代碼
// evh_native.cpp #include <stdio.h> [event_source(native)] class CSource { public: __event void MyEvent(int nValue); }; [event_receiver(native)] class CReceiver { public: void MyHandler1(int nValue) { printf_s("MyHandler1 was called with value %d.\n", nValue); } void MyHandler2(int nValue) { printf_s("MyHandler2 was called with value %d.\n", nValue); } void hookEvent(CSource* pSource) { __hook(&CSource::MyEvent, pSource, &CReceiver::MyHandler1); __hook(&CSource::MyEvent, pSource, &CReceiver::MyHandler2); } void unhookEvent(CSource* pSource) { __unhook(&CSource::MyEvent, pSource, &CReceiver::MyHandler1); __unhook(&CSource::MyEvent, pSource, &CReceiver::MyHandler2); } }; int main() { CSource source; CReceiver receiver; receiver.hookEvent(&source); __raise source.MyEvent(123); receiver.unhookEvent(&source); }
輸入:
MyHandler2 was called with value 123. MyHandler1 was called with value 123.
COM 中的事宜處置
在 COM 事宜處置中,您應用 event_source 和 event_receiver 特征分離設置事宜源和事宜吸收器,並指定 type=com。這些特征為自界說接口、調劑接口和兩重接口注入響應的代碼,從而使這些接口可以或許運用到的類激起事宜並經由過程 COM 銜接點處置事宜。
聲明事宜
在事宜源類中,在接口聲明上應用 __event 症結字以將該接口的辦法聲明為事宜。當您將該接口的事宜作為接口辦法挪用時,將激起這些事宜。事宜接口上的辦法可以有零個或多個參數(應滿是 in 參數)。前往類型可所以 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; }
輸入
MyHandler1 was called with value 123. MyHandler2 was called with value 123.
依附於結構的 COM 事宜
結構依附性只是 COM 編程中的一個成績。在本機和托管事宜處置中,處置法式的簽名(前往類型、挪用商定和參數)必需與其事宜婚配,但處置法式的稱號不用與其事宜婚配。
然則,在 COM 事宜處置中,假如將 event_receiver 的 layout_dependent 參數設置為 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 } };