分享
 
 
 

COM Interop 理论与实践

王朝other·作者佚名  2006-01-31
窄屏简体版  字體: |||超大  

COM interop理论/实践

在.NET框架下,开发人员可以通过COM interop tools 将COM组件导入导一个应用中去,一旦导入成功,那么我么就可以非常容易地调用COM接口给我们所提供的方法了。

A .NET Framework developer can incorporate COM components into a managed application by using COM interop tools to import the relevant COM types. Once imported, the COM types are ready to use.

一、COM interop 概述:

COM Interop看上去象是介乎于COM和.Net之间的一条纽带,一座桥梁。为了保持向后兼容,COM Interop可以使得.Net程序在不修改原有COM组件的前提下方便的访问COM组件。这一点是非常重要的。事实上,全球的COM组件的代码量估计可能有数十亿行,拥有这些COM组件的公司不可能重写这些组件,所以COM Interop的存在为有此需求的开发者提供了很好的解决方案。

COM和.NET之间存在着非常大的差异,为了使两者可以有机的结合在一起进行协同工作,COM Interop中实际存在着2种桥接方式。一种是RCW,Runtime Callable Wrapper;另一种是CCW,COM Callable Wrapper。RCW是在运行时通过CLR从Interop装配件(Interop Assembly)的元数据中获取相关信息动态的实例化而得到的。使用者将感觉不到自己是在调用COM组件,一切都是这么的自然,和调用一个.Net组件没有任何区别。

需要注意的是,一个COM组件(指的是一个实例,即一个DLL文件)由且仅由一个RCW负责维护。那么这儿有一个问题了,对于一个COM组件的不同版本,是不是就会有不同的RCW与之相对应呢?答案是肯定的。那有些朋友会说,.Net中的组件不是已经解决了COM中的“DLL HELL”问题了吗?按上面的说法,似乎并没有得到解决嘛?这儿我要说的是,在.Net中导入一个COM组件的不同版本,是会出现此类问题。解决此类问题的方法是使用PIA(Primary Interop Assembly)。

.Net提供三种方法来导入一个COM组件

l 通过Visual Studio .Net提从的“添加引用”功能

l 通过tlbimp.exe实现

l 使用System.Runtime.InteropServices.TypeLibConverter类编程

下面就分别介绍COM的封装、HRESULTs and Exceptions、继承、聚合和包容、如何运用COM interop来生成发出事件和处理事件以及System.Runtime.InteropServices命名空间几个重要的概念

1. COM的封装(COM Wrappers)

l 在一般的语言(诸如C++)当中在客户端我们一定要控制该COM对象的生命周期

l 客户端的COM对象的方法在C++中的调用通过产生该对象的实例同时获得该对象的接口指针,通过接口指针来访问该对象的方法。在.NET框架下则可以直接通过函数的映射来获得(Clients of .NET objects can obtain a description of an object's functionality using Reflection.)

l 在.NET框架下的运行环境中.NET可以在内存中为.NET重新对象分配内存使用。(NET objects reside in memory managed by the .NET Framework execution environment.)

为了解决上述问题,.NET提供一个COM Wrappers.它可以使得Managed Code 和 Unmanaged Code可以很好结合在一起。COM Wrappers两种桥接方式RCW(runtime callable wrapper)和CCW(COM callable wrapper)其中RCW是将Managed的客户端与Unmanaged的服务器端联接起来的;CCW是将Unmanaged的客户端与 Managed的服务器端联接起来的。

2. HRESULTs and Exceptions

在COM编程中我们通过HRESULT来判断所做的操作是否成功,在.NET框架下我们通过抛不同的异常(Throw Exceptions)来捕捉错误。

注MSDN给我们列出了HRESULT不同值与.NET的不同异常的对照表。(.NET Framework Developer’s Guide—HRESULTs and Exceptions)

3. 继承、聚合和包容(Inheritance,Aggregation and Containment)

继承:.NET提供一些标准的接口,用户在定义接口时,可以继承这些接口。

聚合:.NET也支持COM提供的聚合的概念即,外对象将内对象的接口暴露在用户面前。

包容:

通过在外对象的构造函数中创建内对象的实例,这样客户端就可以通过该实例获得接口进行调用接口的各个方法。

4. 如何运用COM interop来生成发出事件和处理事件

在以下内容中,将要描述有关COM对象出接口与事件接收器的连接机制。

关于COM对象的出接口与事件接收器之间的连接机制与在描述COM原理与应用中的机制是一样的,即COM对象声明一个出接口,在事件接收器中表示该接口的实现方法。一旦,COM对象与事件接收器的连接建立好以后,那么客户端就可以随时接收到COM对象服务器端的事件、消息。下面我们从C#的服务器端和事件接收器两个方面来描述这个问题。

Handling Events Raised by a COM Source(描述COM源对象是如何产生一个事件的)

Raising Events Handled by a COM Sink(通过接收器来处理事件)

5. System.Runtime.InteropServices命名空间

System.Runtime.InteropServices是一个有关访问COM对象以及在.NET框架下的本地API函数。在创建COM接口时经常要运用这个命名空间。

二、C#接口编程

下面将从接口的定义、接口的访问、接口的实现以及接口的转换编程这些方面来阐述运用C#进行接口编程的方法。

1. 接口的定义

接口的声明:

[attributes] [modifiers] interface identifier [:base-list] {interface-body}[;]

l attributes(可选):附加的定义性信息。

l · modifiers(可选):允许使用的修饰符有new和四个访问修饰符。分别是:new、public、protected、internal、private。在一个接口定义中同一修饰符不允许出现多次,new修饰符只能出现在嵌套接口中,表示覆盖了继承而来的同名成员。The public, protected, internal, and private修饰符定义了对接口的访问权限。

l 指示器和事件。

l identifier:接口名称。

l base-list(可选):包含一个或多个显式基接口的列表,接口间由逗号分隔。

l interface-body:对接口成员的定义。

l 接口可以是命名空间或类的成员,并且可以包含下列成员的签名: 方法、属性、索引器 。

l 一个接口可从一个或多个基接口继承。

接口的主体:

interface-body: { interface-member-declarationsopt }

接口可以包含一个和多个成员,这些成员可以是方法、属性、索引指示器和事件,但不能是常量、域、操作符、构造函数或析构函数,而且不能包含任何静态成员。接口定义创建新的定义空间,并且接口定义直接包含的接口成员定义将新成员引入该定义空间。

2. 接口的访问

C#中的CASTS来代替QueryInterface

(Using Casts Instead of QueryInterface)

在C++中客户端需要通过QueryInterface来获得COM对象的接口指针。在C#编程中却不必这么麻烦。我们可以直接将COM对象对应到相应的COM接口上。如果我们在程序中对应错误,那么在运行时C#会抛出异常。

3. 接口的实现

显示地实现接口成员即可以直接利用类来实现接口的成员函数如:

// Since the .NET Framework interface and coclass have to behave as

// COM objects, we have to give them guids.

[Guid("DBE0E8C4-1C61-41f3-B6A4-4E2F353D3D05")]

public interface IManagedInterface

{

int PrintHi(string name);

}

[Guid("C6659361-1625-4746-931C-36014B146679")]

public class InterfaceImplementation : IManagedInterface

{

public int PrintHi(string name)

{

Console.WriteLine("Hello, {0}!", name);

return 33;

}

}

通过为Coclass的方法来实现接口如:

[Guid("56A868B1-0AD4-11CE-B03A-0020AF0BA770"),

InterfaceType(ComInterfaceType.InterfaceIsDual)]

interface IMediaControl // Cannot list any base interfaces here

{ // COM methods }

// Declare FilgraphManager as a COM coclass:

[ComImport, Guid("E436EBB3-524F-11CE-9F53-0020AF0BA770")]

class FilgraphManager // Cannot have a base class or

// interface list here.

{

// Cannot have any members here

// NOTE that the C# compiler will add a default constructor

// for you (no parameters).

}

其中类FilgraphManager实现了ImediaControl的方法其中ComImport--它将类标记为在外部实现的 COM 类。

4. 接口的转换编程

运用C#开发COM组件服务器端

l 声明一个COM接口(Declaring a COM Interface):

首先声明一个COM接口我们必须要明确该接口是继承IUnknown or IDispatch或者其他接口。运用C#描述这方面内容必须使用C#提供的属性InterfaceType(InterfaceType – 表明接口是继承于 IUnknown or IDispatch)

其次,为了使COM接口中出现成员函数,程序中也要指出ComImport and Guid属性。(Guid—表明接口或者coclass的唯一标示号;ComImport—它将类标记为在外部实现的 COM 类。)

注:coclass是(简称组件对象类――component object class)被包含在DLL或EXE中,并且包含着一个或者多个接口的代码。客户端通过创建该对象的实例来获得COM对象的接口。

例子代码:

[Guid("56A868B1-0AD4-11CE-B03A-0020AF0BA770"),

InterfaceType(ComInterfaceType.InterfaceIsDual)]

interface IMediaControl // Cannot list any base interfaces here

{

// COM methods

}

l 声明一个组件对象类(Declaring a COM coclass)

1. 该类不可以继承于其他类。

2. 也不可以实现任何接口。

3. 必须有一个Guid来唯一标示该类

例子代码:

// Declare FilgraphManager as a COM coclass:

[ComImport, Guid("E436EBB3-524F-11CE-9F53-0020AF0BA770")]

//"E436EBB3-524F-11CE-9F53-0020AF0BA770"标示号在系统注册表中可以找到,说明//此处是调用外部的COM类来实现接口ImediaControl的。

class FilgraphManager // Cannot have a base class or

// interface list here.

{

// Cannot have any members here

// NOTE that the C# compiler will add a default constructor

// for you (no parameters).

}

运用C#开发COM组件客户端

l C#中的CASTS来代替QueryInterface

(Using Casts Instead of QueryInterface)

在C++中客户端需要通过QueryInterface来获得COM对象的接口指针。在C#编程中却不必这么麻烦。我们可以直接将COM对象对应到相应的COM接口上。如果我们在程序中对应错误,那么在运行时C#会抛出异常。

例子代码:

// Create an instance of a COM coclass:

FilgraphManager graphManager = new FilgraphManager();

// See if it supports the IMediaControl COM interface.

// Note that this will throw a System.InvalidCastException if

// the cast fails. This is equivalent to QueryInterface for

// COM objects:

IMediaControl mc = (IMediaControl) graphManager;

// Now you call a method on a COM interface:

mc.Run();

l C#运用抛异常的机制来代替HRESULT

在创建COM对象实例以及获得接口时可能都会出现问题,在C++中我们通过调用HRESULT来判断所做的操作是否成功。但是,在C#编程中我们就不必那么麻烦,C#会抛出诸如System.COMException的异常。

三、关于C#中几个工具的用法

1. Tlbimp.exe的用法:

该工具适合将*.tlb的类库文件可以转换成*.dll的文件,同时该工具还可以将一个dll输出到一个新的dll文件当中去。

例:tlbimp myTest.tlb

输出 MYTESTLIB.dll的动态联接库文件

tlbimp myTest.tlb /out:myTest.dll

输出生成 myTest.dll的文件

tlbimp c:\winnt\system32\quartz.dll /out:QuartzTypeLib.dll

将quartz.dll包含到QuartzTypeLib.dll中去。

2. Ildasm工具可以查看*.dll, *.exe, .obj, .lib 文件

例如可以查看.dll的具体情况比如接口、实现类以及成员函数等信息。

如:可以通过命令Ildasm *.dll来查看具体生成的dll的情况。

3. Regasm工具用于将dll动态联接库注册到注册表中的操作

如:Regasm QuartzTypeLib.dll

就将QuartzTypeLib.dll注册到注册表中去。

如果要解除刚才的注册操作可以运用

Regasm /unregister QuartzTypeLib.dll命令即可。

4. CSC工具的使用是编译C#文件*.cs为exe或者dll文件的工具

如:csc File.cs 就是将File.cs编译为File.exe文件

csc /out:my.exe File.cs将File.cs文件编译为my.exe

csc /target:library File.cs就是将File.cs编译为File.dll文件

5.guidgen工具用于生成Guid号

在C#中使用工具

$\Microsoft Visual Studio .NET 2003\Common7\Tools\$下的工具

guidgen.exe生成一个随机的GUID号。

三、 运用C#开发COM的组件的简单例子

功能概述此例子非常简单就是在服务器端写一个具有现实Hello, **的方法

客户端通过调用服务器端的PrintHi(String name)函数显示出 Hello, **的信息。

服务器端代码:

//Copyright (C) 2000 Microsoft Corporation. All rights reserved.

// ShiServer.cs

// compile with: /target:library

using System;

using System.Runtime.InteropServices;

namespace ShiServer

{

// Since the .NET Framework interface and coclass have to behave as

// COM objects, we have to give them guids.

[Guid("976F8704-6E29-4b67-AC4F-A5B1226D1F49")]

public interface IshiInterface

{

int PrintHi(string name);

}

[Guid("2BDD9B83-E4FC-432a-BBE1-F71C05723AB6")]

public class IshiImplementation : IshiInterface

{

public int PrintHi(string name)

{

Console.WriteLine("Hello, {0}!", name);

return 33;

}

}

}

客户端代码:

//Copyright (C) 2000 Microsoft Corporation. All rights reserved.

// shi.cs

// Build with "csc /R:ShiServer.dll shi.cs"

using System;

class MainClass

{

/************************************************************

show Hello,sname

**************************************************************/

public static void Main(string[] args)

{

// input a name

string sname = args[0];

// Create instance of ShiServer

// (Calls CoCreateInstance(D3E09FD9-B987-47f3-89CB-95EFB4D68583,

// NULL, CLSCTX_ALL, IID_IUnknown, &myHello).

// Returns null on failure):

ShiServer.IshiImplementation myHello=

new ShiServer.IshiImplementation();

// QueryInterface for the IshiInterface interface:

ShiServer.IshiInterface myIhello=

(ShiServer.IshiInterface)myHello;

// Call some methods on a COM interface

myIhello.PrintHi(sname);

}

}

输入: shi stonewall 输出:Hello, stonewall

注:以上资料均来自于

MSDN Library –January 2002

TiTle: C# Programmer’s Reference COM Interop Tutorials

COM interop 概述 http://www.xmlasp.net/n966c13.aspx

What’s new for Interop in .NET Framework v2.0? http://www.dotnetinterop.com/features/default.aspx?q=Whidbey

C#COM接口编程

http://tech.ccidnet.com/pub/disp/Article?columnID=295&articleID=40725&pageNO=1

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有