使用 .NET 的原生 COM 伺服器

更新:2007 年 11 月

本節將說明使用 .NET 應用程式中現有的 COM 元件時的可用選項,並且概略說明各種處理方法的優點和缺點。一般來說,建議使用的方法是 C++ Interop。

使用 TLBIMP

Windows Software Development Kit (SDK)型別程式庫匯入工具 (TlbImp.exe) 是一種工具,可以將 COM 型別程式庫公開 (Expose) 為組件 (Assembly),叫做 Interop 組件。這個組件會為特定型別程式庫中的各個 COM 介面定義 Managed 對應項或包裝函式。

當呼叫 Interop 組件的方法時,會執行 Managed-to-Unmanaged 轉換,並且將控制項傳遞給 COM 元件。同樣地,當 Unmanaged COM 函式傳回時,會執行 Unmanaged-to-Managed 轉換。根據預設,會檢查 COM HRESULT 是否失敗,如果 HRESULT 未表示成功,則會擲回例外狀況。同樣地,COM 元件初始化和介面查詢也是由 Interop 組件執行,因此不會顯示在呼叫的程式碼中。

Interop 組件並不會取代它們所表示的 COM 元件,Unmanaged COM 函式仍然是在 COM 元件中,因此使用者必須安裝此元件並且將其登錄至目標電腦上,否則 Interop 組件的呼叫會失敗。

從 Managed 程式碼中使用 COM 元件最簡單的方式就是使用 Tlbimp,但是這種方式有一些嚴重的缺點,特別是對於大型和 (或) 複雜的 COM 介面來說。這些缺點是:

  • Tlbimp 會為型別程式庫中的每個 COM 介面產生 Managed 介面。您無法抑制這種行為,因此產生的組件可能會非常大 (例如,Tlbimp 為 Mshtml.dll 產生的 Interop 組件即超過 8 MB)。您也無法隱藏只能在 COM 元件中使用的介面。

  • Tlbimp 只能支援有限的資料型別。通常不受支援的型別會以泛型、非型別安全的 IntPtr 型別匯入至 Managed 環境中,因此容易發生錯誤以及封送處理 (Marshaling) 冗長的程式碼必須使用組件,不過有時候 Tlbimp.exe 可能根本無法公開介面的成員。

  • Tlbimp 會產生單獨的 Interop 組件,必須與最後的應用程式一起部署。

如果這些缺點都可以接受,請參閱 HOW TO:在 TLBIMP 中使用原生 COM 伺服器中的範例。

修改 MSIL

如果能反組譯 Interop 組件,可以稍微減輕 Tlbimp 的缺點,方式是使用 MSIL 反組譯工具 (Ildasm.exe) 編輯 MSIL,移除不必要的介面定義以及取代引數型別 (Argument Type),然後使用 MSIL 組譯工具 (Ilasm.exe) 重新組譯 MSIL。這個程序很容易發生錯誤,因此需要具備 MSIL、Unmanaged 型別和 .NET 型別的知識。此外,如果更新 COM 介面,就必須再執行一次這個程序。

C++ Interop

在 Visual C++ 中可以完全避開 Tlbimp 的缺點,也不必編輯 MSIL,因為 Visual C++ 可以透過一般的 COM 機制 (例如 CoCreateInstanceQueryInterface) 直接使用 COM 物件,這點有別於 Visual Basic 和 C#。這可能是由於 C++ Interop 所具備的功能,使得編譯器 (Compiler) 可以自動插入轉換程式碼,讓 Managed 函式與 Unmanaged 函式能夠互相轉換。

使用 C++ Interop 時,可以依照一般方式來使用 COM 元件,也可以將 COM 元件包裝在 C++ 類別 (Class) 內。這種包裝函式類別 (Wrapper Class) 稱為自訂執行階段可呼叫包裝函式 (Custom Runtime Callable Wrapper),或簡稱 CRCW,相較於直接在應用程式的程式碼中使用 COM,這種方式有兩個優點:

  • 產生的類別可以在 Visual C++ 以外的其他語言中使用。

  • 可以在 Managed 用戶端程式碼中隱藏 COM 介面的細節。.NET 資料型別可以用來取代原生型別,而且可以直接在 CRCW 內執行資料封送處理的細節。

HOW TO:在 CRCW 中使用原生 COM 伺服器中,將會示範如何使用 Visual C++ 包裝 COM 介面。

不論是直接或是透過 CRCW 使用 COM,除了簡單、Blittable 型別以外的其他引數型別都必須進行封送處理。如需資料封送處理的詳細資訊,請參閱使用 C++ Interop (隱含 PInvoke)

注意事項:

MFC 應用程式必須初始化為單一執行緒的 Apartment (STA)。如果在 InitInstance 覆寫中呼叫 CoInitializeEx,請指定 COINIT_APARTMENTTHREADED (而不是 COINIT_MULTITHREADED)。如需詳細資訊,請參閱<PRB: MFC Application Stops Responding When You Initialize the Application as a Multithreaded Apartment>(828643),網址為:https://support.microsoft.com/default.aspx?scid=kb;en-us;828643

請參閱

其他資源

原生和 .NET 互通性