导读:本文以VB6为例,主要介绍.NET引用COM和COM引用.NET的两个简单示例。
<1>.NET调用COM
为了简单,我们使用VB6,这个据说即将开源的老古董,来制作一个简单的COM。
在VB6中新建一个ActiveX dll工程,只有一个类ComCalc.cls,代码如下:
注意;设置兼容性,并生成dll
然后 ,vs2010中新建一Console项目,微软很奇怪,VB6中的project叫工程,自vs2002起又改名叫“项目”。添加对刚才创建的COM的引用
运行效果:
也许很多人会对这段c#代码很好奇,这个_ComCalc是什么时候产生的?为什么通过它来调用方法,而不是通过类对象?
我们首先看一下,刚才引用COM后,VS IDE为我们做了什么。
请注意,上图中,Interop.SimpleComServer.dll是IDE为我们生成的一个叫“互操作程序集”的东东,而这个东东正是COM和.NET中间的桥梁。
通过对象视图,我们看到_ComCalc正是在这个dll中生成的。我们可以通过OLEView.exe来察看这个Interop.SimpleComServer.dll的Typelib。
如果你已经装全了VB6,你可以在VB目录中找到OLEView.exe,并运行它。如果你没有装全,你可以运行vs2010自带的OLEView.exe,位于
E:\Program Files\Microsoft SDKs\Windows\v7.0A\bin下
找到SimpleComServer,并双击
依据COM规则:COM客户端与COM类进行交互的唯一方式是使用接口引用,而不是对象引用。
如果创建了基于C++的COM客户端,需要特别关注对特定接口的查询过程,如果接口不再被使用,一定要释放它。
如果是VB6创建的客户端,会自动拥有一个默认接口。
现在回到C#代码中来,
_ComCalc itfComInterface = null;//定义COM接口
ComCalcClass comObj = new ComCalcClass();//定义COM类
itfComInterface = (_ComCalc)comObj;//转换为对COM接口的引用
Console.WriteLine("COM server says 10 + 832 is {0}",itfComInterface.Add(10, 832));//调用COM接口的方法
<2>COM调用.NET
记住,COM客户端与COM类进行交互的唯一方式是使用接口引用,而不是对象引用。而.NET不需要任何接口。此时,我们必须确保每个公共成员公开成默认的接口。
我们需要设置[ClassInterface]特性,其属性值可以为以下三个枚举值之一:
AutoDual:指示自动为类生成双重类接口并向 COM 公开。 为该类接口生成类型信息并在类型库中发布。 由于 ClassInterfaceAttribute 中描述的版本控制方面的限制,极力建议不要使用 AutoDual。
AutoDispatch:指示该类只支持 COM
客户端的后期绑定。 在请求时,该类的 dispinterface 将自动向 COM 客户端公开。 Tlbexp.exe(类型库导出程序)
生成的类型库不包含 dispinterface 的类型信息,以防止客户端缓存接口的 DISPID。 由于客户端只能后期绑定到接口,因此
dispinterface 不会出现 ClassInterfaceAttribute 中所述的版本控制问题。
这是 ClassInterfaceAttribute 的默认设置。
None:指示不为类生成类接口。 如果未显式实现任何接口,则该类将只能通过 IDispatch 接口提供后期绑定访问。 这是 ClassInterfaceAttribute 的推荐设置。 要通过由类显式实现的接口来公开功能,唯一的方法是使用 ClassInterfaceType.None。
详见MSDN:(http://msdn.microsoft.com/zh-cn/library/system.runtime.interopservices.classinterfacetype.aspx)
新建一vs2010项目。
注意:作为最佳实践,应该将.NET程序部署到GAC。此时,需要一个SNK文件以供签名。如不部署到GAC,则需要复制到与COM应用程序相同的路径下。
我们选择GAC部署
部署成功!
下来我们需要生成必要的COM类库。可以使用tlbexp.exe命令,当然,通过UI界面,也可以。
现在我们再用OLEView.exe来查看
新建一Vb标准exe工程,并添加引用