COM圖書館

任何使用 COM 的程序都必須同時初始化與取消初始化 COM 函式庫。 除了作為規範外,COM 也在此函式庫中實作了一些重要服務。 COM函式庫以一組DLL和EXE(主要是 Ole32.dll 和 Rpcss.exe)的形式提供於Microsoft Windows,包含以下內容:

  • 少數幾個基本功能,有助於建立 COM 應用程式,包括用戶端與伺服器端。 對用戶端而言,COM 提供建立物件的基本函式。 對伺服器而言,COM提供暴露其物件的方式。

  • 實作定位器服務,透過此服務,COM透過唯一類別識別碼(CLSID)判斷哪台伺服器實作該類別及其所在位置。 此服務支援在物件類別的識別與實作的封裝方式之間加入一層間接機制(通常是系統登錄),使使用戶端不受封裝方式影響,而封裝方式日後仍可變更。

  • 透明遠端程序會在物件在本地或遠端伺服器執行時呼叫。

  • 這是一種標準機制,讓應用程式能控制其程序中記憶體的分配方式,特別是需要在合作物件間傳遞以正確釋放的記憶體。

要使用基本的 COM 服務,客戶端和進程外伺服器中所有執行緒必須先呼叫 CoInitializeCoInitializeEx 函式,才能呼叫除記憶體配置外的其他 COM 函式。 CoInitializeEx 會取代另一個函式,並新增一個參數,讓你可以指定該執行緒的執行緒模型:單元執行緒或自由執行緒。 呼叫 CoInitialize 只是將執行緒模型設為 apartment-threaded。

OLE 複合文件應用程式呼叫 OleInitialize 函式,該函式呼叫 CoInitializeEx ,並執行複合文件所需的部分初始化。 因此,呼叫 OleInitialize 的執行緒不能採用自由執行緒模型。 關於用戶端與伺服器執行緒的資訊,請參見 程序、執行緒與公寓

進行中的伺服器不會呼叫初始化函式,因為它們正被載入已完成初始化的程序中。 因此,進行中的伺服器必須在登錄檔中以 InprocServer32 金鑰設定其執行緒模型。 關於進行中伺服器的執行緒問題詳細資訊,請參見 In-Process 伺服器執行緒問題

同時,取消初始化函式庫也很重要。 每次呼叫 CoInitializeCoInitializeEx,都必須有對應的 CoUninitialize 呼叫。 每次呼叫 OleInitialize,都必須有對應的呼叫 OleUninitialize

進行中伺服器可以假設所載入的程序已經完成這些步驟。

Important

每個使用 COM 的執行緒必須先呼叫 CoInitializeEx ,才能呼叫其他 COM 函式。 這是最常見的 COM 初始化錯誤——在尚未初始化的執行緒上呼叫 CoCreateInstance 或其他 COM API,將會失敗並顯示 CO_E_NOTINITIALIZED (0x800401F0)。

小提示

建議模式 — 使用 RAII 保護器以確保取消初始化:

#include <wil/com.h>  // Windows Implementation Libraries

// wil::unique_couninitialize_call calls CoUninitialize automatically on scope exit
auto comInit = wil::CoInitializeEx(COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

// ... use COM — CoUninitialize is called when comInit goes out of scope,
//     even if an exception is thrown ...

如果無法使用 wil,請手動呼叫 CoUninitialize()——每次成功的 CoInitializeEx 呼叫都必須且只能對應一次 CoUninitialize 呼叫:

HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (FAILED(hr)) return hr;

// ... use COM ...

CoUninitialize();

Important

常見錯誤:

  • 在目前執行緒上未初始化 COM 的情況下呼叫 COM 函式。
  • 呼叫不匹配 CoInitializeEx / CoUninitialize (每個成功的初始化需要恰好一個 uninit)。
  • 在同一執行緒上混用不同的 Apartment 模型(如果以與先前成功呼叫不同的模型呼叫 CoInitializeEx,則會傳回 RPC_E_CHANGED_MODE)。

元件物件模型