(转载)C#将托管DLL嵌入exe文件

http://blog.csdn.net/call_me_lzm/article/details/51501620

一、将dll文件加入工程

1.找到dll文件

可以在项目的“引用”下找到dll,并且根据属性中的“路径”找到文件所在目录;也可以使用bin目录下自动生成(其实就是复制)的dll文件
这里写图片描述
这里需要注意,“引用”下的dll,需要设置“复制本地”为False,这样在bin目录下生成exe的时候就不会顺便复制dll了(感觉这步可要可不要)。

2.加入工程

可以对着项目(我的即“ShadowSuHelper”)右键->添加->现有项;或者更简单的,复制1中找到的dll,直接在工程中粘贴
这里写图片描述
加入dll后,工程结构如上图,引用中的还需要保留(否则代码编译不通过);此外.dll文件也是必须的(运行时需要调用)。最后,别忘了对刚加入的两个dll属性中“生成操作”改为“嵌入的资源”,这样生成的exe就会嵌入这两个dll,体积显著增大,哈哈。

二、添加AssemblyResolve处理函数

添加了AssemblyResolve的处理函数后,当调用dll找不到时,就会回调该函数,我们只需要在这个函数中,将嵌入exe的dll获取并解析返回即可。这个事件必须在调用dll之前添加,否则就没用了,这里我们选择在Program.cs的Main()方法中设置。
首先引入命名空间
using System.Reflection;
然后在Main方法开头加入
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;

其中的CurrentDomain_AssemblyResolve就是我们的回调函数了,完整代码如下:

static void Main()
{
    AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form1());
}
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    string resourceName = "ShadowSuHelper." + new AssemblyName(args.Name).Name + ".dll";
    using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
    {
        byte[] assemblyData = new byte[stream.Length];
        stream.Read(assemblyData, 0, assemblyData.Length);
        return Assembly.Load(assemblyData);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

可以在CurrentDomain_AssemblyResolve中设置断点查看,会发现当程序中首次调用到HtmlAgilityPack.dll或者Newtonsoft.Json.dll的方法时会回调该函数,并且不会再报找不到dll的错误了。

三、其他

1.经过测试,一旦dll被加载到内存中,就会一直存在。所以只有首次找不到dll时会去加载,其他时候就不用了,所以感觉《Load DLL From Embedded Resource 》这篇文章中的提前加载(如EmbeddedAssembly.Load(resource1, "System.Windows.Forms.Ribbon35.dll");)和缓存方式(static Dictionary<string, Assembly> dic = null;)应该没什么必要。
2.要嵌入非托管dll,可以参考底部提到的《Load DLL From Embedded Resource 》这篇文章,这里给出从中摘抄的一段话:

Unmanaged DLL cannot be loaded directly from stream/byte[] as Managed DLL do.

1.First load the DLL from Embedded Resource into byte[].
2.Write byte[] into a physical file and stored it at temp folder. Use
3.Assembly.LoadFile() to load the file into memory.

参考文章

[C#.NET] 合併 .net 組件 / 將 .dll 嵌入 .exe
Load DLL From Embedded Resource
.Net平台实现嵌入DLL C#描述

Article By :

One thought on “(转载)C#将托管DLL嵌入exe文件

回复 sverigapotek 取消回复

您的邮箱地址不会被公开。 必填项已用 * 标注