我用TypeLibConverter的ConvertTypeLibToAssembly函数进行转换,如果转换的com组件比较小时蛮快的,如果转换Access或者Excel的组件时就需要很长时间,没有用tlbimp这个工具转换那么快。求教如何用代码来实现快速转换。

解决方案 »

  1.   

    http://www.cnblogs.com/tonyjoule/archive/2005/01/28/98892.html
    tlbimp 
      

  2.   

    http://www.cnblogs.com/tonyjoule/archive/2005/01/28/98892.html
    tlbimp 
      

  3.   

    这篇文章是《走近COM Interop》系列的最后一篇,也是涉及技术点最多的一篇。希望我的描述大家能看到懂,难免有错,请各位不吝赐教。 
      书归正传,我开始介绍如果通过编程的方式导入一个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可以正常使用,我们还需要定义一个枚举, 
    private enum RegKind 

        RegKind_Default = 0, 
        RegKind_Register = 1, 
        RegKind_None = 2 
    }   注:上述类的说明来自MSDN。   大家都看到了,上述几个类中,仅有StrongNameKeyPair是可选的,这是因为如果我们不需要生成PIA,那么是不需要使用这个类的。同时,如果需要生成PIA,那么需要提供相应的密钥文件。在后面的描述中,我们将使用《走近COM Interop--浅谈PIA》中的例子做进一步的演示。 二、实战演练 
      在此,我们仍就由VB生成的PIADemo.dll展开演示。 
    1. 载入一个COM组件 
    Object typeLib; 
    LoadTypeLibEx("PIADemo.dll", RegKind.RegKind_None, out typeLib);  
             
    if(typeLib == null ) 

      throw new Exception("载入失败!"); 
    }2. 定义一个实现ITypeLibImporterNotifySink接口的类,基于提供回调机制,以供类型库转换器向调用方通知转换的状态,并在转换过程本身之中涉及调用方。 
    public class ConversionEventHandler: ITypeLibImporterNotifySink 

        public void ReportEvent(ImporterEventKind eventKind, int eventCode, string eventMsg ) 
        { 
            // Do nothing. 
        } 
         
        public Assembly ResolveRef(object typeLib) 
        { 
       // 此处直接返回null,避免把演示复杂化了 
            return null;  
        }     

    3. 将COM类型库生成程序集 
     A. 生成PIA Assembly 
    FileStream stream = new FileStream("common.snk", FileMode.Open); 
    try 

        StrongNameKeyPair pair = new StrongNameKeyPair(stream); 
        TypeLibConverter converter = new TypeLibConverter(); 
        ConversionEventHandler eventHandler = new ConversionEventHandler(); 
        AssemblyBuilder ab = converter.ConvertTypeLibToAssembly(typeLib, "interop.PIADemo.dll", TypeLibImporterFlags.PrimaryInteropAssembly, eventHandler, null, pair, null, null);     
        ab.Save("interop.PIADemo.dll"); 
     
        MessageBox.Show("Importing is ok."); 
     
        Assembly asm = Assembly.LoadFile(Application.StartupPath + @"\interop.PIADemo.dll"); 
        Type t = asm.GetType("interop.PIADemo.TestClass"); 
        object obj = t.InvokeMember(null, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance, null, null, null); 
        string ret = (string)t.InvokeMember("Format", BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic |  
    BindingFlags.Instance | BindingFlags.InvokeMethod, null, obj, new object[]{"Go!"}); 
        MessageBox.Show(ret); 

    catch(Exception ep) 

        if(stream != null) 
        { 
            stream.Close(); 
        } 
     
        MessageBox.Show(ep.Message); 
    } B. 生成一般的Assembly 
    TypeLibConverter converter = new TypeLibConverter(); 
    ConversionEventHandler eventHandler = new ConversionEventHandler(); 
    AssemblyBuilder ab = converter.ConvertTypeLibToAssembly(typeLib, "interop.PIADemo.dll", 0,  
    eventHandler, null, null, null, null);     
    ab.Save("interop.PIADemo.dll"); 
     
    MessageBox.Show("Importing is ok."); 
     
    Assembly asm = Assembly.LoadFile(Application.StartupPath + @"\interop.PIADemo.dll"); 
    Type t = asm.GetType("interop.PIADemo.TestClass"); 
    object obj = t.InvokeMember(null, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance, null, null, null); 
    string ret = (string)t.InvokeMember("Format", BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic |  
       BindingFlags.Instance | BindingFlags.InvokeMethod, null, obj, new object[]{"Go!"}); 
    MessageBox.Show(ret); 需要说明几点: 
     1. 上述示例中使用的PIADemo.dll和Common.snk都需要被copy至测试程序的bin目录中,否则,就需要指定可达到的文件路径。 
     2. Assembly.LoadFile的参数是要加载的文件的绝对路径,相对路径将会引发异常。   至此,本系列文章全部完成。因本人水平有限,有不对的地方,欢迎指正。