当前位置:编程学习 > VB >>

COM组件对象与.NET类对象的相互转换

运行环境:Visual Studio.NET Beta2, VC7, C#
参考资料:MSDN
级别:入门级


一、前言


COM组件对象与.NET类对象是完全不同的,但为了使COM客户程序象调用COM组件一样调用.NET对象,使.NET程序
象使用.NET对象一样使用COM组件,MS使用了wrapper技术。本文详细介绍了两种不同的wrapper技术,并给出了
简单的代码实例。


二、COM wrapper简介


传统的COM对象与.NET框架对象模型有以下几点不同:
(1)、COM对象的客户必须自己管理COM对象的生存期,而.NET对象的生存期由CLR(Common Language Runtime)来管
理,即通过GC(Garbage Collection)机制自动回收。

(2)、COM对象的客户通过调用QueryInterface查询COM对象是否支持某个接口并得到其接口指针,而.NET对象的客
户使用Reflection(System.Reflection.*)来获得对象功能的描述,包括方法属性等。

(3)、COM对象的客户通过指针引用COM对象,对象在内存中的位置是不变的,而.NET对象在内存中的驻留由.NET框
架执行环境(execution environment)来管理,对象在内存中的位置是可变的,比如出于优化性能的考虑,同时
会更新所有对对象的引用。这一点也是以CLR中不使用指针为前提的。


为了实现传统的COM程序与.NET程序之间的相互调用,.NET提供了包装类RCW(Runtime Callable Wrapper)和
CCW(COM Callable Wrapper)。每当一个.NET客户程序调用一个COM对象的方法时就会创建一个RCW对象,每当一个
COM客户程序调用一个.NET对象的方法时就会创建一个CCW对象。

具体示意图如图1所示:




图1 COM wrapper overview



三、.NET中调用COM组件


1、RCW(Runtime Callable Wrapper)简介
其示意图如图2所示:




图2 Accessing COM objects through the runtime callable wrapper



RCW的主要功能:
(1)RCW实际上是runtime生成的一个.NET类,它包装了COM组件的方法,并内部实现对COM组件的调用。

(2)列集(marshal).NET客户与COM对象之间的调用,列集的对象包括方法的参数返回值等,比如C#中的string与
COM中的BSTR之间的转换。

(3)CLR为每个COM对象创建一个RCW,与对象上的引用数无关,就是说每个COM对象有且只会有一个RCW对象。

(4)RCW中包含了COM对象的接口指针,并管理COM对象的引用计数。RCW自身的释放通过gc机制管理。

2、实例演示
(1)使用VC7/ATL创建一个最简单的COM对象。组件类名叫AtlComServer,实现的接口名叫IAtlComServer,库名叫
AtlServer。添加一属性Name,并实现Get/Set函数。其idl如下所示:

import "oaidl.idl";
import "ocidl.idl";

[
        object,
        uuid(77506E08-D9FB-4F45-85E0-376F5187AF21),
        dual,
        nonextensible,
        helpstring("IAtlComServer Interface"),
        pointer_default(unique)
]

interface IAtlComServer : IDispatch{
        [propget, id(1), helpstring("property Name")] HRESULT Name([out, retval] BSTR* pVal);
        [propput, id(1), helpstring("property Name")] HRESULT Name([in] BSTR newVal);
};

[
        uuid(9136EEE6-ECEE-4237-90B6-C38275EF2D82),
        version(1.0),
        helpstring("AtlServer 1.0 Type Library")
]

library AtlServerLib
{
        importlib("stdole2.tlb");

        [
                uuid(0E733E15-2349-4868-8F86-A2B7FF509493),
                helpstring("AtlComServer Class")
        ]

        coclass AtlComServer
        {
                [default] interface IAtlComServer;
        };
};

(2)创建一个最简单的C# Console程序。执行菜单Project/Add Reference命令,在COM属性页中选中刚才创建的
AtlServer 1.0 Type Library并添加,系统会提示是否添加一个wrapper,选择是,然后会自动在C#程序的
bin目录下生成一个文件Interop.AtlServerLib_1_0.dll,这个就是AtlServer的RCW。另外使用命令行命令
tlbimp atlserver.tlb有同样的效果。

(3)在程序中添加调用AltServer的代码,如下所示:

using System;
using AtlServerLib;     //通过namespace来引用库,在wrapper(即Interop.AtlServerLib_1_0.dll)中定义

namespace CSharpClient
{
        class Class1
        {
                static void Main(string[] args)
                {
                        AtlComServer server = new AtlComServer();
                        server.Name = "Chang Ming";
                        Console.WriteLine("Hello, My Names is " + server.Name);
                }
        }
}

从上面可以看到,AtlServerLib.AtlComServer就代表了COM组件AtlComServer。在传统的COM客户中通过接口
IAtlComServer来调用,而在.NET中只是把它当作了一个普通的.NET类。因为实际上调用的是wrapper中的类,
而不是真正的COM对象。

下载RCW的示例代码(23KB)




四、COM程序中调用.NET对象


1、CCW(COM Callable Wrapper)简介
其示意图如图3所示:




图3 Accessing .NET objects through COM callable wrapper



CCW的主要功能:
(1)CCW实际上是runtime生成的一个COM组件,它在注册表注册,有CLSID和IID,实现了接口,内部包含了对
.NET对象的调用。

(2)列集(marshal).NET对象与COM客户之间的调用。

(3)每个.NET对象只有一个CCW,多个COM客户调用同一个CCW。

(4)COM客户以指针的方式调用CCW,所以CCW分配在non-collected堆上,不受runtime管理。而.NET对象则分配
在garbage-collected堆上,受runtime管理,享受CLR的种种好处。

(5)CCW实际上是COM组件,所以它遵循引用计数规则。当它的引用计数为0时,会释放它对它管理的.NET对象的
引用,并释放自己的内存空间。当.NET对象上引用计数为0时,则会被GC回收。

.NET中受控类型(Manages types)如class、interface、struct和enum都可以无缝的与COM类型相结合,但是要
遵循以下规则:
(1)受控类型必须是public型。只有public型的类型才会被输出到类型库中。

(2)只有public型的methods、properties、fields和events才会被输出到类型库中,才会被COM客户看见。

(3)受控类型必须有一个公用的缺省构造函数。这是因为COM组件要求必须有缺省构造函数。

(4)强烈推荐.NET类中显式地实现接口。如果一个.NET类没有显式地实现一个接口,COM interop会自动为其生
成一个接口,该接口包含了这个.NET类及其父类的所有公有成员。这个被自动生成的接口被称为"class interface"。
但是MS强烈推荐使用显式的接口定义,原因在下面阐述。

2、实例演示一(不显示定义接口)
(1)创建一个最简单的C# Console工程,其程序如下所示:

using System;
using System.Runtime.InteropServices;

namespace CSharpServer
补充:软件开发 , Vb ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,