以前写了一篇博客《C#嵌入dll到资源释放的问题》讲到了DLL文件嵌入到资源后,程序运行时自动释放并实现代码调用的问题。很多读者都问到了同一个问题:文章针对的是非托管的Win 32 DLL,那么托管的DLL怎么嵌入并释放呢?这篇文章就来聊一下这个话题。
由于托管应用程序在启动时就需要加载全部使用到的托管DLL,所以采用嵌入Win32 DLL到资源然后再释放的方式是不可行的。有一种思路是在生成EXE后,把需要调用的DLL与EXE合并成一个新的EXE,比如IMerge等工具就可以实现这一过程(其实我也一直这么干)。但是今天我要讲的是一种类似嵌入非托管DLL的方式,利用反射直接通过代码来实现动态调用。
1 引用DLL
需要调用的托管math.dll主要代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace math
{
public class math
{
public static int add(int a, int b)
{
return a + b;
}
}
}
生成math.dll后,在需要调用的C#程序中添加对math.dll的引用:
2 嵌入DLL
具体嵌入步骤:
将引用的math修改属性:复制本地->False。
将math.dll文件加入到调用程序功能的资源中,注意修改属性:生成操作->嵌入的资源。
3 反射DLL
直接上代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using System.IO;
namespace Demo
{
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//反射
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
Application.Run(new Form1());
}
static Assembly CurrentDomain_AssemblyResolve(object sender, EventArgs e)
{
//从资源中加载DLL到内存
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Demo.math.dll"))
{
byte[] byData = new byte[stream.Length];
stream.Read(byData, 0, byData.Length);
return Assembly.Load(byData);
}
}
}
}
我们现在就可以删除math.dll文件,直接运行生成的EXE程序,过程就这么简单。