URL: http://zxjgoodboy.blog.sohu.com/74249273.html
什麼是代理和存根 ?
打個比方,你到自動取款機上去取款;你就是客戶,取款機就是你的代理;你不會在乎
錢具體放在那裡,你只想看到足夠或更多的錢從出口出來(這就是com的透明性)。你同銀行之間的操作完全是取款機代理實現。 你的取款請求通過取款機,傳到另一頭,銀行的伺服器,他也沒有必要知道你在哪兒取錢,他所關心的是你的身份,和你取款多少。當他確認你的許可權,就進行相應的操作,返回操作結果給取款機,取款機根據伺服器返回結果,從保險柜裡取出相應數量的錢給你。你取出卡後,操作完成。 取款機不是直接同伺服器串連的,他們之間還有一個“存根”,取款機與存根通訊,伺服器與存根通訊。從某種意義上說存根就是伺服器的代理。
ASPectratio="t" v:ext="edit">
圖1 組件間通訊
如兩個組件之間不是直接通訊,而是通過代理和存根來之間的通訊來間接實現的。圖中的channel是com庫的一部分。
COM裡,只有進程外組件才會用到代理(proxy)和存根(stub)。
代理在客戶的進程內建立,存根在組件com對象的進程中建立。 每個介面的每個函數都有自己的代理和存根。
為什麼要用代理和存根 ?
客戶為什麼要用代理和存根,而不直接同對象串連呢? 給你一個理由,對客戶來說,他與所有com對象的串連都是通過指標來調用的, 而對服務來說,調用對象的介面函數也是通過指標來完成的,然而,指標只有在同一進程內才會有效。這樣,代理和存根為了完成這個使命也就產生了。
代理和存根的作用不只這些,他還要打包所有的參數(包括介面指標),產生 RPC(遠程進程調用),通向另一個進程,或者對象運行所在的另一台機器。
圖2 代理的結構
所顯示的代理結構支援參數的標準列集。每個介面的代理實現了IRpcProxyBuffer介面,用於內聚各個部分之間的相互連信。當代理準備把已列集的參數傳遞過進程邊界時,他調用IRpcChannelBuffer 介面的方法(該介面由channel實現)。channel調用RPC運行庫使資料轉送到目的地。
圖3 存根的結構
如所示,每個介面的存根被串連到對象的相應介面上。chnnel分發傳入的訊息到適當的介面的存根。所有的組件通過IRpcChannelBuffer介面與chnnel交流,這個介面提供了與RPC運行庫的串連。
列集(marshalling)
說到代理和存根,自然少不了列集,什麼是列集?
列集,對函數參數進行打包處理得過程,因為指標等資料,必須通過一定得轉換,才能被另一組件所理解,列集完成後,RPC調用就會產生。可以說列集是一種資料格式的轉換方法。
列集有3種方式:
1. 類型庫列集
它可以列集與OLEAUTOMATION相容的任何介面,意思是你的介面的傳回值必須是HRESULT,所使用的參數的類型也應該是與C++的VARIANT結構相容。
2. 通過建立Stub / proxy DLL
這個DLL的源代由MIDL產生。你必須在伺服器和客戶機上都註冊這個DLL(這是標準的marshal 方式)使用吃方法時,最好把stub / proxy代碼編譯作為一個獨立的組件。
3. 自訂marshaling
自訂marshal要求在你的組件中必須實現IMarshal介面。當COM需要marchal時,他首先通過QueryInterface看你是否支援IMarshal介面,如果你實現了該介面,也就是說,由你控制了你的COM的所有參數和傳回值的打包、解包的方法模式。
代理和存根dll的建立
使用工具MIDL,對一個IDL檔案,MIDL會分析自動產生相應的代理/存根 DLL的相關檔案。
怎麼使用代理和存根
對於你來說代理和存根的使用是透明的,你根本不用去關心如何使用他們,com庫會知道怎麼做。
[ 註:本文中的圖均取自MSDN ]
歡迎你閱讀此文,並留下寶貴的意見,討論會讓問題瞭解更加得深入,如果你要引用該文,請留下我的名字。 謝謝大家,共同進步。
如何組建代理程式/存根dll
1.編譯idl 檔案,產生*_i.h、*_i.c、*_p.c、dlldata.c 和 *ps.def 檔案。
*.h為介面說明標頭檔;
*_p.c為介面代理和存根的實現檔案;
*_i.c為定義所有GUID描述符的檔案;
dlldata.c包含代理/存根程式的入口函數及類廠所需的資料結構。
如果沒有.def檔案,也可以自己編輯一個。格式如下:
LIBRARY "testProxy.dll"
EXPORTS
DllGetClassObject @1 PRIVATE
DllCanUnloadNow @2 PRIVATE
GetProxyDllInfo @3 PRIVATE
DllRegisterServer @4 PRIVATE
DllUnregisterServer @5 PRIVATE
2. 建立一個新的win32應用程式:
程式類型為dll:
3. 加入上述五個檔案;
4.設定工程編譯屬性:
1)在Preprocessor Definitions 中加入:REGISTER_PROXY_DLL
2)在Linker->Input->Module Definition file指定模組定義檔案路徑:*ps.def;
3)在 Linker->Input->Additional Dependencies中加入:rpcrt4.lib uiid.lib
5.編譯,如果出現如下錯誤:
fatal error C1189: #error : You need a Windows 2000 or later to run this stub because it uses these features:
在Preprocessor Definitions加入:_WIN32_WINNT=0x0500v