C#:将引用的外部DLL文件和当前项目编译打包成一个EXE文件

C#工程项目经常需要引用外部DLL文件,在生成解决方案或者发布项目时,这些外部的DLL文件会被复制进Bin目录,生成的应用程序是一个多文件组成的结构。有时为了方便,我们想把引用的外部DLL文件编译进当前项目中,使得这个引用外部DLL文件的项目最后只生成一个可执行文件。过程如下:

准备工作:新建一个类库(作为被引用的外部DLL),编译成DLL文件,本例中的DLL文件名为TestExternalDll.dll。如果引用的DLL文件是NuGet的第三方插件,请跳过此步骤。

namespace TestExternalDll {
    public class ExternalDll { //这里的修饰符不能是internal,否则引用它的其它项目将不能访问
        public string GetString() {
            return "External Dll String";
        }
    }
}

1.新建一个WinForm工程,将引入的外部DLL文件复制到该工程文件夹中(位置随便,我把它放到工程根目录下)。点选图中箭头指示处——“显示所有文件”,让之前复制的文件显示在工程项目文件夹中。

右键该文件,在弹出的菜单中选择“包括在项目中”。再右键该文件,在弹出菜单中选择“属性”,如图所示设置文件属性。

 

 2.在解决方案管理器中右键点击“引用”,选择“添加引用”,在弹出窗口中选择“浏览”,在文件对话框中选定引用的DLL文件。

 3.新建一个类文件LoadDll,以便在工程文件启动时加载引入的DLL文件,代码如下:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;

namespace TestMain {
    internal class LoadDll {
         //已加载的DLL
         private static readonly Dictionary<string, Assembly> LoadedDlls = new Dictionary<string, Assembly>();
         //已处理的程序集
         private static readonly Dictionary<string, object> Assemblies = new Dictionary<string, object>();

        /// <summary> 在对程序集解释失败时触发 </summary>
        private static Assembly AssemblyResolve(object sender, ResolveEventArgs args) {
            //获取加载失败的程序集的名称
            string assName = new AssemblyName(args.Name).FullName;
            //判断已加载的Dll集合中是否有已加载的同名程序集
            if (LoadedDlls.TryGetValue(assName, out Assembly ass) && ass != null) {
                LoadedDlls[assName] = null;
                return ass;
            } else {
                //抛出加载失败的异常
                throw new DllNotFoundException(assName);
            }
        }
        
        /// <summary> 注册资源中的dll </summary>
        public static void RegistDLL() {
            //获取当前项目的程序集
            Assembly ass = new StackTrace(0).GetFrame(1).GetMethod().Module.Assembly;
            //如果已处理程序集列表中包含此程序集则返回,否则将此程序集加入到已处理程序集列表中(Assemblies)
            if (Assemblies.ContainsKey(ass.FullName))
                return;
            else
                Assemblies.Add(ass.FullName, null);
            //绑定程序集加载失败事件
            AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve;
            //获取所有资源文件文件名
            string[] resources = ass.GetManifestResourceNames();
            //DLL文件名的正则表达式*.dll,如果是其它扩展名,可以修改该正则表达式
            var regex = new Regex("^.*\\.dll$", RegexOptions.IgnoreCase);
            foreach (string res in resources) {
                //如果是dll则加载
                if (regex.IsMatch(res)) {
                    Stream s = ass.GetManifestResourceStream(res);
                    byte[] bytes = new byte[s.Length];
                    s.Read(bytes, 0, (int)s.Length);
                    Assembly loadedAss = Assembly.Load(bytes);
                    //判断是否已经加载
                    if (LoadedDlls.ContainsKey(loadedAss.FullName))
                        continue;
                    else
                        LoadedDlls[loadedAss.FullName] = loadedAss;
                }
            }
        }
     }
}

4.修改当前项目的Program.cs文件,将LoadDll类的RegistDLL()方法加入到启动Main函数中。

using System;
using System.Windows.Forms;

namespace TestMain {
    internal static class Program {
        /// <summary>应用程序的主入口点。 </summary>
        [STAThread]
        static void Main() {

            LoadDll.RegistDLL();    //将引用的Dll文件加载到当前应用程序域中

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

5.在项目中随便调用引入的DLL文件中的对象和方法,生成解决方案,测试成功。

namespace TestMain {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e) {
            ExternalDll test=new TestExternalDll.ExternalDll();
            this.Text = test.GetString();
        }
    }
}

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值