Inside COM讀書筆記—–ExE中的伺服器

來源:互聯網
上載者:User
1.      不同的進程

每一個EXE檔案都將在不同的進程中運行,而每一個進程都有其自己的進程空間。一個進程空間中的邏輯地址0X0000ABBA所對應的物理地址將不同於另外一個進程中同一邏輯地址所對應的物理地址。所以若一個進程將地址0X0000ABBA傳給另一個進程,後者訪問到的邏輯單元將不是前一個進程所希望的。

同每一個EXE都有自己的進程不同,DLL將映射到連結他們的EXE檔案的進程空間中,因此DLL也被稱作進程中伺服器,而EXE則被稱作是進程外伺服器。在某些情況下,EXE也被稱作本機伺服器。

對於跨進程邊界的借口,需要考慮的:

  • 一個進程需要能夠調用另外一個進程中的函數
  • 一個進程需要能夠將資料傳遞給另外一個進程
  • 客戶無需關心他所訪問的伺服器是同處理序伺服程式還是進程外伺服器

 

本地程序呼叫

對於進程間的通訊,有幾種不同的方法,如動態資料交換(DDE)、具名管道以及共用記憶體等。COM所用的方法是本地程序呼叫(LPC)。LPC是同一機器上不同處理序間通訊的一種方法。LPC是如何工作呢?他們是由作業系統實現的,由於作業系統知道同每一個進程邏輯地址空間向對應的物理地址,因此作業系統可以調用任何進程的任何函數。

 

調整

調用EXE中的函數只是第一步,另外我們還需要一種方法將函數調用的參數從一個進程空間傳到另一個進程的地址空間中,這種方法稱為“調整”。LPC技術可以將資料從一個進程複製到另一個進程中去,需要其他一些資訊以將參數打包並傳遞給其他進程。比如對指標的處理將將不同於對整數的處理,將指標引用的結構賦值到另一個進程中去。

 

代理/存根DLL

當調用Win32函數時,系統實現上講調用一個DLL的函數,而此函數將通過LPC調用windows中的實際代碼,這種結構可以將使用者進程同Windows代碼隔離開。

COM使用的結構與此類似,客戶將同一個模仿組件的DLL進行通訊,這個DLL可以為客戶完成參數的調整及LPC調用。一個代理就是同另外一個組件行為相同的組件,代理必須是DLL形式,因為他們需要訪問客戶進程的地址空間以便對傳給介面函數的資料進行調整,組件還需要一個被稱為存根的DLL,以從客戶傳來的資料進行反調整。

 

2.      IDL/MIDL簡介

藉助IDL(介面定義語言)可以編寫介面的一個描述,然後用MIDL編譯器組建代理程式和存根DLL。

 

IDL介面描述舉例

//interface ISum

[

    object,

    uuid(B3B82DE4-4EA0-475F-A386-22C5DF7DC213),

    helpstring("IPrimeinterface"),

    oleautomation

]

interface ISum : IUnknown

{

    HRESULTSum(int x,
inty, [out, retval]int*
retval);

}

 

IDL的文法同C++並無太大的差異,其中object表示所定義的介面為一個com介面,關鍵字object是Microsoft對於IDL的一個擴充,第二個關鍵字uuid為相應介面的IID。第三個關鍵字用於將一個協助串放到一個類型庫中,

  •  Pointer_default關鍵字

使用IDL的目的是為了提供足夠的資訊,以便函數參數可以調整。Pointer_default關鍵字具有三個不同的選項

                        i.             Ref---將指標當成是引用對待,此時表示此指標將總是指向一個合法的地址,並可被反引用。不可為空,在調整前後他們將指向同一記憶體位址。

                      ii.             Unique---此類指標可以為空白,並且在函數內可以修改他們的值。但不能為之指定別名。

                     iii.             Ptr---此選項指定相應的指標就是一個c指標,此類指標可以是一個別名、可以為NULL並且其值可以被修改。

  •  IDL中輸入與輸出參數

MIDL可以使用in、out參數屬性對代理和存根代碼進一步最佳化。對於被標記為in的參數,MIDL將指導僅僅需要將此參數指從客戶傳遞給組件,存根代碼不需要送回任何值。Out關鍵字告訴MIDL相應的參數僅被用來從組件向客戶傳回有關的資料。代理不需要對輸出參數指進行調整也不需要將此值傳送給組件。

  • IDL中的字串

Com中對於字串的標準約定是使用Unicode字元及wchar_t。

  • IDL中的import關鍵字

Import用於將其他IDL檔案中的定義包含到當前檔案中,同C++中的預先處理指令#include命令式類似的,

 

MIDL編輯器

           可以用如下命令編譯idl檔案

           Midl foo.idl

           Idl檔案有一個library語句,將產生一個類型庫。

 

代理/存根的登記

3.      本機伺服器的實現

EXE無法輸出函數,所有在進程中伺服器依賴的一些輸出函數:

DllGetClassObjectPRIVATE

    DllRegisterServerPRIVATE

    DllUnregisterServerPRIVATE

    DllCanUnloadNow  PRIVATE

需要找到替代物,替換DllCanUnloadNow是很簡單的,exe不是被動的,可以對自己控制生命期。DllRegisterServer和DllUnregisterServer可以直接通過exe檔案提供相應的命令列參數,來完成自登記。

 

類廠的啟動

COM通過維護一個關於被登記的類廠的內部表格,當客戶用合適的參數調用CoGetClassObject時,COM將首先檢查此關於類廠的私人表格,已得到與客戶請求的CLSID相應的類廠,若存在將進行尋找並啟動EXE,EXE可以調用COM函數CoRegisterClassObject來完成類廠的登記。只需要建立相應的類廠並將其介面指標傳給CoRegisterClassObject即可。

  • CoRegisterClassObject

第一個參數是被登記類的CLSID,第二個和第三個參數是一起使用的,第四個參數表示EXE的單個執行個體能否支援一個組件的多個執行個體,他能提供單個組件REGCLS_SINGLEUSER和CLSCTX_LOCAL_SERVER,可以支援多個組件的執行個體,REGCLS_MULTI_SEPARATE。

 

CoRegisterClassObject(__in REFCLSID rclsid,

    __inLPUNKNOWN pUnk,

    __inDWORD dwClsContext,

    __inDWORD flags,

    __outLPDWORD lpdwRegister

);

  • 類廠的釋放

當伺服器被關閉時,他必須沖內部表格中刪除相應的類廠,使用COM庫德CoRevokeClassObject。

 

對LockServer的修改

           進程中伺服器將輸出函數DllCanUnloadNow,用此函數以決定能否從記憶體中講伺服器卸載。對於本機伺服器,需要對LockServer進行修改,其原因在於:DLL不能控制他們的生命期,他們的裝載和卸載都是由另外的EXE檔案完成。但EXE本身可以控制,當退出的時候發送退出訊息即可。C和C++程式的標準進入點為main。程式的執行將從main函數開始,當main退出時,程式也就終止了。Windows程式通過入口函數WinMain,通過引入windows訊息迴圈來不致EXE退出,

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.