如何用C#将COM组件转换成程序集
1个回答
2017-02-01 · 知道合伙人数码行家
huanglenzhi
知道合伙人数码行家
向TA提问 私信TA
知道合伙人数码行家
采纳数:117538
获赞数:517183
长期从事计算机组装,维护,网络组建及管理。对计算机硬件、操作系统安装、典型网络设备具有详细认知。
向TA提问 私信TA
关注
展开全部
一、准备工作
具体说来,编程实现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的参数是要加载的文件的绝对路径,相对路径将会引发异常。
具体说来,编程实现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的参数是要加载的文件的绝对路径,相对路径将会引发异常。
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询