走近COM Interop--编程以实现COM-->Assembly

  这篇文章是《走近COM Interop》系列的最后一篇,也是涉及技术点最多的一篇。希望我的描述大家能看到懂 emsmile.gif,难免有错,请各位不吝赐教。
  书归正传,我开始介绍如果通过编程的方式导入一个COM组件,并生成相应的.Net Assembly。其实,过程非常简单,个人认为只是自己实现了TLBIMP.EXE做的事情而已。(当然,也可以实现TLBEXP.EXE的功能,只是它属于CCW的范畴,这儿就不多说了。)

一、准备工作
  具体说来,编程实现COM-->Assembly的功能,需要使用的以前几个类:
   System.Runtime.InteropServices
   -TypeLibConverter      
提供一组服务,将托管程序集转换为 COM 类型库或进行反向转换。
   -ITypeLibImporterNotifySink   提供回调机制,以供类型库转换器向调用方通知转换的状态,并在转换过程本身之中涉及调用方。
  System.Reflection
   -StrongNameKeyPair(可选)  
封装对公钥或私钥对的访问,该公钥或私钥对用于为强名称程序集创建签名。
  System.Reflection.Emit
   -AssemblyBuilder                           
定义并表示动态程序集。

  此外,还需要使用一个WinAPI,LoadTypeLibEx,具体定义如下:
    [DllImport( "oleaut32.dll", CharSet = CharSet.Unicode, PreserveSig = false )]
          private static extern void LoadTypeLibEx(String strTypeLibName, RegKind regKind, [MarshalAs(UnmanagedType.Interface)] out     Object typeLib );
  
为了让这个WinAPI function可以正常使用,我们还需要定义一个枚举,
None.gifprivate enum  RegKind
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
InBlock.gif    RegKind_Default 
= 0
,
InBlock.gif    RegKind_Register 
= 1
,
InBlock.gif    RegKind_None 
= 2

ExpandedBlockEnd.gif}

None.gif


  注:上述类的说明来自MSDN。

  大家都看到了,上述几个类中,仅有StrongNameKeyPair是可选的,这是因为如果我们不需要生成PIA,那么是不需要使用这个类的。同时,如果需要生成PIA,那么需要提供相应的密钥文件。在后面的描述中,我们将使用《 走近COM Interop--浅谈PIA》中的例子做进一步的演示。

二、实战 演练
  在此,我们仍就由VB生成的PIADemo.dll展开演示。
1. 载入一个COM组件
None.gif Object typeLib;
None.gifLoadTypeLibEx(
" PIADemo.dll " , RegKind.RegKind_None,  out  typeLib); 
None.gif        
None.gif
if (typeLib  ==   null  )
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif  
throw new Exception("载入失败!");
ExpandedBlockEnd.gif}

2. 定义一个实现ITypeLibImporterNotifySink接口的类,基于提供回调机制,以供类型库转换器向调用方通知转换的状态,并在转换过程本身之中涉及调用方。
None.gif public   class  ConversionEventHandler: ITypeLibImporterNotifySink
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
public void ReportEvent(ImporterEventKind eventKind, int eventCode, string eventMsg )
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
// Do nothing.
ExpandedSubBlockEnd.gif
    }

InBlock.gif    
InBlock.gif    
public Assembly ResolveRef(object typeLib)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif  
// 此处直接返回null,避免把演示复杂化了
InBlock.gif
        return null
ExpandedSubBlockEnd.gif    }
    
ExpandedBlockEnd.gif}

None.gif

3. 将COM类型库生成程序集
 A. 生成PIA Assembly
None.gif FileStream stream  =   new  FileStream( " common.snk " , FileMode.Open);
None.gif
try
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    StrongNameKeyPair pair 
= new StrongNameKeyPair(stream);
InBlock.gif    TypeLibConverter converter 
= new TypeLibConverter();
InBlock.gif    ConversionEventHandler eventHandler 
= new ConversionEventHandler();
InBlock.gif    AssemblyBuilder ab 
= converter.ConvertTypeLibToAssembly(typeLib, "interop.PIADemo.dll", TypeLibImporterFlags.PrimaryInteropAssembly, eventHandler, null, pair, nullnull);    
InBlock.gif    ab.Save(
"interop.PIADemo.dll");
InBlock.gif
InBlock.gif    MessageBox.Show(
"Importing is ok.");
InBlock.gif
InBlock.gif    Assembly asm 
= Assembly.LoadFile(Application.StartupPath + @"\interop.PIADemo.dll");
InBlock.gif    Type t 
= asm.GetType("interop.PIADemo.TestClass");
InBlock.gif    
object obj = t.InvokeMember(null, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance, nullnullnull);
InBlock.gif    
string ret = (string)t.InvokeMember("Format", BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | 
ExpandedSubBlockStart.gifContractedSubBlock.gifBindingFlags.Instance 
| BindingFlags.InvokeMethod, null, obj, new object[]dot.gif{"Go!"});
InBlock.gif    MessageBox.Show(ret);
ExpandedBlockEnd.gif}

None.gif
catch (Exception ep)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
if(stream != null)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        stream.Close();
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    MessageBox.Show(ep.Message);
ExpandedBlockEnd.gif}

 B. 生成一般的Assembly
None.gif TypeLibConverter converter  =   new  TypeLibConverter();
None.gifConversionEventHandler eventHandler 
=   new  ConversionEventHandler();
None.gifAssemblyBuilder ab 
=  converter.ConvertTypeLibToAssembly(typeLib,  " interop.PIADemo.dll " 0
None.gifeventHandler, 
null null null null );    
None.gifab.Save(
" interop.PIADemo.dll " );
None.gif
None.gifMessageBox.Show(
" Importing is ok. " );
None.gif
None.gifAssembly asm 
=  Assembly.LoadFile(Application.StartupPath  +   @" \interop.PIADemo.dll " );
None.gifType t 
=  asm.GetType( " interop.PIADemo.TestClass " );
None.gif
object  obj  =  t.InvokeMember( null , BindingFlags.DeclaredOnly  |  BindingFlags.Public  |  BindingFlags.NonPublic  |  BindingFlags.Instance  |  BindingFlags.CreateInstance,  null null null );
None.gif
string  ret  =  ( string )t.InvokeMember( " Format " , BindingFlags.DeclaredOnly  |  BindingFlags.Public  |  BindingFlags.NonPublic  |  
   BindingFlags.Instance 
|  BindingFlags.InvokeMethod,  null , obj,  new   object [] {"Go!"} );
None.gifMessageBox.Show(ret);

 需要说明几点:
 1. 上述示例中使用的PIADemo.dll和Common.snk都需要被copy至测试程序的bin目录中,否则,就需要指定可达到的文件路径。
 2. Assembly.LoadFile的参数是要加载的文件的绝对路径,相对路径将会引发异常。

  至此,本系列文章全部完成。因本人水平有限,有不对的地方,欢迎指正。

转载于:https://www.cnblogs.com/TonyJoule/archive/2005/01/28/98892.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值