• 沒有找到結果。

呼叫模組元件

第二章 模組間內部機制介紹

2.4 模組使用機制

2.4.2 模組使用流程

2.4.2.1 呼叫模組元件

透過解析這個步驟的原理,將幫助我們了解外部使用者如何使用 COM 模組的 問題,而且也可以了解 COM 模組如何自動連結 Library,而無須使用者手動連結 的機制,以下我們先從呼叫 COM 模組所要用到的一個指令開始介紹,接著才介紹 使用者下達這個指令時,這個指令內部是如何幫我們找出我們的模組並建立起 來。

當要呼叫 COM 模組時我們是調用 COM 函式庫內的 API CoCreateInstance() 來幫我們完成呼叫的動作,其 API 函式原型如圖 2-13,以下我們將分別解釋這 個 API 所帶參數的意義,了解這些參數後可以幫助我們知道如何去呼叫自己的 Filter 模組。

HRESULT CoCreateInstance ( REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid,

LPVOID* ppv );

圖 2-13 CoCreateInstance()函式原型

z rclsid: COM 模組 CLSID, CLSID 即是 GUID(Globally unique identifier) 的意思,所謂 GUID 是一個 128 位數字的全球唯一標示符,因此每個模組都 有自己一組獨一無二的 CLSID 註冊在操作系統中,外部使用者知道此 ID 即 可呼叫 COM 模組。

z pUnkOuter: 負責 COM 模組的外部函式,可以利用此參數對 COM 模組添加外 部函式,NULL 表示不使用外部函式。

z dwClsContext: 表示 COM 模組所使用服務器種類,例如在 DirectShow 中使 用的是 in-process DLL,代表的意思就是在本機器操作並以 DLL 的方式進 行連接,所代表的參數值是 CLSCTX_INPROC_SERVER。

23

z riid: 所要求介面函式的 IID,例如可以設定 IID_ITest 來取得 ITest 的介 面指標。

z ppv: 介面指標的位址(address),通過此參數接收由 riid 所要求的介面函 式指標。

了 解 以 上 各 個 參 數 的 意 義 之 後 , 我 們 藉 由 撰 寫 一 個 外 部 使 用 者 透 過 CoCreateInstance 呼叫一個 COM 模組的範例來說明這個 API 如何使用,其程式 碼如圖 2-14 所示

IExample* pIEX;

hr = CoCreateInstance ( CLSID_EXAMPLE,

圖 2-14 CoCreateInstance 範例程式碼

以這個範例可以看到,首先呼叫了一個叫 CLSID_EXAMPLE 的 COM 模組,不使 用外部函式,使用 In-Process DLL 的服務器,並且向 COM 模組要求一個 IID_IExample 的介面,取得之介面函式指標傳送給 pIEX 接收。

而 CoCreateInstance 會有 HRESULT 的回傳值,回傳值代表之意義如表 2-6 所示。當 COM 模組使用完畢,可以透過 Release()來釋放 COM 模組,一但釋放 COM 模組將從記憶體刪除,因此也就無法在使用其介面,適當的釋放將能更有效的運 用記憶體,避免記憶體被不必要的 COM 模組所佔住空間。

24

返回值 代表意義

S_OK COM 元件呼叫成功

REGDB_E_CLASSNOTREG 此 COM 元件沒有註冊或找不到此註冊值而發生錯誤 CLASS_E_NOAGGREGATION COM 元件不能被創建,要求外部函式不支持 E_NOINTERFACE 介面錯誤,COM 元件無法取得介面

E_POINTER 位址錯誤,介面位址為 NULL 表 2-6 HRESULT 回傳值代表意義

‹ CoCreateInstance 內部流程解說

以上知道 CoCreateInstance 這個 API 如何使用之後,接著我們要來深入探 討當我們使用這個指令來呼叫 Filter 的時候,這個指令的內部是透過怎樣的機 制來幫我們把 Filter 給建立起來,以及如何幫我們連接 Library。

在講解流程之前先介紹一個重要的介面,稱為 IClassFactory,這個介面對 於 CoCreateInstance 來說極為重要,因為 Filter 模組在還沒有呼叫之前是不知 道 Filter 類別(Class)的名稱,而不知道類別的名稱將無法取得類別裡面所實現 的功能函式。因此 COM 規範針對這個問題就規定了每個 Filter 模組都必須實現 一個與之相對應的類別工廠(Class Factory),而這個類別工廠(Class Factory) 的任務就是負責管理這個 Filter 模組的資訊,因此在開發 Filter 模組的過程必 須把我們所開發的 Filter 類別工廠新增到 Filter 資料庫中以方便管理,而 CoCreateInstance 就是透過 IClassFactory 介面來下達指令給 Filter 資料庫以 查找我們所需的 Filter 類別工廠。

了解這個介面之後,我們將透過下面圖 2-15 的流程圖分成六個步驟來說明 Filter 模組呼叫的整體過程。

25

CoCreateInstance() CoCreateInstance 呼叫 CoGetClassObject 啟動執行,此函式 Virtual code 如圖 2-16 所示,此函式便會透過使用者所給之 GUID 向 DLL 資料庫查找屬於 GetPrcoAddress(…DllGetClassObject);

}

圖 2-16 CoGetClassObject 函式原型

z Step 2:找到 DLL 路徑之後便把 DLL 路徑輸入 LoadLlibrary 函式,而此函式 便會將其 Filter 模組的 DLL 載入。

z Step 3:DLL 載入之後,接著透過 GetProcAddress 函式來取得 DLL 中的 DllGetClassObject 的功能函式指標。

26

z Step 4:透過 Step3 所取得之 DllGetClassObject 指標就可以幫我去 Filter 資料庫查找並透過 QueryInterFace 函式呼叫出其 Filter 的類別工廠介面 IClassFactory,DllGetClassObject 函式 Virtual code 如圖 2-17 所示。

DllGetClassObject(…) {

//透過 Filter GUID 查找其類別工廠 CFactory* pFactory = new CFactory;

//查找 IClassFactory 介面指標

pFactory->QueryInterFace(IID_IClassFactory,(void**)&pClassFactory);

pFactory->Release();

}

圖 2-17 DllGetClassObject 函式原型

z Step 5: 呼 叫 出 類 別 工 廠 後 , 接 著 利 用 類 別 工 廠 裡 面 的 成 員 函 式 CreateInstance 便可以把要求的 Filter 類別呼叫出來。

z Step 6:Filter 類別呼叫完成後就可以透過 QueryInterFace 就可以取得所 要求功能介面函式指標提供給使用者使用。