从 .NET 客户端调用 COM 组件

 

迈克·金德洛伊
Lark Group, Inc.

2001 年 11 月

总结: 本文档介绍从 .NET 客户端调用 COM 服务器的详细信息。 ) (14 个打印页

目标

  • 了解Runtime-Callable包装器的概念
  • 使用 TLBIMP 从 COM 组件创建程序集
  • 直接从 Microsoft® Visual Basic® .NET 代码引用 COM 组件

假设

若要充分利用本文档,应遵循以下条件:

  • 你熟悉 Visual Basic 编程
  • 你熟悉 COM 概念。 具体而言,你应该了解组件化软件的优点和体系结构
  • 你有权访问 Visual Basic .NET
  • 你了解整个 Microsoft .NET 平台体系结构

目录

互操作性的喜悦
练习从 .NET 调用 COM
直接使用 COM 组件
总结

互操作性的喜悦

有时,编程的一场革命会迫使你放弃之前的所有功能。 举一个极端的例子,假设你已经编写 Visual Basic 应用程序多年了。 如果你和许多开发人员一样,你将在这段时间里构建大量的代码清单。 如果你一直遵循各种语言大师的建议,该代码将 组件化。 也就是说,通过使用 COM (组件对象模型) (以前为 Microsoft ActiveX®)服务器,可将应用程序分解成多个可调用的功能块。 当然,你也可能对其他开发人员和其他公司的组件(例如 ActiveX 控件)进行大量投资。

但是,如果你决定彻底地将开发切换到另一个操作系统呢? 此时,COM 的全部投资将变得毫无价值。 不能使用任何现有代码,必须了解如何在新平台上执行所有操作。 毫无疑问,这将是对你的工作效率的严重打击。

幸运的是,从 COM 切换到 Microsoft .NET 不会造成这种根本的生产力损失。 有两个关键概念可以更轻松地从 COM 开发迁移到 .NET 开发,而不会损失任何代码库或工作效率:

  • .NET 组件可以调用 COM 组件。
  • COM 组件可以调用 .NET 组件。

这种双向互操作性是从 COM 迁移到 .NET 的关键。 了解 .NET 的复杂情况后,可以继续使用 COM 组件。 在很多情况下,这种互操作性非常有用:

  • 你不会立即知道有关 .NET 的所有内容。 学习 .NET 编程概念和实现需要时间,因此可能需要继续在 COM 中进行关键开发。
  • 尽管 Microsoft Visual Basic 6 代码可以移植到 .NET,但转换并不完美。 由于实现或语言怪癖,你可能有无法移动到 .NET 的组件。
  • 不能立即在新系统(如 .NET)中编写大型应用程序的所有代码。 更有意义的是单独编写组件,并一次测试一个组件,同时仍与现有代码互操作。
  • 你可能使用的是没有源代码的第三方 COM 组件。

本文档介绍从 .NET 客户端调用 COM 服务器的详细信息。 在配套文章 从 COM 组件调用 .NET 组件中,你将了解如何从 COM 客户端到 .NET 服务器从另一个方向调用 。

非托管代码和Runtime-Callable包装器

在 Microsoft .NET 公共语言运行时 (CLR) 内运行 的代码称为托管代码。 此代码可以访问 CLR 为表提供的所有服务,例如跨语言集成、安全性和版本控制支持以及垃圾回收。 不在 CLR 中操作的代码称为 非托管代码。 根据定义,所有旧 COM 组件都是非托管代码。 由于 COM 是在 CLR 存在之前设计的,并且 COM 代码不在 CLR 提供的框架中运行,因此它无法使用任何 CLR 服务。

在单个应用程序中混合托管代码和非托管代码的问题在于,在 CLR 环境中无法识别非托管代码。 托管代码组件不仅依赖于 CLR,还要求与其交互的其他组件依赖于 CLR。

摆脱这种困境的出路是使用 代理。 一般来说,代理是一种软件,它接受来自某个组件的命令,对其进行修改,并将其转发到另一个组件。 从托管代码调用非托管代码时使用的特定代理类型称为Runtime-Callable包装器或 RCW。 图 1 以示意图方式显示了 RCW 如何跨越托管代码和非托管代码之间的边界。 此图包括一个名为 NetUI.exe 的 .NET 程序、两个名为 BackEnd.dll 和 Service.dll 的 COM 组件,以及连接它们的必要技术。

图 1. 使用 RCW 调用非托管代码

使用 TLBIMP 转换元数据

当然,.NET 并不是第一个使用元数据来描述公共接口的 。 事实上,COM 类型库还包含描述 COM 组件的公共接口的元数据。 RCW 的工作是将此 COM 元数据转换为 .NET 元数据。

用于执行此转换的一个工具称为 tlbimp (类型库导入程序) ,它是作为 .NET Framework Software Developer Kit (SDK) 的一部分提供的。 Tlbimp 从 COM 类型库读取元数据,并创建用于调用 COM 组件的匹配 CLR 程序集。

注意 如果使用 Visual Basic 生成 ActiveX DLL 或 ActiveX EXE,类型库将嵌入 DLL 或 EXE 文件中。

Tlbmp 是一种命令行工具,其中包含许多选项,例如使用加密密钥对生成的程序集进行签名或解析类型库中的外部引用。 (在命令提示符处键入 tlbimp /? 以查看所有 options.) 最重要的选项是 /out,它允许你为生成的 .NET 程序集指定名称。 例如,若要将名为 support.dll 的 Visual Basic ActiveX DLL 转换为名称NETsupport.dll匹配的 .NET 程序集,可以使用以下命令行:

tlbimp support.dll /out:NETsupport.dll

直接使用 COM 组件

作为 Visual Basic .NET 开发人员,还可以选择直接使用 COM 组件。 至少,这是它的外观,尽管你仍在以编程方式使用 RCW 来访问非托管代码中的对象。 如果在 Visual Basic .NET 项目中工作,可以按照以下步骤添加对 COM 组件的引用:

  1. 单击“ 项目”,然后单击“ 添加引用”。
  2. “添加引用 ”对话框中,单击“ COM ”选项卡。
  3. 从列表中选择要使用的类型库,然后单击“ 选择”,或使用“ 浏览 ”按钮查找未列出的组件。 所选组件将添加到对话框中的下部列表视图。
  4. 单击“ 确定 ”,为 Visual Basic .NET 项目中的所选类型库创建 RCW。

执行此操作时,你会发现 Visual Basic .NET 实际上在项目的 /Bin 文件夹中创建了一个 DLL,该 DLL 的名称派生自原始 COM 组件名称。 例如,如果以这种方式引用BackEnd.dll版本 2.0,Visual Basic .NET 将在 Interop.BackEnd_2_0.dll 文件中创建 RCW。

直接使用 COM 组件的此快捷方式方法的主要缺点是没有机会对生成的代码进行签名。 因此,不能将代码放在全局程序集缓存 (GAC) 中,这反过来又使得无法在多个 .NET 应用程序之间共享该组件。

在 TLBIMP 和直接引用之间进行选择

尽管使用 COM 组件的任一方法都允许 .NET 代码调用 COM 组件,但有一些原因需要选择一个组件,

  • 对于仅在单个 Visual Basic .NET 项目中使用的 COM 组件(由你自己编写),请使用直接引用,而不是执行任何额外的工作。 此方法仅适用于不需要共享的真正专用组件。
  • 如果 COM 组件在多个项目之间共享,请使用 tlbimp,以便可以对生成的程序集进行签名并将其置于全局程序集缓存中。 共享代码 必须 签名。 此方法还允许在特定位置创建具有特定名称的 RCW。
  • 如果需要控制已创建程序集的高级详细信息,例如其命名空间或版本号,则必须使用 tlbimp。 直接引用方法使你无法控制这些详细信息。
  • 如果未编写 COM 组件,则 这两种方法都不能接受。 这是因为不允许对其他开发人员编写的代码进行签名。 在这种情况下,需要从组件的原始开发人员获取主互操作程序集 (PIA) 。 MSDN 包含可帮助你查找常见组件(如 ActiveX 控件)的 PIA 的链接。

练习从 .NET 调用 COM

在以下示例中,将在 .NET 代码的 COM 组件中使用属性、方法和事件。 你将使用 tlbimp 将 COM 组件的接口转换为程序集,然后了解如何在托管代码中将其视为任何其他 .NET 组件。 完成此操作后,还将了解如何在不使用 tlbimp 的情况下直接从 Visual Basic .NET 项目中使用 COM 组件来获取快捷方式。

安装 COM 组件

你将在本练习中使用 COM 组件名为 PhysServer.dll。 这是一个 ActiveX DLL,其中包含名为 Temperature 的单个类。 此类存储表示温度的内部变量,并处理摄氏度和华氏度之间的转换。 表 1 显示了 Temperature 接口的成员。

表 1. 与 PhysServer.dll 中的 Temperature 类的接口

成员 类型 说明
摄氏温度 属性 当前温度(摄氏度)
Fahrenheit 属性 当前温度(以华氏度为单位)
GetCelsius 方法 获取当前温度(以摄氏度为单位)
GetFahrenheit 方法 获取当前温度(以华氏度为单位)
下方Freezing 事件 温度低于冰点时触发
AboveBoiling 事件 当温度高于沸腾时触发

若要在安装了 Visual Basic 6.0 的计算机上创建此 COM 组件,请执行以下操作:

  1. 启动 Visual Basic 6.0 并创建新的 ActiveX DLL 项目。

  2. 单击“项目资源管理器”窗口中的“Class1”模块,并使用属性窗口将类的名称更改为“温度”。

  3. 单击“项目资源管理器”窗口中的“Project1”项目,并使用属性窗口将项目名称更改为“PhysServer”。

  4. 将此代码添加到 Temperature 类:

     Option Explicit
    
    Private mdblCelsius As Double
    Private mdblFahrenheit As Double
    
    Public Event BelowFreezing()
    Public Event AboveBoiling()
    
    Public Property Get Celsius() As Double
        Celsius = mdblCelsius
    End Property
    
    Public Property Let Celsius(NewTemperature As Double)
        mdblCelsius = NewTemperature
        mdblFahrenheit = ((NewTemperature * 9) / 5) + 32
        If mdblCelsius < 0 Then
            RaiseEvent BelowFreezing
        End If
        If mdblCelsius > 100 Then
            RaiseEvent AboveBoiling
        End If
    End Property
    
    Public Property Get Fahrenheit() As Double
        Fahrenheit = mdblFahrenheit
    End Property
    
    Public Property Let Fahrenheit(NewTemperature As Double)
        mdblFahrenheit = NewTemperature
        mdblCelsius = ((NewTemperature - 32) * 5) / 9
        If mdblFahrenheit < 32 Then
            RaiseEvent BelowFreezing
        End If
        If mdblFahrenheit > 212 Then
            RaiseEvent AboveBoiling
        End If
    End Property
    
    Public Function GetCelsius() As Double
        GetCelsius = mdblCelsius
    End Function
    
    Public Function GetFahrenheit() As Double
        GetFahrenheit = mdblFahrenheit
    End Function
    
    Private Sub Class_Initialize()
        mdblCelsius = 0
        mdblFahrenheit = 32
    End Sub
    
  5. 单击“ 项目”,然后在 “Visual Basic ”菜单中单击“ PhysServer 属性”。 在“ 项目属性 ”对话框中,将“项目说明”更改为“物理常量服务器”。 单击" 确定"。

  6. 保存项目。

  7. 单击“ 文件”,若要创建 COM 组件,请单击“制作PhysServer.dll”。

若要在 Visual Studio .NET 计算机上安装此 COM 组件,请执行以下操作:

  1. 在硬盘驱动器上创建名为“旧版”的新文件夹。

  2. 将PhysServer.dll复制到旧文件夹。

  3. 打开命令提示符窗口并键入:

    regsvr32 c:\Legacy\PhysServer.dll
    

    应会看到图 2 所示的消息。

    图 2. 已成功安装旧版 COM 组件消息

使用 TLBIMP 创建程序集

接下来,使用 tlbimp 实用工具创建为 PhysServer 组件提供 RCW 的程序集。 从控制面板启动系统小程序。

  1. 若要打开 Visual Studio .NET 命令提示符窗口,依次单击“ 开始”、“ 程序”、“ Microsoft Visual Studio .NET 7.0”、“ Visual Studio .NET 工具”和“ Visual Studio .NET 命令提示符”。

  2. 更改为 \旧目录。

  3. 在命令提示符处,键入:

    tlbimp PhysServer.dll /out:NETPhysServer.dll
    

在此特定情况下,我们选择在不签名的情况下创建 RCW。 如果此组件在多个客户端之间共享,则需要在调用 tlbimp 时对其进行签名。 为简洁起见,此处省略了此步骤的详细信息。 有关代码签名和全局程序集缓存的详细信息,请参阅 从 COM 组件调用 .NET 组件

Tlbimp 将执行转换工作,然后打印一条消息,确认类型库已作为新名称导入。

注意 Visual Studio .NET 命令提示符将框架 SDK 的 /Bin 文件夹添加到路径,以便无需指定其路径即可调用 SDK 工具(如 tlbimp)。

创建测试项目

现在,可以测试 Visual Basic .NET 应用程序使用旧版 COM 组件中的对象的能力。

  1. 打开 Visual Studio .NET,然后从“ 开始 ”页中选择“ 新建项目”。

  2. 从屏幕左侧的树视图中选择 “Visual Basic 项目 ”。

  3. 选择“ Windows 应用程序” 作为项目模板。

  4. 将应用程序的名称设置为 “PhysServerTest ”,然后单击“ 确定 ”创建项目。

  5. 突出显示解决方案资源管理器窗口中名为 Form1.vb 的窗体,并将其重命名为 frmTemperature.vb

  6. 通过添加相应的控件并设置这些控件的属性,创建图 3 所示的窗体,如表 2 中所述。

    表 2. frmTemperature.vb 的控件

    控件类型 属性
    Label 名称 lblFahrenheit
      文本 Fahrenheit
    TextBox 名称 txtFahrenheit
      文本 (空白)
    Button 名称 cmdConvertToC
      文本 转换为 C
    Label 名称 lblCelsius
      文本 摄氏温度
    TextBox 名称 txtCelsius
      文本 (空白)
    Button 名称 cmdConvertToF
      文本 转换为 F
    Label 名称 lblAboveBoiling
      文本 以上沸腾!
      字号 12
      字体粗体 True
      可见 False
    Label 名称 lblBelowFreezing
      文本 低于冻结!
      字号 12
      字体粗体 True
      可见 False

    图 3. 测试窗体设计

  7. 若要将 RCW 用于 PhysServer COM 组件,请单击“ 项目”,然后单击“ 添加引用”。 确保选中 “.NET ” 选项卡,然后单击 “ 浏览”。

  8. 浏览到旧文件夹并选择NETPhysServer.dll组件。 单击 “打开” 。 这会将组件添加到“所选组件”列表,如图 4 所示。

  9. 单击" 确定"。 解决方案资源管理器中的引用节点将展开以显示 NetPhysServer 引用 (以及 Visual Basic 项目包含) 的默认引用。

    图 4。 添加对 RCW 组件的引用

添加代码以使用 COM 组件

现在,你已准备好编写使用 Temperature 类的方法、属性和事件的代码。 单击“视图”,单击“代码”,然后在 Windows 窗体Designer生成的代码后输入此代码:

    Private WithEvents moTemp As NETPhysServer.Temperature

    Private Sub cmdConvertToC_Click(ByVal sender As System.Object, _
 ByVal e As System.EventArgs) Handles cmdConvertToC.Click
        lblBelowFreezing.Visible = False
        lblAboveBoiling.Visible = False
        With moTemp
            .Fahrenheit = txtFahrenheit.Text
            txtCelsius.Text = .GetCelsius
        End With
    End Sub

    Private Sub cmdConvertToF_Click(ByVal sender As System.Object, _
 ByVal e As System.EventArgs) Handles cmdConvertToF.Click
        lblBelowFreezing.Visible = False
        lblAboveBoiling.Visible = False
        With moTemp
            .Celsius = txtCelsius.Text
            txtFahrenheit.Text = .GetFahrenheit
        End With
    End Sub

    Private Sub frmTemperature_Load(ByVal sender As System.Object, _
 ByVal e As System.EventArgs) Handles MyBase.Load
        moTemp = New NETPhysServer.Temperature()
    End Sub

    Private Sub moTemp_AboveBoiling() Handles moTemp.AboveBoiling
        lblAboveBoiling.Visible = True
    End Sub

    Private Sub moTemp_BelowFreezing() Handles moTemp.BelowFreezing
        lblBelowFreezing.Visible = True
    End Sub

请注意,就此代码而言,NETPhysServer.Temperature 类与任何其他 .NET 类类似。 声明 类的实例并使用其方法和属性,就像它是本机类而不是围绕 COM 组件的Runtime-Callable包装器一样。

试用

若要查看 Temperature 类的运行情况,请执行以下步骤:

  1. F5 启动项目。
  2. 华氏度文本框中输入 41,然后单击“转换为 C”。“摄氏度”框应填充值 5
  3. “摄氏度”框中输入 123,然后单击“转换为 F”。华氏度框应填充值 253.4,且“以上沸腾!”标签应可见。
  4. 关闭窗体以停止项目。

直接使用 COM 组件

了解如何使用 tlbimp 后,请尝试直接使用 COM 组件的替代过程。

  1. 打开 Visual Studio .NET 的第二个实例,然后从“ 开始 ”页中选择“ 新建项目”。
  2. 从屏幕左侧的树视图中选择 “Visual Basic 项目 ”。
  3. 选择“ Windows 应用程序” 作为项目模板。
  4. 将应用程序的名称设置为 PhysServerTest2 ,然后单击“ 确定 ”创建项目。
  5. 突出显示解决方案资源管理器窗口中名为 Form1.vb 的窗体,并将其重命名为 frmTemperature.vb
  6. 切换到 Visual Studio .NET 的原始实例,并在设计视图中打开 frmTemperature 。 单击 Ctrl-ACtrl-C 以选择窗体上的所有控件并复制它们。
  7. 切换回 Visual Studio .NET 的第二个实例,在设计视图中选择 frmTemperature ,然后单击 Ctrl-V 将所有控件粘贴到新窗体上。

若要直接使用 COM 组件,请单击“项目”,单击“添加引用”,然后在“添加引用”对话框中选择“COM”选项卡。 向下滚动 COM 组件列表,直到找到 “物理常量服务器”,单击“ 选择”,然后单击“ 确定”。 你将收到如图 5 所示的警告。

图 5。 插入 COM 组件引用时显示的警告

此时,正确的响应取决于 COM 组件的生成者。 如果它来自供应商或其他开发人员,则应单击“ ”,然后从该供应商或开发人员处获取主互操作程序集。 在这种情况下,该组件专用于你自己的开发,因此单击“ ”告知 Visual Studio .NET 为此组件生成 RCW。 你将看到 PhysServer 出现在解决方案资源管理器的引用列表中。

注意 这是原始PhysServer.dll,而不是前面使用 tlbimp 生成的 RCW。

添加代码以使用 COM 组件

现在,你已准备好编写使用 Temperature 类的方法、属性和事件的代码。 单击“视图”,单击“代码”,然后在 Windows 窗体Designer生成的代码后输入此代码:

    Private WithEvents moTemp As PhysServer.Temperature

    Private Sub cmdConvertToC_Click(ByVal sender As System.Object, _
 ByVal e As System.EventArgs) Handles cmdConvertToC.Click
        lblBelowFreezing.Visible = False
        lblAboveBoiling.Visible = False
        With moTemp
            .Fahrenheit = txtFahrenheit.Text
            txtCelsius.Text = .GetCelsius
        End With
    End Sub

    Private Sub cmdConvertToF_Click(ByVal sender As System.Object, _
 ByVal e As System.EventArgs) Handles cmdConvertToF.Click
        lblBelowFreezing.Visible = False
        lblAboveBoiling.Visible = False
        With moTemp
            .Celsius = txtCelsius.Text
            txtFahrenheit.Text = .GetFahrenheit
        End With
    End Sub

    Private Sub frmTemperature_Load(ByVal sender As System.Object, _
 ByVal e As System.EventArgs) Handles MyBase.Load
        moTemp = New PhysServer.Temperature()
    End Sub

    Private Sub moTemp_AboveBoiling() Handles moTemp.AboveBoiling
        lblAboveBoiling.Visible = True
    End Sub

    Private Sub moTemp_BelowFreezing() Handles moTemp.BelowFreezing
        lblBelowFreezing.Visible = True
    End Sub

注意 除了库名称之外,此代码与 PhysServerTest 项目的第一个版本中使用的代码完全相同。

试用

若要查看 Temperature 类的运行情况,请执行以下步骤:

  1. F5 启动项目。
  2. 华氏度文本框中输入 77,然后单击“转换为 C”。“摄氏度”框应填充值 25
  3. “摄氏度”框中输入 -17,然后单击“转换为 F”。华氏度框应填充值 1.4,以下冻结! 标签应变为可见。
  4. 关闭窗体以停止项目。

总结

尽管从托管代码调用 COM 组件很简单,但对于大多数应用程序来说,不应将此视为永久性解决方案。 从长远来看,需要将大量使用的组件迁移到本机 .NET 代码。 这将为你提供各种 .NET 功能,并通过消除 RCW 层来加快代码速度。

但是,当你开始将开发从 Visual Basic 移动到 Visual Basic .NET 时,从 .NET 代码调用 COM 组件的能力至关重要。 如你所见,它也很容易实现。 将此技术视为迁移策略的重要组成部分。

关于作者

迈克·金德洛伊 在华盛顿州东部写软件并饲养鸡。 他是 Access 2002 开发人员手册的合著者,也是 Sybex 的SQL Server Developer OLAP 与 Analysis Services 指南的作者。 自史前 Windows 时代以来,他一直在为 Microsoft 产品编写代码,无意很快停止任何时间。

关于 Informant Communications 组

Informant Communications Group, Inc. (www.informant.com) 是一家专注于信息技术行业的多元化媒体公司。 ICG 成立于 1990 年,专门从事软件开发出版物、会议、目录发布和网站。 ICG 在美国和英国设有办事处,是受人尊敬的媒体和营销内容集成商,满足了 IT 专业人员对优质技术信息的需求。

版权所有 © 2001 Informant Communications Group and Microsoft Corporation

技术编辑:PDSA, Inc.或 KNG 咨询