NET中怎么调用COM组件?

NET中怎么调用COM组件?,第1张

.NET在设计之初就考虑到了如何方便的利用现有的各种技术资源,这也是微软的一贯作风,.NET的强大之处也可见一斑。.NET提供了大量的类库来方便的实现同COM的相互 *** 作,其中很重要的一个名称空间就是:System.Runtime.InteropServices。通过这个名称空间的名字我们也可以从字面上看出,“互 *** 作服务”。System.Runtime.InteropServices这个名称空间提供了一系列的类来对COM对象进行 *** 作。

下面的例子中,我们来调用一下系统自带的Win32函数MessageBoxA,这个函数位于系统的激消COM组件user32.dll当中,我们明握知调用的代码如下:

using System

using System.Runtime.InteropServices

class Test{[DllImport( "user32.dll "皮孝)]

public static extern int MessageBoxA(inthWnd,string strMsg,string strCaption,intnType)

public static void Main(){int myMsg

myMsg=MessageBoxA(0, "Hello! ", "test ",0)}}切换到MS-DOS命令行下面,运行:

C:\ csc Test.cs

编译完毕我们的C#应用程序之后,直接运行就可以看到对话框了!

需要注意的是,在调用COM组件之前,我们需要在.NET程序中引用名称空间:System.Runtime.InteropServices。因为我们需要使用这个名称空间所提供的一个方法:DllImport。

你需要做的是:

1.做一个COM+的.NET封装(可以直接在VS.NET中引用COM组件,也可以使用Regsvcs.exe命令自己完成)

2.在项目中引用上面产生的dll最好可以帖出你的代码,这样大家判断的才准确!

一、准备工作

具体说来,编程实现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的参数是要加载的文件的绝对路径,相对路径将会引发异常。


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/12370017.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-23
下一篇2023-05-23

发表评论

登录后才能评论

评论列表(0条)

    保存