日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【转载】COM 连接点

發布時間:2025/3/20 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转载】COM 连接点 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文:COM 連接點

?

CLR 完全介紹?COM 連接點?Thottam R. Sriram

來自:http://msdn.microsoft.com/zh-cn/magazine/cc163361.aspx#S1

代碼下載位置:?CLRInsideOut2007_09.exe?(252 KB)?

Browse the Code Online

目錄 示例方案?
在 COM 服務器上創建連接點?
客戶端?
獲取 Add 和 ConnectionPoint 接口?
托管客戶端?
總結? COM 中的典型方案是讓客戶端對象實例化服務器對象,然后調用這些對象。然而,沒有一種特殊機制的話,這些服務器對象將很難轉向并回調到客戶端對象。COM 連接點便提供了這種特殊機制,實現了服務器和客戶端之間的雙向通信。使用連接點,服務器能夠在服務器上發生某些事件時調用客戶端。 有了連接點,服務器可通過定義一個接口來指定它能夠引發的事件。服務器上引發事件時,要采取操作的客戶端會向服務器進行自行注冊。隨后,客戶端會提供服務器所定義接口的實現。 客戶端可通過一些標準機制向服務器進行自行注冊。COM 為此提供了 IConnectionPointContainer 和 IConnectionPoint 接口。 COM 連接點服務器的客戶端可用 C++ 和 C# 托管代碼來編寫。C++ 客戶端會注冊一個類的實例,該類提供了接收器接口的實現。托管客戶端會注冊單個事件的委托,因而會按每個事件通知方法創建單個接收器。在托管領域中,客戶端自行注冊有兩種方法 — 我會在本專欄的后面部分詳細介紹這兩種方法。 Web 上幾乎很少有事件和互操作的可用示例。在本專欄中,我將重點討論創建活動模板庫 (ATL) 連接點服務器。這包括公開 COM 方法、定義由客戶端實現的事件接口,以及實現引發服務器事件的代碼。我還會向您展示提供了接收器實現的示例 C++ 客戶端,還有示例 C# 客戶端,以及您可以注冊并偵聽服務器事件的兩種方法。最后,我會介紹實現托管事件接收器的推薦方式。


示例方案 在我的方案中,服務器會公開 COM 方法: HRESULT Add(int nFirst, int nSecond) 服務器還會定義 ConnectionPointContainer 和連接點,以便客戶端能夠向該服務器進行注冊。此外,服務器會定義一個接口 _IAddEvents,該接口中有兩個方法: HRESULT AdditionStarted() HRESULT AdditionCompleted(int nResult) 客戶端會提供 _IAddEvents 的實現,并調用服務器上的 Add 方法。服務器會觸發客戶端上的 AdditionStarted 和 AdditionCompleted 方法,以便適時向客戶端發送通知。然后,客戶端會執行與這些事件相關的適當操作。

?

在 COM 服務器上創建連接點 在 2007 年 1 月期“CLR 完全介紹”中,我詳細介紹了如何創建簡單的 ATL COM 服務器(參見msdn.microsoft.com/msdnmag/issues/07/01/CLRInsideOut)。本期專欄假設您已經歷了創建名為 ATLConnectionPointServer 的 ATL COM 服務器這一過程。如果還沒有經歷的話,您可能需要在繼續之前先閱讀早期的專欄。 現在,您需要定義由服務器實現的 COM 接口,并使之成為連接點。在此 COM 服務器的基礎上創建連接點的過程非常簡單。要執行此操作,請打開 Visual Studio??中的“類視圖”,創建一個簡單的 ATL 對象。只需右鍵單擊 ATLConnectionPointServer 并添加一個類,選擇一個簡單的 ATL 對象,然后將類命名為 Add。按向導逐步操作時,請務必選擇“Supports: Connection Points”(支持:連接點)。 您現在便具備了可從客戶端調用的服務器接口 IAdd。如果您要構建服務器,您會發現此處定義了兩個接口。一個是實現 IDispatch 的 IAdd,另一個則是調度接口 _IAddEvents。 下一步是將稱為 Add 的新方法添加到接口 IAdd。它會接受兩個整數參數并返回一個 HRESULT。要執行此操作,請右鍵單擊 IAdd,選擇“Add Methods”(添加方法)。方法的簽名為: HRESULT Add([in] int nFirst, [in] int nSecond) 現在,請打開 ATLConnectionPointServer.idl,將方法 AdditionStarted 和 AdditionCompleted 添加到 _IAddEvents 接口,如圖 1所示。 Figure?1?添加 AdditionStarted 和 AdditionCompleted library ATLConnectionPointServerLib { importlib("stdole2.tlb"); [ uuid(7F45FEA6-4D7C-489C-A852-19BA8B29D8AB), helpstring("_IAddEvents Interface") ] dispinterface _IAddEvents { properties: methods: [id(1), helpstring("AdditionStarted")]HRESULT AdditionStarted(); [id(2), helpstring("AdditionStarted")] HRESULT AdditionCompleted(int nResult); }; [ uuid(15B6C26A-0416-4C8F-9533-89F318355E31), helpstring("Add Class") ] coclass Add { [default] interface IAdd; [default, source] dispinterface _IAddEvents; }; }; 如果您在此時編譯項目,則會發現一個自動生成的文件 _IAddEvents_CP.h。此文件由 ATL 生成,包含一個空的 CProxy_IAddEvents 類。這個便是在連接點完成及掛接時觸發事件的類。 轉到“類視圖”,右鍵單擊 CAdd,選擇“添加”|“添加連接點”。在隨后的向導中,選擇 _IAddEvents。如果您此刻打開 _IAddEvents_CP.h 文件,它將包含為兩個方法(即 Fire_AdditionStarted 和 Fire_AdditionCompleted)自動生成的代碼。這是客戶端接收器對象向服務器進行注冊時回調到這些對象的代碼。 現在,您即將完成服務器的實現過程。剩下的所有步驟便是實現服務器上的 Add 方法,并觸發用于觸發服務器事件的點。 打開 Add.cpp,為您添加的 Add 方法提供一個實現。該實現如下所示: STDMETHODIMP CAdd::Add(int nFirst, int nSecond) { // Fire AdditionStarted event Fire_AdditionStarted(); int nResult = nFirst + nSecond; Sleep(1000); // simulate the addition taking a long time // Fire AdditionCompleted event Fire_AdditionCompleted(nResult); return S_OK; } 現在即可編譯解決方案,您的服務器已準備就緒。

?

客戶端 現在您可以轉到客戶端。我會從討論 C++ 客戶端開始,然后轉到托管客戶端。 客戶端負責五個主要任務:
  • 它必須向您提供 _IAddEvents 接口的實現。
  • 它必須向您提供指向服務器 Add 接口的接口指針。
  • 它必須獲取 Add 接口 ConnectionPoinContainer 的 ConnectionPoint,并添加接收器接口。
  • 它必須調用 Add 方法,并等待服務器事件被觸發。
  • 它必須徹底關閉并退出。
要實現客戶端,請打開名為 ConnectionPointClient 的新 C++ 項目,并向該項目添加新的 C++ 源文件。向該項目添加 ATLConnectionPointServer.h 和 ATLBase.h 文件。接收器會實現服務器所定義的 _IAddEvents。此接口中有兩個方法:AdditionStarted 和 AdditionCompleted。這兩個方法的實現如圖 2?所示。 Figure?2?AdditionStarted 和 AdditionCompleted class CSink : _IAddEvents { private: DWORD m_dwRefCount; public: CSink::CSink() {m_dwRefCount = 0;} CSink::~CSink() {} HRESULT STDMETHODCALLTYPE AdditionStarted() { printf("C++ SINK: Addition started event fired ... \n"); return S_OK; }; HRESULT STDMETHODCALLTYPE AdditionCompleted(int nResult) { printf("C++ SINK: Addition completed event fired ... \n"); printf("C++ SINK: Addition result: %d \n",nResult); return S_OK; }; ... 為方便起見,我已經實現了客戶端上的調度接口;示例代碼提供了自動執行該操作的 ATL 客戶端。此實現中的接收器只打印它已被調用的事實及添加完成后的結果。現在您的接收器已實現,可供使用。

?

獲取 Add 和 ConnectionPoint 接口 現在已經實現了接收器,讓我們來看看將向服務器注冊此接收器的客戶端。該客戶端負責處理三個主要任務。
  • 獲取指向服務器 Add 接口的接口指針。
  • 從 Add 接口獲取 ConnectionPointContainer 的 ConnectionPoint。
  • 向服務器注冊接收器接口。
首先,請按如下方式獲取服務器的接口 IAdd: CoInitialize(NULL); hr = CoCreateInstance( CLSID_Add, NULL, CLSCTX_ALL, IID_IAdd, (void **)&pAdd); if(hr != S_OK) { return; } 然后,您必須獲取服務器上的連接點,以便可以用它來注冊接收器實現。要執行此操作,請按如下方式從 IAdd 接口獲取 ConnectionpointContainer: // Using the interface for add, // query for IConnectionPointContainer interface hr = pAdd->QueryInterface( IID_IConnectionPointContainer,(void **)&pCPC); if ( !SUCCEEDED(hr) ) { return; } 現在您可以到達 ConnectionPoint: // Using the IConnectionPointContainer, // get the IConnectionPoint interface hr = pCPC->FindConnectionPoint(DIID__IAddEvents,&pCP); if ( !SUCCEEDED(hr) ) { return; } 此刻,客戶端必須創建其接收器實現的一個實例,并向服務器注冊該實例。為此,客戶端會創建接收器的一個實例,并按如下方式獲取其 IUnknown 接口指針: // Create an instance of the sink object to pass // to the server pSink = new CSink(); if ( NULL == pSink ) { return; } // Get the interface pointer to CSink's IUnknown pointer, which you // will pass to the server hr = pSink->QueryInterface (IID_IUnknown,(void **)&pSinkUnk); if(!SUCCEEDED(hr)) { return; } 您即將完成客戶端。其余的所有步驟便是向服務器注冊接收器,調用服務器,然后進行清理??蛻舳藭蚍掌髯越邮掌鞯膶嵗?#xff1a; // Pass the sink interface to the server through the Advise hr = pCP->Advise(pSinkUnk,&dwAdvise); if(!SUCCEEDED(hr)) { return; } 此刻,您已經向服務器注冊了客戶端接收器接口。 客戶端會調用服務器上的 Add 方法,并將該方法所需的兩個參數傳遞給它。添加的結果會通過 AdditionCompleted 事件返回,而不是直接從 Add 調用返回?,F在請調用您獲得的 IAdd 接口指針上的 Add 方法。 pAdd->Add(1, 5); 此調用應觸發隨之調用客戶端的事件。此時,您可以通過釋放您獲得的所有接口來清理客戶端(參見圖 3)。 Figure?3?清理客戶端 // Release the IConnectionPointContainer interface. if(pCPC != NULL) pCPC->Release(); // Unadvise the event call back we registered. if(pCP != NULL) { pCP->Unadvise(dwAdvise); } if(pSinkUnk != NULL) { pSinkUnk->Release(); } // Disconnect from the server. if(pCP != NULL) { pCP->Release(); } // Release interfaces. if(pAdd != NULL) { pAdd->Release(); } CoUninitialize(); return; 您最終完成了客戶端?,F在,您可以編譯并執行客戶端: cl COMConnectionPointClient.cpp 執行時,您會看到以下輸出: C++ SINK: Addition started event fired ... C++ SINK: Addition completed event fired ... C++ SINK: Addition result: 6

?

托管客戶端 現在,我想討論一下從托管代碼使用同一 ConnectionPointServer 的情況。托管客戶端比 COM 客戶端簡單得多。實現該客戶端有兩種方法。首先,我將重點討論推薦的方法。 首先,通過將 Microsoft??.NET Framework 類型庫用于程序集轉換器工具 tlbimp.exe,將服務器 DLL 導入到托管代碼,以獲得 ATLConnectionPointServerLib.dll,這一過程通過運行以下命令來實現: tlbimp ATLConnectionPointServer.dll 您需要引用托管項目中生成的程序集,然后提供用于客戶端接收器接口的實現,如圖 4?所示。ManagedSink 類實現了 _IAddEvents 接口中所定義的兩個方法,AdditionStarted 和 AdditionCompleted。完成后,您的接收器事件處理程序便完成了,可供使用(與 COM 客戶端比起來,它看上去幾乎太簡單了,對吧?)。 Figure?4?提供接收器接口的實現 public class ManagedSink :_IAddEvents { public void AdditionStarted() { Console.WriteLine("C# SINK: Addition started event fired ..."); } public void AdditionCompleted(int nResult) { Console.WriteLine("C# SINK: Addition completed event fired ..."); Console.WriteLine("C# SINK: Addition result: {0}", nResult); return; } }; 與 COM 客戶端一樣,您必須向服務器注冊接收器,以便服務器能夠在觸發事件時調用該接收器。然而,托管客戶端向服務器進行自行注冊的方式會有所不同。 COM 客戶端向服務器注冊了已實現接口 _IAddEvents 的接收器對象實例。提醒一下,以下調用注冊了 COM 客戶端: // Pass the sink interface to the server through the Advise hr = pCP->Advise(pSinkUnk,&dwAdvise); if(!SUCCEEDED(hr)) { return;} 使用托管客戶端,您可以向服務器將單個方法作為委托注冊。要實現這一點,您需要創建接收器對象的實例: ManagedSink ms = new ManagedSink(); 創建服務器對象實例,并單獨添加 AdditionStarted 和 AdditionCompleted 事件處理程序,如下所示: AddClass a = new AddClass(); a.AdditionStarted += ms.AdditionStarted; a.AdditionCompleted += ms.AdditionCompleted; 客戶端會向服務器為每個事件處理程序注冊兩個不同的接口。要添加到客戶端委托的先前調用會在客戶端的運行庫可調用包裝 (RCW) 上添加一個引用計數。調用完成后,必須通過刪除事件處理程序來釋放該引用計數,如下所示: a.Add(1, 5); a.AdditionStarted -= ms.AdditionStarted; a.AdditionCompleted -= ms.AdditionCompleted; 最后,編譯 ManagedClient.cs: csc /r:ATLConnectionPointServerLib.dll ManagedClient.cs 并運行可執行文件。您會看到以下輸出: C# SINK: Addition started event fired ... C# SINK: Addition completed event fired ... C# SINK: Addition result: 6

?

總結 編寫用于 ATL 調度接口的客戶端實現稍微有點復雜。我此處討論的示例特意通過使用其本身的調用實現來解決該復雜性。 我要感謝 Cosmin Radu、Ladi Prosek、Mason Bendixen、Varun Sekhri 和 Claudio Caldato,感謝他們為本期專欄的制作提供幫助并提出寶貴意見。

轉載于:https://www.cnblogs.com/zhehan54/p/5909760.html

總結

以上是生活随笔為你收集整理的【转载】COM 连接点的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。