
下面的例子中,我们来调用一下系统自带的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的参数是要加载的文件的绝对路径,相对路径将会引发异常。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)