【转载】COM 连接点
生活随笔
收集整理的這篇文章主要介紹了
【转载】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 服務器上創建連接點 在 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 方法,并等待服務器事件被觸發。
- 它必須徹底關閉并退出。
?
獲取 Add 和 ConnectionPoint 接口 現在已經實現了接收器,讓我們來看看將向服務器注冊此接收器的客戶端。該客戶端負責處理三個主要任務。- 獲取指向服務器 Add 接口的接口指針。
- 從 Add 接口獲取 ConnectionPointContainer 的 ConnectionPoint。
- 向服務器注冊接收器接口。
?
托管客戶端 現在,我想討論一下從托管代碼使用同一 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 连接点的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 立长志
- 下一篇: SHELL脚本--简介