.Net平台dll合入exe

在开发Winform桌面程序中,经常要引用一些*.dll文件。这些dll文件被称为动态链接库(DLL,Dynamic Link Library)。在Windows系统中,许多应用程序并不是一个单独的可执行文件(.exe),它们被分割成一些相对独立的动态链接库,即dll文件,放置于系统中。当我们执行某一个程序时,相应的dll文件就会载入被调用。
优点:dll中存放的是程序所需的类或函数的实现。当程序需要调用函数时只需先载入dll,然后获得函数的地址,最后进行调用。使用dll文件的优点是,程序不需要在运行开始时就加载所有代码,只有在需要某个函数的时候才从dll中取出。
一般在Visual Studio中创建解决方案后,会构建如下图所示的项目结构,其中BLL、DAL、Model、Utility为类库,另一个项目一般放置Main窗体,是程序的入口。程序编译之后,在bin/Debug文件下就可以看到生成了BLL.dll,DAL.dll,Model.dll,Utility.dll,启动项就会被编译成*.exe文件。
这里写图片描述

有时,希望程序编译之后只有一个.exe文件,直接可以拷到别处运行。那么程序依赖的.dll文件无疑就需要合入.exe中,否则程序将无法运行。.NET平台将.dll文件合入*.exe中主要有三种方式:
1.最不高级的方式是,把BLL,DAL,Model,Utility以及启动项合并成一个项目重新编译生成。这种方式显然很low,否则没有必要分三层或四层架构了。而且第三方.dll文件仍然无法合入.exe中。

2.微软提供的ILMerge工具
这个工具可以将多个.dll文件合为一个.dll,或者将多个.dll以及.exe合成一个*.exe。听起来很好,可是有个缺点,它是命令行形式的。网上也有图形界面的,试了很久,最后也没成功。最后失败的原因好像是有些.dll文件的.net framework版本不一致,导致最后合成失败。因为要合并的.dll文件过多,且有些.dll文件懒得去换成统一版本的,就放弃了。

3.将.dll文件以资源的形式,引入项目

操作方法为,首先,打开Resources.resx文件,如下图
这里写图片描述

选择“添加资源”->“添加现有文件”,将.dll文件添加进资源文件。
这里写图片描述

然后,打开启动项下的Resource文件夹,找到刚添加进的.dll文件,将其属性“生成操作”改为“嵌入的资源”,如下图
这里写图片描述
这样就可以将.dll作为资源文件打包到exe中去。
注意,除第三方.dll文件可以按照以上方式添加外,项目自身生成的BLL.dll,DAL.dll等也可以。区别是,因为程序代码可能会有更改,涉及到BLL,DAL层的代码如果更改后,需要重新编译生成BLL.dll和DAL.dll,然后再次添加进去,否则更改的代码无法应用的exe中,因为exe引用的BLL还是代码更改前的。(亲试有用的)

完成以上操作,只是把.dll文件作为资源文件打包到了exe中。运行程序会出错,程序集加载失败,触发 AppDomain.CurrentDomain.AssemblyResolve 事件。
这是为什么呢?这是因为,程序运行时,在硬盘中找不到程序集,因为程序集已经被打包到exe中去了,硬盘中不存在。解决方法是,在触发的这个事件中手动加载。

以下代码来自于
http://www.cnblogs.com/blqw/p/LoadResourceDll.html

class Program
{
    static Program()
    {
        //这个绑定事件必须要在引用到TestLibrary1这个程序集的方法之前,注意是方法之前,不是语句之间,就算语句是在方法最后一行,在进入方法的时候就会加载程序集,如果这个时候没有绑定事件,则直接抛出异常,或者程序终止了
        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    }

    static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        //获取加载失败的程序集的全名
        var assName = new AssemblyName(args.Name).FullName;
        if (args.Name == "TestLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
        {
            //读取资源
            using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ConsoleApplication5.TestLibrary1.dll"))
            {
                var bytes = new byte[stream.Length];
                stream.Read(bytes, 0, (int)stream.Length);
                return Assembly.Load(bytes);//加载资源文件中的dll,代替加载失败的程序集
            }
        }
        throw new DllNotFoundException(assName);
    }
    //程序进入方法之前会加载程序集,当程序集加载失败,则会进入CurrentDomain_AssemblyResolve事件
    static void Main(string[] args)
    {
        var test = new TestLibrary1.Test();
        test.Point();
        Console.ReadLine();
    }
}

以上是加载一个.dll文件的逻辑代码。加载多个.dll文件,链接的博主也给出,真是好人!

通用的资源dll加载类:
原理:主要是通过StackTrace类获取调用RegistDLL方法的对象,获取到对方的程序集,

然后,通过Assembly.GetManifestResourceNames()获取所有资源的名称

判断后缀名”.dll”(这一步可以自由发挥)。然后加载,以加载的程序集的名称为key保存到一个字典中

并绑定AppDomain.AssemblyResolve事件

在程序集加载失败时,从字典中查询同名程序集,如果有,直接从字典中加载

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;

namespace blqw
{
    /// <summary> 载入资源中的动态链接库(dll)文件
    /// </summary>
    static class LoadResourceDll
    {
        static Dictionary<string, Assembly> Dlls = new Dictionary<string, Assembly>();
        static Dictionary<string, object> Assemblies = new Dictionary<string, object>();

        static Assembly AssemblyResolve(object sender, ResolveEventArgs args)
        {
            //程序集
            Assembly ass;
            //获取加载失败的程序集的全名
            var assName = new AssemblyName(args.Name).FullName;
            //判断Dlls集合中是否有已加载的同名程序集
            if (Dlls.TryGetValue(assName, out ass) && ass != null)
            {
                Dlls[assName] = null;//如果有则置空并返回
                return ass;
            }
            else
            {
                throw new DllNotFoundException(assName);//否则抛出加载失败的异常
            }
        }

        /// <summary> 注册资源中的dll
        /// </summary>
        public static void RegistDLL()
        {
            //获取调用者的程序集
            var ass = new StackTrace(0).GetFrame(1).GetMethod().Module.Assembly;
            //判断程序集是否已经处理
            if (Assemblies.ContainsKey(ass.FullName))
            {
                return;
            }
            //程序集加入已处理集合
            Assemblies.Add(ass.FullName, null);
            //绑定程序集加载失败事件(这里我测试了,就算重复绑也是没关系的)
            AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve;
            //获取所有资源文件文件名
            var res = ass.GetManifestResourceNames();
            foreach (var r in res)
            {
                //如果是dll,则加载
                if (r.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
                {
                    try
                    {
                        var s = ass.GetManifestResourceStream(r);
                        var bts = new byte[s.Length];
                        s.Read(bts, 0, (int)s.Length);
                        var da = Assembly.Load(bts);
                        //判断是否已经加载
                        if (Dlls.ContainsKey(da.FullName))
                        {
                            continue;
                        }
                        Dlls[da.FullName] = da;
                    }
                    catch
                    {
                        //加载失败就算了...
                    }
                }
            }
        }
    }
}

LoadResourceDll

用法是,在Program.cs中增加如下代码

static Program()
        {            
            //在程序集中的方法被调用前,执行绑定程序集,否则会出错,程序终止。
            LoadResourceDll.RegistDLL();
        }

代码部分是从别处查询来的,整理出来,以防自己忘记。
再次贴出代码来源:
http://www.cnblogs.com/blqw/p/LoadResourceDll.html

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 将.NET DLLEXE合并是一种将DLL(动态链接库)和EXE(可执行文件)文件进行合并的技术。这种合并可以实现.NET应用程序的简化和优化。 通过合并DLLEXE文件,可以将应用程序的所有依赖项包含在一个独的可执行文件中,而不需要额外的DLL文件。这种合并有以下几个优点: 1. 简化部署:合并后的文件可以更容易地进行部署和分发,因为只需要一个文件即可。 2. 提高性能:合并后的文件可以减少程序的启动时间和加载时间,因为不再需要在运行时从外部DLL加载代码和资源。 3. 防止依赖关系冲突:合并后的文件可以避免由于不同版本的DLL之间存在冲突而导致的问题。所有必需的代码和资源都包含在一个文件中,可以确保它们之间的兼容性。 4. 保护源代码:合并后的文件可以更好地保护.NET应用程序的源代码,因为它们将不再以可访问的DLL形式存在。 要实现DLLEXE的合并,可以使用一些工具或技术,如ILMerge、Costura.Fody等。这些工具可以将DLLEXE文件合并成一个独的可执行文件。可以在构建过程中使用这些工具,或者手动执行它们来完成合并操作。 总而言之,将.NET DLLEXE合并可以简化部署,提高性能,避免依赖关系冲突,并保护源代码。这是一个优化和改进.NET应用程序的有效方法。 ### 回答2: 将.NET DLLEXE合并是指将DLL文件与EXE文件合并为一个独的可执行文件。这种操作主要有两个目的:减少文件数量和简化部署过程。 首先,通过将DLLEXE合并为一个文件,可以减少文件数量。原本,一个应用程序可能需要依赖多个DLL文件才能正常运行,这样就导致了文件过多的问题,给文件的管理和部署带来了一定的困扰。而将DLLEXE合并为一个文件后,就避免了这个问题,只需要一个文件就能完整地运行应用程序,简化了文件的管理和维护。 其次,将DLLEXE合并为一个文件还能简化部署过程。在原本的情况下,需要将DLL文件与EXE文件分开部署,并且还需要将DLL文件正确地放置在应用程序的搜索路径中,否则应用程序无法找到所需的DLL文件,导致运行失败。而合并后的文件就不存在这个问题,只需要将一个文件部署到目标系统中即可,无需额外的配置和指定搜索路径。 但需要注意的是,合并DLLEXE也有一些潜在的问题。首先,合并后的文件体积会比原来的文件大,这会增加程序的加载时间和磁盘占用空间。其次,如果需要更新DLL文件,合并后的文件就需要重新打包和部署,而不像原来的方式只需要替换对应的DLL文件即可。 综上所述,将.NET DLLEXE合并为一个文件可以减少文件数量和简化部署过程,但也带来了一些潜在的问题需要考虑。根据具体情况,可以选择是否进行合并。 ### 回答3: 将.NETdll(动态链接库)和exe(可执行文件)合并是通过使用ILMerge工具来实现的。ILMerge是一个独立的命令行工具,用于将多个.NET程序集合并为个程序集。 使用ILMerge合并dllexe可以有以下几个好处: 1. 减少部署的文件数量:将多个dll合并为一个dll,或者将多个dllexe合并为一个exe,可以减少需要部署的文件数量,简化部署过程。 2. 提高应用程序的运行效率:合并dllexe可以减少程序的加载时间和启动时间,提高应用程序的运行效率。 3. 避免版本冲突:将不同版本的dll合并为一个程序集,可以避免版本冲突问题,确保程序能够正确加载所需的函数和方法。 4. 保护源代码:合并dllexe可以将源代码打包到一个文件中,使得源代码不容易被反编译或者修改。 使用ILMerge合并dllexe的步骤如下: 1. 下载并安装ILMerge工具。 2. 打开命令行工具,进入到ILMerge的安装目录。 3. 使用以下命令进行合并操作: `ILMerge.exe /out:MergedAssembly.exe PrimaryAssembly.exe SecondaryAssembly.dll` 其中,MergedAssembly.exe是合并后生成的新的exe文件名,PrimaryAssembly.exe是主程序集的文件名,SecondaryAssembly.dll是次要程序集的文件名。 4. 执行命令后,ILMerge将会合并指定的程序集,生成一个新的exe文件。 5. 使用合并后的新的exe文件进行部署和运行。 需要注意的是,合并dllexe可能会导致一些依赖关系和引用路径的问题,因此在进行合并操作前,需要仔细检查和解决这些问题,确保程序能够正确运行。此外,合并dllexe可能会使得调试和更新程序变得更加困难,因此在合并前需要权衡利弊,选择合适的方案。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值