
一、准备工作
具体说来,编程实现COM-->Assembly的功能,需要使用的以前几个类:
SystemRuntimeInteropServices
-TypeLibConverter提供一组服务,将托管程序集转换为 COM 类型库或进行反向转换。
-ITypeLibImporterNotifySink提供回调机制,以供类型库转换器向调用方通知转换的状态,并在转换过程本身之中涉及调用方。
SystemReflection
-StrongNameKeyPair(可选)封装对公钥或私钥对的访问,该公钥或私钥对用于为强名称程序集创建签名。
SystemReflectionEmit
-AssemblyBuilder 定义并表示动态程序集。
此外,还需要使用一个WinAPI,LoadTypeLibEx,具体定义如下:
[DllImport( "oleaut32dll", CharSet = CharSetUnicode, PreserveSig = false )]
private static extern void LoadTypeLibEx(String strTypeLibName, RegKind regKind, [MarshalAs(UnmanagedTypeInterface)] 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生成的PIADemodll展开演示。
1 载入一个COM组件
Object typeLib;
LoadTypeLibEx("PIADemodll", RegKindRegKind_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("commonsnk", FileModeOpen);
try
{
StrongNameKeyPair pair = new StrongNameKeyPair(stream);
TypeLibConverter converter = new TypeLibConverter();
ConversionEventHandler eventHandler = new ConversionEventHandler();
AssemblyBuilder ab = converterConvertTypeLibToAssembly(typeLib, "interopPIADemodll", TypeLibImporterFlagsPrimaryInteropAssembly, eventHandler, null, pair, null, null);
abSave("interopPIADemodll");
MessageBoxShow("Importing is ok");
Assembly asm = AssemblyLoadFile(ApplicationStartupPath + @"\interopPIADemodll");
Type t = asmGetType("interopPIADemoTestClass");
object obj = tInvokeMember(null, BindingFlagsDeclaredOnly | BindingFlagsPublic | BindingFlagsNonPublic | BindingFlagsInstance | BindingFlagsCreateInstance, null, null, null);
string ret = (string)tInvokeMember("Format", BindingFlagsDeclaredOnly | BindingFlagsPublic | BindingFlagsNonPublic |
BindingFlagsInstance | BindingFlagsInvokeMethod, null, obj, new object[]{"Go!"});
MessageBoxShow(ret);
}
catch(Exception ep)
{
if(stream != null)
{
streamClose();
}
MessageBoxShow(epMessage);
}
B 生成一般的Assembly
TypeLibConverter converter = new TypeLibConverter();
ConversionEventHandler eventHandler = new ConversionEventHandler();
AssemblyBuilder ab = converterConvertTypeLibToAssembly(typeLib, "interopPIADemodll", 0,
eventHandler, null, null, null, null);
abSave("interopPIADemodll");
MessageBoxShow("Importing is ok");
Assembly asm = AssemblyLoadFile(ApplicationStartupPath + @"\interopPIADemodll");
Type t = asmGetType("interopPIADemoTestClass");
object obj = tInvokeMember(null, BindingFlagsDeclaredOnly | BindingFlagsPublic | BindingFlagsNonPublic | BindingFlagsInstance | BindingFlagsCreateInstance, null, null, null);
string ret = (string)tInvokeMember("Format", BindingFlagsDeclaredOnly | BindingFlagsPublic | BindingFlagsNonPublic |
BindingFlagsInstance | BindingFlagsInvokeMethod, null, obj, new object[]{"Go!"});
MessageBoxShow(ret);
需要说明几点:
1 上述示例中使用的PIADemodll和Commonsnk都需要被copy至测试程序的bin目录中,否则,就需要指定可达到的文件路径。
2 AssemblyLoadFile的参数是要加载的文件的绝对路径,相对路径将会引发异常。
下一个net reflector反编译,可以生成c#源码。或者用ildasm生成中间语言代码,这个需要你精通net il。改动后就是编译了。由于是强名称程序集,你如果想改了后还能让原来程序调用还好用,这就有难度了,毕竟微软设计强名称就是为了防止恶意修改
你把项目A换一个名字吧~可能与其它命名空间有冲突~即有同名
强名称由程序集的标识——其简单文本名称、版本号和区域性信息(如果提供)——加上公钥和数字签名组成。强名称是使用相应的私钥,通过程序集文件(包含程序集清单的文件,并因而也包含构成该程序集的所有文件的名称和散列)生成的。Microsoft® Visual Studio NET® 和在 NET 框架 SDK 中提供的其他开发工具能够将强名称分配给一个程序集。强名称相同的程序集应该是相同的。
通过签发具有强名称的程序集,您可以确保名称的全局唯一性。强名称还特别满足以下要求:
强名称依赖于唯一的密钥对来确保名称的唯一性。任何人都不会生成与您生成的相同的程序集名称,因为用一个私钥生成的程序集的名称与用其他私钥生成的程序集的名称不相同。
强名称保护程序集的版本沿袭。强名称可以确保没有人能够生成您的程序集的后续版本。用户可以确信,他们所加载的程序集的版本出自创建该版本(应用程序是用该版本生成的)的同一个发行者。
强名称提供可靠的完整性检查。通过 NET 框架安全检查后,即可确信程序集的内容在生成后未被更改过。但请注意,强名称中或强名称本身并不暗含某一级别的信任,例如由数字签名和支持证书提供的信任。
在引用具有强名称的程序集时,您应该能够从中受益,例如版本控制和命名保护。如果此具有强名称的程序集以后引用了具有简单名称的程序集(后者没有这些好处),则您将失去使用具有强名称的程序集所带来的好处,并依旧会产生 DLL 冲突。因此,具有强名称的程序集只能引用其他具有强名称的程序集。
下面的方案说明了使用强名称对程序集签名及以后按照该名称引用它的过程。
使用以下方法之一创建具有强名称的程序集 A:
使用支持创建强名称的开发环境,例如 Visual Studio NET。
使用强名称工具 (Snexe) 创建加密密钥对,并使用命令行编译器或程序集链接器 (Alexe) 将该密钥对分配给程序集。NET 框架 SDK 同时提供 Snexe 和 Alexe。
开发环境或工具使用开发人员私钥对包含程序集清单的文件哈希签名。数字签名存储在包含程序集 A 的清单的可移植可执行 (PE) 文件中。
程序集 B 是程序集 A 的使用者。程序集 B 的清单的引用部分包括代表程序集 A 公钥的标记。标记是完整公钥的一部分,并且这种标记(而不是密钥本身)可用于节省空间。
公共语言运行库在程序集置于全局程序集缓存时验证强名称签名。当运行时强名称进行绑定时,公共语言运行库会将存储在程序集 B 的清单中的密钥与用于为程序集 A 生成强名称的密钥进行比较。如果 NET 框架安全检查通过并且绑定成功,则程序集 B 可保证程序集 A 的位未被篡改,而这些位实际来自程序集 A 的开发人员。
注意 此方案不处理信任问题。程序集除强名称外,还带有完整的 Microsoft® Authenticode® 签名。Authenticode 签名包括建立信任的证书。请注意,强名称不要求以这种方式为代码签名,这一点非常重要。事实上,用于生成强名称签名的密钥不必与用于生成 Authenticode 签名的密钥相同。
创建密钥对
要使用强名称为程序集签名,必须具有公钥/私钥对。这一对加密公钥和加密私钥用于在编译过程中创建强名称程序集。您可以使用强名称工具 (Snexe) 来创建密钥对。密钥对文件通常具有 snk 扩展名。
您可以使用代码访问安全策略工具 (Caspolexe) 执行此 *** 作。每一策略级别都有单独的列表。完全信任的程序集列表为相关的策略级别向其成员授予完全信任。这是令运行库免于执行循环策略解析所必需的。 将实现自定义安全对象的程序集添加到完全信任的程序集列表在将一个程序集添加到安全策略中之前,必须给它提供一个强名称并将其放置在全局程序集缓存中。有关使用程序集和全局程序集缓存的更多信息,请参见创建和使用具有强名称的程序集。在命令提示处键入以下命令: caspol [-enterprise|-machine|-user] –addfulltrust�0�2AssemblyFile在–addfulltrust 选项前面指定策略级别选项。如果省略该策略级别选项,则 Caspolexe 列出处于默认策略级别的权限集。对于计算机管理员,默认级别是计算机策略级别;对于其他人员,默认级别是用户策略级别。 以下命令将 MyCustomPermissionSetexe 添加到用户策略级别的完全信任程序集列表中。 caspol –user –addfulltrust MyCustomPermissionSetexe 如果添加的程序集依赖其他程序集(即,使用在其他程序集中实现的类型),则必须还将该程序集添加到该列表中。将一个程序集添加到完全信任的程序集列表并不保证策略系统作为一个整体授予对它的完全信任,而是该程序集只在列出它的策略级别将被授予完全信任。例如,如果将 MyCustomPermissionexe 程序集添加到用户策略级别的完全信任的程序集列表,但 MyCustomPermissionexe 只接收来自计算机策略的执行权限,则 MyCustomPermissionexe 将最终只被授予执行权限。因此需牢记的是,将一个程序集放入完全信任的程序集列表将只有助于避免为在其中列出它的策略级别创建循环策略解析。不保证实现自定义权限的程序集实际接收完全信任授予。
以上就是关于如何用C#将COM组件转换成程序集全部的内容,包括:如何用C#将COM组件转换成程序集、如何修改强名称dll文件内容、C#引用的集合不是强名是怎么回事等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)