使用 .NET 中的本机 COM 服务器

更新:2007 年 11 月

本节介绍用于从 .NET 应用程序使用现有 COM 组件的可用选项,并概括了各种方法的优点和缺点。通常,推荐的方法是 C++ Interop。

使用 TLBIMP

Windows 软件开发工具包 (SDK) 类型库导入程序 (Tlbimp.exe) 是一个可将 COM 类型库公开为称作互操作程序集的一种程序集的工具。此程序集为给定类型库中的各个 COM 接口定义托管等效项(或包装)。

当调用互操作程序集的方法时,将执行从托管到非托管的转换并且将控件传递给 COM 组件。同样地,当非托管 COM 函数返回时,将执行从非托管到托管的转换。默认情况下,检查 COM HRESULT 以查看是否失败,如果 HRESULT 没有指示成功,将引发异常。类似地,COM 组件初始化和接口查询是由互操作程序集执行的,因此从调用代码隐藏。

互操作程序集不替代它们代表的 COM 组件;在 COM 组件中保留非托管 COM 函数,因此必须在目标计算机上安装并注册此组件,否则调用互操作程序集将失败。

使用 Tlbimp 是从托管代码使用 COM 组件的最简单方法,但存在一些严重的缺点,特别是对于大型和/或复杂的 COM 接口。这些缺点是:

  • Tlbimp 为类型库中的每个 COM 接口生成托管接口。此行为无法取消,因此结果程序集会变得非常大。(例如,Tlbimp 为 Mshtml.dll 生成的互操作程序集超过 8 MB。) 也无法隐藏只打算在 COM 组件内部使用的接口。

  • Tlbimp 支持有限的几个数据类型。通常,不受支持的类型作为泛型、非类型安全的 IntPtr 类型导入到托管世界中,并需要编写易于出错且冗长的封送代码以使用程序集,但有时 Tlbimp.exe 根本无法公开接口的成员。

  • Tlbimp 生成一个单独的互操作程序集,它必须与最终应用程序一起部署。

如果这些缺点是可接受的,请参见如何:将本机 COM 服务器用于 TLBIMP 获取一个示例。

修改 MSIL

Tlbimp 的缺点可在一定程度上得到减轻,方法是使用 MSIL 反汇编程序 (Ildasm.exe) 反汇编互操作程序集,编辑 MSIL 以移除不必要的接口定义并替换参数类型,然后用 MSIL 汇编程序 (Ilasm.exe) 重新汇编 MSIL。此过程易于出错并且要求具备 MSIL、非托管类型和 .NET 类型的知识。而且,如果更新了 COM 接口,必须重新执行此过程。

C++ Interop

在 Visual C++ 中,可以完全避免 Tlbimp 和编辑 MSIL 的缺点,因为与 Visual Basic 和 C# 不同,Visual C++ 可以通过常用的 COM 机制(例如 CoCreateInstanceQueryInterface)直接使用 COM 对象。这是可能的,因为 C++ Interop 的功能可导致编译器自动插入转换代码以在托管和非托管函数之间移动。

使用 C++ Interop,可以像通常那样使用 COM 组件,也可以将其包装到 C++ 类中。这些包装类称为自定义运行时可调用包装(或 CRCW),与在应用程序代码中直接使用 COM 相比,它们有两大优点:

  • 结果类可从 Visual C++ 之外的语言中使用。

  • COM 接口的细节可从托管客户端代码中隐藏。.NET 数据类型可用于替换本机类型,并且数据封送的细节可在 CRCW 内部透明地执行。

如何:将本机 COM 服务器与 CRCW 一起使用 中演示如何使用 Visual C++ 包装 COM 接口。

无论是直接使用 COM 还是通过 CRCW 使用 COM,必须封送参数类型(简单的、可直接复制到本机结构中的类型除外)。有关数据封送的信息,请参见使用 C++ Interop(隐式 PInvoke)

说明:

MFC 应用程序必须初始化为单线程单元 (STA)。如果在 InitInstance 重写中调用 CoInitializeEx,请指定 COINIT_APARTMENTTHREADED(而不是 COINIT_MULTITHREADED)。有关更多信息,请参见位于 https://support.microsoft.com/default.aspx?scid=kb;zh-cn;828643 上的“PRB: MFC Application Stops Responding When You Initialize the Application as a Multithreaded Apartment (828643)”(PRB:作为多线程单元初始化 MFC 应用程序时,程序停止响应 (828643))。

请参见

其他资源

本机和 .NET 的互操作性