.Net平台实现嵌入DLL C#描述
一、场景
- 开发小工具时需引用DLL,而部署分发时只希望提供执行文件。
- 在项目架构上隐藏某些DLL文件(文件结构层面)
二、原理
- DLL的加载是在使用时才被加载,而不是启动时(卸载是由垃圾回收器处理,无法预测回收时间)。
- AppDomain.CurrentDomain.AssemblyResolve事件可用于.Net框架加载程序集失败时手动控制重新加载程序集。
- DLL文件可作为资源内嵌进程序集。
三、实现要点
- 将DLL以“嵌入的资源”的形式加入项目。
- 引用DLL,并设置为“不复制到本地”。
- 在Main方法内利用AppDomain.CurrentDomain.AssemblyResolve事件手动控制加载DLL(也可在任意使用DLL前能够被执行到的地方订阅事件)。
- 保证在加载DLL成功前不以任何形式引用此DLL。
- 可同时实现对多个DLL及其他程序集进行加载。
四、示例代码
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 // 引入加载dll所需命名空间 7 using System.Reflection; 8 9 //using DllDemo; 10 // 错误,不要用任何方式调用dll,会导致未加载dll就依赖dll 11 12 namespace AppDemo 13 { 14 class Program 15 { 16 static void Main(string[] args) 17 { 18 // 框架加载dll失败后执行,手动加载dll 19 AppDomain.CurrentDomain.AssemblyResolve += (sender, senderArgs) => 20 { 21 // 当前程序集 22 var executingAssembly = Assembly.GetExecutingAssembly(); 23 // 当前程序集名称 24 var assemblyName = new AssemblyName(executingAssembly.FullName).Name; 25 // dll名称 26 var dllName = new AssemblyName(senderArgs.Name).Name; 27 // 待加载dll路径,指向当前程序集资源文件中dll路径。* 根据程序结构调整,使其正确指向dll 28 var dllUri = assemblyName + "." + dllName + ".dll"; 29 // 加载dll 30 using (var resourceStream = executingAssembly.GetManifestResourceStream(dllUri)) 31 { 32 var assemblyData = new Byte[resourceStream.Length]; 33 resourceStream.Read(assemblyData, 0, assemblyData.Length); 34 return Assembly.Load(assemblyData); //加载dll 35 } 36 }; 37 // app入口 38 AppDemo.Demo(); 39 //var obj = new DllDemo.Dll(); 40 //错误,不要用任何方式调用dll,会导致未加载dll就依赖dll 41 Console.Read(); 42 } 43 } 44 }
演示源码下载: https://files.cnblogs.com/kui2/DEMO-EmbeddedDllDemo.zip
五、另一个想法
将DLL等资源文件内嵌程序集,执行时将其释放到磁盘上恢复所需文件。恩,费力不讨好而且容易被安全软件盯上的办法。非常时期可能会有用吧。