如何生成强名称的程序集

如何生成强名称的程序集,第1张

通过嵌入公钥并使用私钥签名,可以生成强名称(strong name)的程序集。

强名称程序集由4部分进行标识:名称、版本、区域性和公钥。

与之相对的,我们可以把没有嵌入公钥和使用私钥签名的程序集称之为弱名称(weak name)程序集(这个术语是Jffery Richter创造的)。

一、准备工作

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

Unity开发者可以在一个文件夹中自定义程序集。定义明晰的依赖关系,可以确保脚本更改后,只会重新生成必需的程序集,减少编译时间。

在一个项目中会存在多个程序集,例如SDK集合、热更集合、插件集合、主集合等,如果未自定义程序集,修改其中一个集合的脚本后Unity再次编译,这时Unity会将所有集合都编译一遍,时间的浪费是我们所不希望的。当我们为每一个集合都定义程序集后,修改脚本只会编译对应的程序集。

通过在Unity中点击:Assets >Create >Assembly Definition菜单创建。该文件的扩展名是.asmdef。

需要注意的是程序集名与文件名无关,真正有关联关系的是Inspector面板中Name对应的名称

该程序集我们还可以在解决方案中观察到

程序集依赖关系成树状,一旦确立依赖关系,低层级的程序集则无法调用高层级程序集里的类和方法。

这里我设立了三个程序集:Unity.Hotfix、Unity.Model、Unity.ThirdParty;

他们之间的依赖关系如下

这样在Hotfix程序集里可以调用Model与ThirdParty程序集中的脚本,但是Model无法调用Hotfix程序集中的脚本

程序集会管理它当前所在文件夹和子文件夹中的脚本。

如果一个脚本当前文件夹中定义了一个程序集,它的父文件夹中也定义了一个程序集,该脚本会被归纳到它当前文件夹的程序集中

在平台中可以设置程序集编译平台

这样可以使某些程序集避免在一些特殊平台下被编译,常见的例如我们希望我们的Edtor程序集或热更资源程序集只在编辑器下被编译,那么我们就可以在平台设置中只勾选Editor


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

原文地址: http://outofmemory.cn/yw/11031880.html

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

发表评论

登录后才能评论

评论列表(0条)

保存