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相關常見概念:

 

  1. COM Interface
  2. COM Class
  3. Type Library
  4. 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表項中包含

  1. ProxyStubClsid :該鍵值的具體內容請參考下圖。
  2. ProxyStubClsid32 :該鍵值的具體內容參考下圖。該鍵值與ProxyStubClsid相同值。
  3. 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下面包含以下鍵值(如上圖所示)

  1. LocalServer32
  2. ProgID
  3. TypeLib
  4. 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM