微軟工程師必修技術之《使用COM組件技術》

本系列的第 1 模塊演示瞭如何創建窗口並響應窗口消息,如WM_PAINTWM_CLOSE。 模塊 2 引入瞭組件對象模型 (COM) 。

COM 是創建可重用軟件組件的規范。 在基於新式Windows的程序中使用的許多功能都依賴於 COM,例如:

  • 圖形 (Direct2D)
  • 文本 (DirectWrite)
  • Windows Shell
  • 功能區控件
  • UI 動畫

(此列表中的某些技術使用 COM 的子集,因此不是“純”COM.)

COM 有難以學習的聲譽。 的確,編寫支持 COM 的新軟件模塊可能很棘手。 但是,如果你的程序嚴格是 COM 的 使用者 ,你可能會發現 COM 比預期更容易理解。

本模塊演示如何在程序中調用基於 COM 的 API。 它還描述瞭 COM 設計背後的一些原因。 如果瞭解 COM 的設計原因,則可以更有效地對其進行編程。 本模塊的第二部分介紹瞭 COM 的一些推薦編程做法。

COM 於 1993 年引入,以支持對象鏈接和嵌入 (OLE) 2.0。 人們有時認為 COM 和 OLE 是一樣的。 這可能是 COM 難以學習的另一個原因。 OLE 2.0 是基於 COM 構建的,但你不必知道 OLE 才能理解 COM。

COM 是 二進制標準,而不是語言標準:它定義應用程序和軟件組件之間的二進制接口。 作為二進制標準,COM 是非語言中立的,盡管它自然映射到某些 C++ 構造。 本模塊將重點介紹 COM 的三個主要目標:

  • 將對象的實現與其接口分離。
  • 管理對象的生存期。
  • 在運行時發現對象的功能。

一、什麼是 COM 接口?

如果你知道 C# 或 Java,接口應該是一個熟悉的概念。接口定義瞭一組對象可以支持的方法,而無需聽寫有關實現的任何內容。 接口在調用方法的代碼與實現該方法的代碼之間標記明確的邊界。 在計算機科學方面,調用方與實現分離

在 C++ 中,與接口最接近的等效項是純虛擬類,即僅包含純虛擬方法且不包含其他成員的類。 下面是接口的假設示例:

// The following is not actual COM.

// Pseudo-C++:

interface IDrawable

{

void Draw();

};

此示例的想法是,一些圖形庫中的一組對象是可繪制的。 接口 IDrawable 定義任何可繪制對象必須支持的操作。 (按約定,接口名稱以“I”.) 開頭。在此示例中,IDrawable接口定義單個操作: Draw

所有接口都是 抽象IDrawable ,因此程序無法創建對象的實例,因此。 例如,以下代碼不會編譯。

IDrawable draw;

draw.Draw();

相反,圖形庫提供實現IDrawable接口的對象。 例如,庫可能提供用於繪制形狀的形狀對象和用於繪制圖像的位圖對象。 在 C++ 中,這是通過繼承自通用抽象基類來完成的:

class Shape : public IDrawable

{

public:

virtual void Draw(); // Override Draw and provide implementation.

};

class Bitmap : public IDrawable

{

public:

virtual void Draw(); // Override Draw and provide implementation.

};

ShapeBitmap類定義兩種不同的可繪制對象類型。 每個類繼承自 IDrawable 該方法並提供其自己的實現 Draw 。 當然,這兩個實現可能會大相徑庭。 例如,該方法 Shape::Draw 可能會光柵化一組線條,同時 Bitmap::Draw 會點亮像素數組。

使用此圖形庫的程序可以通過指針操作 ShapeBitmap 對象 IDrawable ,而不是直接使用 ShapeBitmap 指針。

IDrawable *pDrawable = CreateTriangleShape();

if (pDrawable)

{

pDrawable->Draw();

}

下面是循環訪問指針數組IDrawable的示例。 隻要數組中的每個對象繼承IDrawable,該數組可能包含形狀、位圖和其他圖形對象的異類分類。

void DrawSomeShapes(IDrawable **drawableArray, size_t count)

{

for (size_t i = 0; i < count; i++)

{

drawableArray[i]->Draw();

}

}

有關 COM 的一個關鍵點是,調用代碼永遠不會看到派生類的類型。 換句話說,你永遠不會在代碼中聲明類型 ShapeBitmap 代碼中的變量。 對形狀和位圖的所有操作都使用 IDrawable 指針執行。 通過這種方式,COM 在接口和實現之間保持嚴格分離。 和類的ShapeBitmap實現詳細信息可以更改(例如,修復 bug 或添加新功能),對調用代碼沒有更改。

在 C++ 實現中,使用類或結構聲明接口。

備註本主題中的代碼示例旨在傳達一般概念,而不是實際做法。 定義新的 COM 接口超出瞭此系列的范圍,但不會直接在頭文件中定義接口。 而是使用名為“接口定義語言” (IDL) 的語言定義 COM 接口。 IDL 文件由 IDL 編譯器處理,該編譯器生成 C++ 頭文件。

class IDrawable
{
public:
virtual void Draw() = 0;
};

赞(0)