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


Aximp相关:http://msdn.microsoft.com/library/en-us/cptools/html/cpgrfwindowsformsactivexcontrolimporteraximpexe.asp