COM進程內組件與進程外組件1. COM進程內組件
進程內組件以動態連結程式庫的形式存在(尾碼名為dll),用戶端需要使用進程內組件提供的服務時只需要將dll載入進用戶端進程。進程內組件必須提供自註冊功能,這樣用戶端進程才能在需要的從註冊表中尋找到相應的資訊,並載入該組件。
進程內組件需要匯出四個函數
DllRegisterServer:
參數:無
傳回值:HRESULT 指示註冊操作的錯誤類型
DllUnregisterServer
參數:無
傳回值:HRESULT 指示刪除註冊表中的相應項操作的錯誤類型
DllGetClassObject
參數1:CLSID&組件的CLSID(因為一個dll可以作為多個組件的載體)
參數2:IID&,要從組件中擷取的介面IID
參數3:void**,接收穫得的介面指標的雙重指標
傳回值: HRESULT 指示操作結果的錯誤類型,一般有(E_OUTOFME\
MORY, S_OK,E_NOINTERFACE,CLASS_E_CLASSNOTAVAILABLE);
DllCanUnloadNow
參數:無
傳回值:HRESULT 指示是否可卸載該組件
說明:COM庫每隔一段時間便會自動調用該方法判斷是否可以卸載該組件。
進程內組件註冊表中需要的內容
位於HKEY_CLASSES_ROOT的CLSID項下
其中7F21137D…為組件的CLSID
InprocServer32所對應的值為進程內組件的完整路徑
ProgID 所對應的值為組件的自訂名稱用戶端可以通過該名稱獲得組件的CLSID.
2.COM進程外組件2.1 LPC和RPC
COM採用LPC(本地程序呼叫)和RPC(遠端程序呼叫)的方法進行進程之間的通訊,LPC用於在同一機器上的不同進程之間進行通訊,而RPC用於在不同機器上的進程之間進行通訊。
2.2 存根代理dll
為了提供LPC的處理,com提供了一個非常簡便的方法,當組件為進程外組件時,客戶將同一個模仿組件的dll進行通訊,這個dll可以為客戶完成參數調整以及LPC調用,這個dll在用戶端稱之為代理dll,而在伺服器端稱作為存根dll。
代理存根dll的產生步驟:
1. 編寫idl檔案
該idl檔案包含了所有服務端組件定義的介面,組件標示符CLSID除外
2. 使用MIDL編譯該IDL檔案
編譯後產生的一下幾個檔案
1) XXX_h.h 包含介面定義的標頭檔,和所有介面IID的聲明
2) XXX_i.c 介面IID的定義
3) XXX_p.c 代理檔案
4) Dlldata.c 資料檔案
3. 使用以上檔案產生存根代理dll
1) 在預先處理增加REGISTER_PROXY_DLL
2) 提供輸入庫rpcrt4.lib uuid.lib
3) 添加def檔案,匯出五個函數
4) 編譯產生dll
產生後的dll會有五個匯出函數如
前面四個和進程內組件意義一致
2.3 進程外組件的註冊
進程外組件註冊需要註冊存根代理dll和組件exe檔案,其中存根代理dll的註冊和進程內組件的註冊一致,而exe檔案的註冊就依靠其命令參數來進行。
組件程式的兩個用於註冊的入口函數為DllRegisterServer和DllUnregisterServer,註冊組件使用命令:RegSvr32
*.dll;反註冊組件使用命令:RegSvr32 /u *.dll,進程內組件註冊使用此命令。進程外組件註冊必須支援兩個命令列參數/RegServer和/UnregServer。
CLSID子鍵下:
圖1
圖2
Interface子鍵下:
圖3
圖4
其中ProxyStubClsid32為該介面的存根代理dll的CLSID,圖1,這樣在查詢某介面時com庫就知道到哪載入存根代理dll了
3 類廠
COM庫通過類廠建立COM對象,對應每一個COM類,都有一個類廠專門用於該COM類的對象建立工作。類廠本身也是一個COM對象,它支援介面IClassFactory。
CreateInstance建立對應的COM對象,LockServer控制組件的生存周期。
類廠由函數DllGetClassObject建立。
DllGetClassObject返回類廠對象的介面指標,再通過CreateInstance建立對應的COM對象。
4.COM庫與類廠的互動
建立對象函數:
1)若建立遠程對象或希望一次擷取對象的多個介面指標,選用CoCreateInstanceEx。
2)若希望擷取類廠對象或要調用類廠的某些成員函數,選用CoGetClassObject,通常IID=IID_IclassFactory,進程內組件直接調用DLL的CoGetClassObject,若CoGetClassObject建立的類廠對象位於進程外組件,函數啟動組件進程,然後等待,直到組件進程把它支援的COM類對象的類廠註冊到COM中,返回類廠資訊。
3)其他情況下,選用CoCreateInstance建立對象,CoCreateInstance封裝類廠建立對象的過程,返回COM對象的介面指標,不能建立遠程機器上的對象。
5.COM庫
COM庫初始化函數:CoInitialize
COM庫終止函數:CoUninitialize
COM庫記憶體管理:
COM提供的記憶體管理器標準,是一個COM介面IMalloc。當組件記憶體的分配和釋放不在同一模組,需要用到記憶體管理器,COM庫封裝了三個API函數,用於記憶體配置和釋放
CoTaskMemAlloc
CoTaskMemFree
CoTaskMemRealloc