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

原创 2011年01月10日 14:25:00
LINK:http://www.cnblogs.com/TonyJoule/archive/2005/01/28/98892.html

这篇文章是《走近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.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.gifObject typeLib;
None.gifLoadTypeLibEx("PIADemo.dll", RegKind.RegKind_None, out typeLib);
None.gif
None.gifif(typeLib == null )
ExpandedBlockStart.gif{
InBlock.gif throw new Exception("载入失败!");
ExpandedBlockEnd.gif}

2. 定义一个实现ITypeLibImporterNotifySink接口的类,基于提供回调机制,以供类型库转换器向调用方通知转换的状态,并在转换过程本身之中涉及调用方。

None.gifpublic class ConversionEventHandler: ITypeLibImporterNotifySink
ExpandedBlockStart.gif{
InBlock.gif public void ReportEvent(ImporterEventKind eventKind, int eventCode, string eventMsg )
ExpandedSubBlockStart.gif {
InBlock.gif // Do nothing.
ExpandedSubBlockEnd.gif    }
InBlock.gif
InBlock.gif public Assembly ResolveRef(object typeLib)
ExpandedSubBlockStart.gif {
InBlock.gif // 此处直接返回null,避免把演示复杂化了
InBlock.gif return null;
ExpandedSubBlockEnd.gif    }
ExpandedBlockEnd.gif}
None.gif

3. 将COM类型库生成程序集
A. 生成PIA Assembly

None.gifFileStream stream = new FileStream("common.snk", FileMode.Open);
None.giftry
ExpandedBlockStart.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, null, null);   
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, null, null, null);
InBlock.gif string ret = (string)t.InvokeMember("Format", BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic |
ExpandedSubBlockStart.gifBindingFlags.Instance | BindingFlags.InvokeMethod, null, obj, new object[]{"Go!"});
InBlock.gif    MessageBox.Show(ret);
ExpandedBlockEnd.gif}
None.gifcatch(Exception ep)
ExpandedBlockStart.gif{
InBlock.gif if(stream != null)
ExpandedSubBlockStart.gif {
InBlock.gif        stream.Close();
ExpandedSubBlockEnd.gif    }
InBlock.gif
InBlock.gif    MessageBox.Show(ep.Message);
ExpandedBlockEnd.gif}

B. 生成一般的Assembly

None.gifTypeLibConverter 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.gifobject obj = t.InvokeMember(null, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance, null, null, null);
None.gifstring 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的参数是要加载的文件的绝对路径,相对路径将会引发异常。
至此,本系列文章全部完成。因本人水平有限,有不对的地方,欢迎指正。

COM组件编程—理论知识

1、 COM组件是一个C++类,他从一系列接口派生而来,并实现了所有的接口。这些接口都是纯虚类。 2、COM组件有三个最基本的接口类,分别是IUnknown、IClassFactory、IDispa...
  • u012905728
  • u012905728
  • 2015年02月11日 09:47
  • 1653

COM组件开发(一)—— 对象与接口

一.前言        在COM规范中,最基本的两个要素就是对象与接口,因为COM就是由这两者来共同实现的。COM对象在组件中是被封装起来的,客户代码只能通过接口来访问COM对象并享受其,由于客户与C...
  • q5806622
  • q5806622
  • 2015年01月19日 23:08
  • 3495

VS2010 简单ATL COM开发(下)

前面一章介绍了怎么创建ATL COM组件及注册,下面简单介绍如何调用COM组件。 1、在MFC中调用有一种很方便的方法,就是通过ClassWizard利用类型库生成包装类,不过有个前提就是com...
  • wangwenjing90
  • wangwenjing90
  • 2013年04月08日 15:11
  • 12929

C# COM 编程指南--pdf格式

  • 2009年09月29日 18:41
  • 2.01MB
  • 下载

Linux图形界面COM口调试工具-cutecom源码

  • 2010年04月02日 09:49
  • 23KB
  • 下载

JavaScript高级培训-自定义对象(转自:http://www.ccvita.com/94.html)

一,概述 在Java语言中,我们可以定义自己的类,并根据这些类创建对象来使用,在Javascript中,我们也可以定义自己的类,例如定义User类、Hashtable类等等。 目前在Javascr...
  • lslxdx
  • lslxdx
  • 2011年10月12日 21:48
  • 1125

使用VC6.0开发COM组件 - 傻瓜式,不讲理论,只讲实例

原文地址:http://www.cnblogs.com/lin1270/archive/2013/04/02/2997042.html 1.创建一个ATL COM AppWizard...
  • qq799238350
  • qq799238350
  • 2016年10月08日 16:28
  • 268

使用VC6.0开发COM组件 - 傻瓜式,不讲理论,只讲实例

1.创建一个ATL COM AppWizard工程,如图: 2.  选择 Dynamic link Library (DLL),其它两个请百度,或参照其它文档。如下图: 3. 添加一个自己的COM...
  • Chinamming
  • Chinamming
  • 2013年12月06日 10:01
  • 584

如何获得COM的Interop交互库C#源代码

如何获得COM的Interop交互库的源代码   How can I generate C# source code for a COM Interoplibrary instead of an a...
  • wlanye
  • wlanye
  • 2015年01月09日 13:32
  • 581

C#操作Word导致 “Microsoft.Office.Interop.Word.ApplicationClass”的 COM 组件错误的解决方法

C#操作Word导致“Microsoft.Office.Interop.Word.ApplicationClass”的 COM 组件错误的解决方法 首先,要知道在C#中我们是通过调用COM组件来操作W...
  • zrf2112
  • zrf2112
  • 2016年06月03日 21:20
  • 2128
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:FW:走近COM Interop--编程以实现COM–>Assembly
举报原因:
原因补充:

(最多只允许输入30个字)