0、前言
C#总的来说不错,Framework也提供了比较丰富的类库,基本上能够满足大部分的需要。但是应用程序难免要和遗留系统打交道,比如说:API函数或者COM组件。
#中调用COM组件经常遇到的集中情况进行说明。
1、引用一个COM组件,通过New创建
大部分情况下调用COM组件是非常简单的时候,在工程中引用COM组件对应的文件就行了,“Project->References->Add Reference...”。
我们会发现自动生成了一个interop.xyz.dll之类的文件,这个文件中包含了一大堆定义,它其实就是将COM组件中的Interface、CoClass、Enum和Const等重新包装成为符合Framework的形式,接下来我们就可以在程序中直接使用了。DotNet Framework有一个配套的工具tlbimp.exe,可以自己手动进行转换。
例如在Windows XP SP2下,在工程中引用了%System32%/hnetcfg.dll后,就可以直接写这样的代码:
NETCONLib.NetSharingManagerClass iManager = new NETCONLib.NetSharingManagerClass();
iManager就是一个类的实例,可以相调用Framework类库中其他的类实例一样使用。
如果是控件,也差不多,在工具栏上执行“Add/Remove Items...”的动作,选择控件对应的DLL或者OCX,然后就可以像Framework下的控件一样使用。
控件通常会生成两个文件:axinterop.xyz.dll,包含ConnectionPoint的信息;interop.xyz.dll,CoClass和Interface等的定义,通常不需要关心这些细节。DotNet Framework有一个配套的工具aximp.exe,也可以自行转换。
2、不引用COM组件进行调用
此外有些组件只暴露接口,没有暴露实现接口的CoClass或者没有暴露实现接口的CoClass的构造函数,这个时候我们没有办法通过new的方式创建实例,就比如说上面的例子。同样引用hnetcfg.dll,其中NetFwTypeLib命名控件下只有接口的定义,这个时候下面的代码运行时会产生找不到构造函数的错误:
NetFwTypeLib.INetFwMgr iFwMgr = new NetFwTypeLib.INetFwMgr(); // Error!
没有办法了么?当然不是。COM组件实现的接口如果可以被外界创建,即便是不暴露CoClass,也可以通过ClassFactory的方式去创建实例。
我们知道VB和VBS等脚本语言有一个特性,叫后期绑定,就是不引用类型库,直接通过CreateObject创建对象并且使用。C#中也有类似的方法,通过调用Activator.CreateInstance实现等同CreateObject的功能。具体步骤如下:
Type typFwMgr = null;
NetFwTypeLib.INetFwMgr iFwMgr = null;
...
typFwMgr = Type.GetTypeFromCLSID(new Guid("{304CE942-6E39-40D8-943A-B913C40C9CD4}"));
iFwMgr = (NetFwTypeLib.INetFwMgr) Activator.CreateInstance(typFwMgr);
在这种情况下可以不引用类型库,直接通过Type.InvokeMember去调用方法,参考代码如下:
Type typFwMgr = null;
...
typFwMgr = Type.GetTypeFromCLSID(new Guid("{304CE942-6E39-40D8-943A-B913C40C9CD4}"));
Object objFwMgr = (NetFwTypeLib.INetFwMgr) Activator.CreateInstance(typFwMgr);
typFwMgr = objFwMgr.GetType();
typFwMgr.InvokeMember(...);
这样的方式就很灵活了,C#一样可以用后期绑定的方法是用COM组件,在调用具体方法时会麻烦一点。
3、在另一个AppDomain创建COM实例
还有一种情况,应用程序中可能有多个AppDomain,希望在另一个AppDomain上创建一个实例。AppDomain为应用程序执行提供了独立的运行空间,通常Remoting的应用的时候有用。这里稍稍提一下调用方式:
AppDomain newDomain = AppDomain.CreateDomain("Test");
System.Runtime.Remoting.ObjectHandle objhdlManager = newDomain.CreateComInstanceFrom("interop.netconlib.dll","NETCONLib.NetSharingManagerClass");
NETCONLib.NetSharingManagerClass iManager = (NETCONLib.NetSharingManagerClass) objhdlManager.Unwrap();
和当年COM+ Component的应用有几分相似亚。
综上应该能够涵盖绝大多数情况下COM组件的调用了,创建实例之后具体的使用就非常简单了。COM的应用广泛,熟练掌握COM组件的使用对开发会相当有帮助的。
参考文档
Tlbimp相关:http://msdn.microsoft.com/library/en-us/cptools/html/cpgrfTypeLibraryImporterTlbimpexe.asp