在 COM 中建立物件
線上程初始化 COM 程式庫之後,執行緒可以使用 COM 介面是安全的。 若要使用 COM 介面,您的程式會先建立實作該介面的物件實例。
一般而言,有兩種方式可以建立 COM 物件:
- 實作 物件的模組可能會提供特別設計來建立該物件的實例的函式。
- 或者,COM 提供名為 CoCreateInstance的泛型建立函式。
例如,從什麼是 COM 介面?主題中取得假設 Shape
物件。 在該範例中,物件會 Shape
實作名為 的 IDrawable
介面。 實作 Shape
物件的圖形庫可能會匯出具有下列簽章的函式。
// Not an actual Windows function.
HRESULT CreateShape(IDrawable** ppShape);
假設此函式,您可以建立新的 Shape
物件,如下所示。
IDrawable *pShape;
HRESULT hr = CreateShape(&pShape);
if (SUCCEEDED(hr))
{
// Use the Shape object.
}
else
{
// An error occurred.
}
ppShape參數的類型為 pointer-to-pointer-to- IDrawable
。 如果您之前沒有看到此模式,則雙間接取可能會令人困惑。
請考慮函式 CreateShape
的需求。 函式必須提供 IDrawable
指標給呼叫端。 但函式的傳回值已用於錯誤/成功碼。 因此,指標必須透過函式的引數傳回。 呼叫端會將 類型的 IDrawable*
變數傳遞至函式,而函式會以新的 IDrawable
指標覆寫此變數。 在 C++ 中,只有兩種方式可讓函式覆寫參數值:以傳址方式傳遞或以位址傳遞。 COM 會使用後者的傳遞位址。 而指標的位址是指標對指標,因此參數類型必須是 IDrawable**
。
以下是一個圖表,可協助視覺化發生什麼事。
函 CreateShape
式會使用 pShape (位址) &pShape
將新的指標值寫入 pShape。
CoCreateInstance:建立物件的一般方式
CoCreateInstance函式提供建立物件的泛型機制。 若要瞭解 CoCreateInstance,請記住,兩個 COM 物件可以實作相同的介面,而一個物件可以實作兩個或多個介面。 因此,建立物件的泛型函式需要兩項資訊。
- 要建立的物件。
- 要從 物件取得的介面。
但是,當我們呼叫 函式時,如何指出這項資訊? 在 COM 中,物件或介面的識別方式是指派 128 位的數位,稱為 全域唯一識別碼 (GUID) 。 GUID 會以有效唯一的方式產生。 GUID 是如何在沒有中央註冊授權單位的情況下建立唯一識別碼之問題的解決方案。 GUID 有時稱為 通用唯一識別碼 , (UUID) 。 在 COM 之前,它們用於 DCE/RPC (分散式運算環境/遠端程序呼叫) 。 有數個演算法可用來建立新的 GUID。 並非所有演算法都嚴格保證唯一性,但意外建立相同 GUID 值的機率非常小,實際上為零。 GUID 可用來識別任何類型的實體,而不只是物件和介面。 不過,這是本課程模組中唯一關注我們的用法。
例如,連結 Shapes
庫可能會宣告兩個 GUID 常數:
extern const GUID CLSID_Shape;
extern const GUID IID_IDrawable;
(您可以假設這些常數的實際 128 位數值定義于其他地方。) 常數 CLSID_Shape 識別 Shape
物件,而常數 IID_IDrawable 識別 IDrawable
介面。 前置詞 「CLSID」 代表 類別識別碼,而 前置詞 IID 代表 介面識別碼。 這些是 COM 中的標準命名慣例。
根據這些值,您會建立新的 Shape
實例,如下所示:
IDrawable *pShape;
hr = CoCreateInstance(CLSID_Shape, NULL, CLSCTX_INPROC_SERVER, IID_IDrawable,
reinterpret_cast<void**>(&pShape));
if (SUCCEEDED(hr))
{
// Use the Shape object.
}
else
{
// An error occurred.
}
CoCreateInstance函式有五個參數。 第一個和第四個參數是類別識別碼和介面識別碼。 實際上,這些參數會告訴函式「建立 Shape 物件,並提供 IDrawable 介面的指標」。
將第二個參數設定為 Null。 (如需此參數意義的詳細資訊,請參閱 COM 檔中的 匯總 主題。) 第三個參數採用一組旗標,其主要用途是指定物件的 執行內容 。 執行內容會指定物件是否在與應用程式相同的進程中執行;在同一部電腦上的不同進程中;或位於遠端電腦上。 下表顯示此參數最常見的值。
旗標 | 描述 |
---|---|
CLSCTX_INPROC_SERVER | 相同的程序。 |
CLSCTX_LOCAL_SERVER | 不同的進程,相同的電腦。 |
CLSCTX_REMOTE_SERVER | 不同的電腦。 |
CLSCTX_ALL | 使用 物件支援的最有效率選項。 (從最有效率到最不有效率的排名是:跨進程、跨進程和跨電腦。) |
特定元件的檔可能會告訴您物件所支援的執行內容。 如果沒有,請使用 CLSCTX_ALL。 如果您要求物件不支援的執行內容, CoCreateInstance 函式會傳回錯誤碼 REGDB_E_CLASSNOTREG。 這個錯誤碼也可以指出 CLSID 不會對應到使用者電腦上註冊的任何元件。
CoCreateInstance的第五個參數會收到介面的指標。 因為 CoCreateInstance 是泛型機制,所以這個參數無法強型別。 相反地,資料類型為 void**,而呼叫端必須強制指向 void** 類型的指標位址。 這是上一個範例中 reinterpret_cast 的目的。
請務必檢查 CoCreateInstance的傳回值。 如果函式傳回錯誤碼,COM 介面指標無效,而且嘗試取值可能會導致程式當機。
在內部, CoCreateInstance 函式會使用各種技術來建立物件。 在最簡單的情況下,它會在登錄中查閱類別識別碼。 登錄專案會指向實作 物件的 DLL 或 EXE。 CoCreateInstance 也可以使用 COM+ 目錄或並存 (SxS) 資訊清單的資訊。 不論為何,呼叫端的詳細資料都是透明的。 如需 CoCreateInstance內部詳細資料的詳細資訊,請參閱 COM 用戶端和伺服器。
Shapes
我們所使用的範例稍有需要,因此現在讓我們改成實際 COM 的實際範例:顯示 [開啟] 對話方塊,讓使用者選取檔案。
下一個