没有合适的资源?快使用搜索试试~ 我知道了~
.NET与COM的互操作性.pdf
4星 · 超过85%的资源 需积分: 10 42 下载量 178 浏览量
2009-01-17
19:08:22
上传
评论
收藏 1.87MB PDF 举报
温馨提示
试读
38页
.NET与COM的互操作性.pdf.NET与COM的互操作性.pdf.NET与COM的互操作性.pdf.NET与COM的互操作性.pdf.NET与COM的互操作性.pdf.NET与COM的互操作性.pdf
资源推荐
资源详情
资源评论
COM 的互操作性
如果您在学习.NET 之前编写过 Windows 程序,通常没有时间和资源用.NET 再重新编
写以前的程序。有时重写代码有助于做一些修订,重新思考应用程序的体系架构,从长远
来看,还有助于提高效率,更便于用新技术添加新特性。但是,我们不会为使用一种新技
术而重写已有的代码。我们本来有数千行可运行的代码,重写它们需要的精力太多,还不
如把它们迁移到托管的环境中。
这也同样适用于 Microsoft。在命名空间 System.DirectoryService 中,Microsoft 并没有
重新编写 COM 对象来访问有层次的数据存储,这个命名空间中的类实际上是访问 ADSI
COM 对象的包装器。System.Data.OleDb 命名空间也是这样,由这个命名空间中的类所使
用的 OLE DB 提供程序包含相当复杂的 COM 接口。
我们自己的解决方案也会面临相同的问题。如果在.NET 应用程序中要使用已有的
COM 对象,或者要编写在旧 COM 客户程序中使用的.NET 组件,就应使用本章介绍的 COM
互操作性。
如果没有要与应用程序集成的 COM 组件,或旧 COM 客户程序要使用一些.NET 组件,
就应跳过本章。
本章主要内容如下:
● COM 和.NET 技术
● 在.NET 应用程序中使用 COM 对象
● 在 COM 客户程序中使用.NET 组件
● 调用本地方法的 Platform Invoke(平台调用)
与其他章节一样,本章的示例代码也可以从 Wrox 网站 www.wrox.com 上下载。
23.1 .NET 和 COM
COM 是.NET 以前的技术。COM 定义了一个组件模型,在该模型中,组件可以用不同
的编程语言编写。用 C++编写的组件可以在 VB 客户程序中使用。组件还可以在本地的进
程中使用,跨进程使用或在网络上使用。看起来是不是很熟悉?当然,.NET 的目标也是这
样。但这些目标的实现方式是不同的。COM 概念使用起来越来越复杂,已经不能扩展
第 章
23
0
第Ⅲ部分 基 类 库
692
了。.NET 达到了与 COM 类似的目标,但引入了新概念,实现起来更容易。
即使到了今天,使用 COM 和.NET 交互操作的主要问题是要理解 COM。是 COM 客
户程序使用.NET 组件,还是.NET 应用程序使用 COM 组件并不重要,而是必须理解 COM。
所以这里首先比较 COM 和.NET。
如果您已经熟练掌握了 COM 技术,本节将是 COM 知识的复习。否则,您将学习到
COM 的概念—— 现在是使用.NET—— 我们不再需要在日常事务中处理它了。但是,在把
COM 技术集成到.NET 应用程序中时,COM 的问题仍旧存在。
COM 和.NET 有许多类似的概念和不同的解决方案。下面将讨论:
● 元数据
● 释放内存
● 接口
● 方法绑定
● 数据类型
● 注册
● 线程
● 错误处理
● 事件处理
23.1.1 元数据
在 COM 中,组件的所有信息都存储在类型库中。类型库包含的信息有接口、方法和
参数的名称和 ID 等。而在.NET 中,所有这些信息都可以存储在程序集中,如第 12 章和第
16 章所述。COM 存在的问题是,类型库是不能扩展的。在 C++中,IDL(接口定义语言)文
件用于描述接口和方法。其中一些 IDL 修饰符不在类型库中,因为 Visual Basic(和负责开
发类型库的 Visual Basic 小组)不能使用这些 IDL 修饰符。而在.NET 中,不存在这个问题,
因为.NET 元数据可以使用定制特性来扩展。
因此,一些 COM 组件有类型库,而其他 COM 组件没有。如果没有类型库可用,就
可以使用 C++头文件来描述接口和方法。在.NET 中,使用带有类型库的 COM 组件是比较
容易的,也可使用不带类型库的 COM 组件。在这种情况下,必须使用 C#代码重新定义
COM 接口。
23.1.2 释放内存
在.NET 中,内存的释放是由垃圾收集器完成的。这完全不同于 COM,COM 依赖的
是引用数。
接口 IUnknown 是每个 COM 对象必须实现的一个接口,它提供了 3 个方法。其中两
个方法与引用数有关。如果需要另一个接口指针,客户程序就必须调用方法 AddRef(),这
个方法会递增引用数。方法 Release()会递减引用数,如果所得的引用数是 0,就销毁对象,
释放内存。
第 23 章 COM 的互操作性
693
23.1.3 接口
接口是 COM 的核心,它区分了在客户程序和对象之间使用的契约和实现方式。接口(契
约)定义了由组件提供的方法,可以由客户程序使用。而在.NET 中,接口也有非常重要的
作用。
COM 有 3 种接口类型:定制接口、分派接口(dispatch interface)和双重接口。
1. 定制接口
定制接口派生自接口 IUnknown。定制接口定义了虚拟表(vtable)中的方法顺序,所以
客户程序可以直接访问接口的方法。这也表示在开发阶段客户程序需要知道虚拟表,因为
方法的绑定是使用内存地址进行的。因此,定制接口不能由脚本客户程序使用。图 23-1 显
示了定制接口 IMath 的虚拟表,除了接口 IUnknown 的方法之外,该接口还提供了方法 Add()
和 Sub()。
图 23-1
2. 分派接口
因为脚本客户程序(和早期的 Visual Basic 客户程序)不支持定制接口,所以需要另外一
种接口类型,而在分派接口中,可用于客户程序的接口总是 IDispatch 接口。IDispatch 接
口派生自 IUnknown 接口,除了接口 IUnknown 的方法之外,它还提供了 4 个方法,其中
两个比较重要的方法是 GetIDsOfNames()和 Invoke()。如图 23-2 所示,在分派接口中需要
两个表。第一个表把方法或特性名映射到分派 ID(dispatch id),第二个表把分派 ID 映射到
方法或特性的实现代码。
图 23-2
第Ⅲ部分 基 类 库
694
在客户程序调用组件中的方法时,要先调用方法 GetIDsOfNames(),并给它传送要调
用的方法名。方法 GetIDsOfNames()会查找名称-ID 表,返回分派 ID,客户程序再使用这
个 ID 调用方法 Invoke()。
注意:
通常,IDispatch 接口的两个表存储在类型库中,但这不是必需的,一些组件把这两个
表存储在其他地方。
3. 双重接口
可以想像,分派接口比定制接口慢得多。另一方面,脚本客户程序不能使用定制接口。
双重接口可以解决这个问题。如图 23-3 所示,双重接口派生自 IDispatch 接口,但提供了
可以在虚拟表中直接使用的接口方法。脚本客户程序可以使用 IDispatch 接口调用方法,而
了解虚拟表的客户程序可以直接调用方法。
图 23-3
4. 强制类型转换和 QueryInterface
如果.NET 类实现多个接口,就可以进行强制类型转换,得到一个接口或另一个接口。
而在 COM 中,接口 IUnknown 通过方法 QueryInterface()提供了类似的机制。如上一节所
述,接口 IUnknown 是其他接口的基础接口,所以可以以任何方式使用方法 QueryInterface()。
23.1.4 方法绑定
客户程序映射方法的方式是用早期绑定和后期绑定来定义的。后期绑定表示要调用的
方法是在运行期间确定的。.NET 使用 System.Reflection 命名空间来实现后期绑定(参阅第
12 章)。
COM 使用上面讨论的 IDispatch 接口进行后期绑定。后期绑定可以使用分派接口和双
重接口来实现。
在 COM 中,早期绑定有两个不同的选项。早期绑定的一种方式也称为虚拟表绑定,
它直接使用虚拟表,可以通过定制接口和双重接口来实现。早期绑定的第二种方式也称为
第 23 章 COM 的互操作性
695
id 绑定。其中分派 id 存储在客户程序代码中,在运行期间只需要调用一次 Invoke()。
GetIdsOfNames()方法在设计期间调用。对于这种客户程序,记住不必改变分派 id 是非常重
要的。
23.1.5 数据类型
对于双重接口和分派接口,COM 能使用的数据类型被局限于一个自动兼容的数据类
型列表。接口 IDispatch 的 Invoke()方法接收 VARIANT 数据类型的数组。VARIANT 是许
多不同数据类型的组合,例如 BYTE、SHORT、LONG、FLOAT、DOUBLE、BSTR、
IUnknown*、IDispatch*等。VARIANT 在 Visual Basic 中很容易使用,但在 C++中使用时就
比较复杂了。在.NET 中,使用 Object 类代替了 VARIANT。
在定制接口中,C++能使用的所有数据类型也可用于 COM。但是,使用这个组件的客
户程序只能采用某些语言来编程。
23.1.6 注册
.NET 区分了私有程序集和共享程序集,详见第 16 章。而在 COM 中,所有的组件都
进行了注册配置,是全局可用的。
所有的 COM 对象都有一个唯一的标识符,该标识符由一个 128 位的数字组成,也称
为类 ID(CLSID)。创建 COM 对象时,COM API 调用 CoCreateInstance()会在注册表中查找
CLSID 和 DLL 或 EXE 的路径,然后加载 DLL 或启动 EXE,并实例化组件。
这个 128 位数字不容易记忆,所以许多 COM 对象还有一个 prog id,该 id 很容易记忆,
例如 Excel.Application 就映射到一个 CLSID。
除了 CLSID 之外,COM 对象还为每个接口和类型库指定了一个唯一的标识符(IID
和 typelib id)。
本章的后面将详细讨论注册表中的信息。
23.1.7 线程
COM 使用了单元模型,这样程序员就不必考虑线程问题了。但是,这也增加了复杂
性。不同的操作系统版本添加了不同的单元类型。本节讨论单线程单元和多线程单元。
注意:
.NET 中的线程详见第 18 章。
1. 单线程单元
单线程单元(STA)是在 Windows NT 3.51 中引入的。在 STA 中,只允许一个线程(创建
实例的线程)访问组件。但是,在一个进程中允许有多个单线程单元,如图 23-4 所示。
剩余37页未读,继续阅读
资源评论
- bjfriday2012-04-25很好,很清晰!不过只有该书的一部分。
zhaoyunlong
- 粉丝: 12
- 资源: 105
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功