COM在登錄檔中的相關鍵值及其意義(這個很詳細,必須轉)
轉自 http://www.cnblogs.com/developersupport/archive/2013/06/02/COM-registry.html
COM在登錄檔中的相關鍵值及其意義
概要
當編寫好一個COM並將其在系統中註冊之後,這些登錄檔項到底位於Register中的什麼位置,系統是如何通過這些登錄檔項在Runtime時候找到某個COM的,這些都是診斷COM相關的問題至關重要的資訊。總的來說,系統是通過GUID來查詢每個物件的,比如TypeLib,Interface和Class都有其相應的GUID(16bytes的字串)。本文介紹了一個COM在註冊後,系統登錄檔會被寫入哪些鍵值,以及這些鍵值所代表的意義。
正文
COM是一種基於獨立於開發語言的程式設計模型。因此在描述COM功能和介面的時候採用了與程式語言無關的介面描述語言(IDL)來編寫介面的抽象定義,該介面定義檔案(*.IDL)經過Platform SDK自帶的Microsoft IDL編譯器編譯之後將生成相應的標頭檔案、型別庫等。
如下是一個簡單的型別庫定義檔案(OOPCOM.idl)
// OOPCOM.idl : IDL source for OOPCOM.dll // This file will be processed by the MIDL tool to // produce the type library (OOPCOM.tlb) and marshalling code. import "oaidl.idl"; import "ocidl.idl"; [ object, uuid(DB20D9BF-FAA4-4D23-9243-19860EB4482A), dual, helpstring("ISimpleClass Interface"), pointer_default(unique) ] interface ISimpleClass : IDispatch { [id(1), helpstring("method HelloWorld")] HRESULT HelloWorld([out,retval]BSTR *result); }; [ uuid(FE0FAA57-2E27-425F-9FA3-518E73F729FB), version(1.0), helpstring("OOPCOM 1.0 Type Library") ] library OOPCOMLib { importlib("stdole32.tlb"); importlib("stdole2.tlb"); [ uuid(1CF4A019-A754-44F1-B164-047A3F0AC184), helpstring("SimpleClass Class") ] coclass SimpleClass { [default] interface ISimpleClass; }; };
本文主要介紹以下幾個COM相關常見概念:
- COM Interface
- COM Class
- Type Library
- Application ID &Name
COM的相關表項在登錄檔中的位置及其意義:
表項一:COM Interface
登錄檔路徑 : HKEY_CLASSES_ROOT\Interface\[X] 或者:HKLM\Software\Classes\Interface\[x]
在以上的OOPCOM.idl,我們看到其Inferface ID (IID)為DB20D9BF-FAA4-4D23-9243-19860EB4482A,其在Register中的位置如圖所示。
在COM的Interface表項中包含
- ProxyStubClsid :該鍵值的具體內容請參考下圖。
- ProxyStubClsid32 :該鍵值的具體內容參考下圖。該鍵值與ProxyStubClsid相同值。
- TypeLib: 與該interface相關的COM 型別庫定義。
在Interface中,有關ProxyStubClsid和ProxyStubClsid32所指向的CLSID值如下圖所示:
ProxyStubClsid鍵值和ProxyStubClsid32起什麼作用呢?這需要對COM client和COM service是如何進行通訊和資料交換的有所瞭解。
當COM client和COM Server application不在同一個程序地址空間時,COM會建立一個客戶端的proxy和server端的stub。例如當client呼叫CoCreateInstance()時,在伺服器將介面指標返回給COM之後,COM將介面指標返回給client之前,COM為指定的介面建立proxy和stub並將指向proxy的指標返回給client。我們把類似這樣的過程叫做Marshaling (彙集)。
開發人員可以實現IMarshal這個interface來支援自定義的Marshaling。而如果物件不支援自定義Marshaling,則COM使用proxy和stub程式執行標準Marshaling,因此COM必須從登錄檔中獲得提供proxy和stub程式生成器的DLL的CLSID。這就是我們為什麼ProxyStubClsid(32)的意義所在。
如果開發的COM支援自動化技術,即實現了IDispatch interface(支援解釋型語言的呼叫,如vbscript等),則其Marshaling的DLL一般為以上所示的oleaut32.dll (16bit系統則為ole2disp.dll)。如果其不支援該技術,則其Marshaling的DLL一般為ole32.dll
表項二:COM Class
登錄檔路徑: HKEY_CLASSES_ROOT\CLSID\[X] 或者:HKLM\Software\Classes\CLSID\[x]
預設情況下,在CLSID下面包含以下鍵值(如上圖所示)
- LocalServer32
- ProgID
- TypeLib
- Programmable (omitted)
LocalServer32:
該鍵用來指定執行在程序外的COM Server Application的.EXE檔案path。與之相似的一個表項是:InprocServer32。COM執行模式有2種,一種為程序內模式,即COM與Client在同一個程序記憶體之內,執行在這種模式下的COM必須只能為*.DLL,指定其具體COM module的path的時候,即用InprocServer32來指定;另外一種是Out of Process(OOP),即Client和COM Server Application位於不同的Process地址空間,而這種COM必須為*.EXE,指定其具體COM module 的path時候,即用LocalServer32來指定。
而這兩種模式下的COM呼叫過程也不盡相同。
1.伺服器為*.DLL時,呼叫過程如下所示:
2. 當伺服器為*.EXE 時,其過程如下所示:
ProgID:
實際上ProgID和CLSID都是一回事,只不過是2種不同的叫法而已,ProgID可以說是CLSID的nickname吧。相對於CLSID一串16bytes的難以記憶的數字, ProgID顯得更為人性化,系統提供了相應API: GetClsIdFromProgid(t_ProgID) 可以實現ProgID和CLSID之間的互換。
TypeLib:
不用多講了, 該鍵在COM interface鍵中也出現過,用來指定該COM的型別庫檔案。
既然在COM Interface和COM class中都出現了Type Library,那就看看TypeLib 鍵吧。
表項三: COM Type Library
登錄檔路徑: HKEY_CLASSES_ROOT\TypeLib\ [X]
TypeLib的各項鍵值如上圖所示。
還有一項不太注意的Register Entry就是AppID。當把COM註冊到系統之後,系統會在 HK_ROOT\AppID 下面生成一個指向該COM的AppID Entry。預設情況下,會使用COM module name作為該Application name,從而使得該COM/DCOM 可讀。如下圖5在dcomcnfg.exe中所示,該AppID和一個readable的Application Name對應起來。
表項四:COM Application相關注冊表項
登錄檔路徑: HKEY_CLASSES_ROOT\AppID\[X]
希望以上內容對您有所幫助
Winston He