原文:利用Costura.Fody制作绿色单文件程序(C#程序(含多个Dll)合并成一个Exe)

开发程序的时候经常会引用一些第三方的DLL,然后编译生成的exe文件就不能脱离这些DLL独立运行了。这样交给用户很不方便,希望的效果是直接交付一个exe文件。

这时候就需要借助一款名为Fody.Costura的插件。Fody.Costura是一个Fody框架下的插件,可通过Nuget安装到VS工程中。安装之后,就可以将项目所依赖的DLL(甚至PDB)文件全部打包到EXE文件里。

使用 Costura.Fody ,这个强大之处是可以在build阶段直接将依赖的DLL合并在目标EXE中,支持非托管DLL进行mixed mode 打包。不足之处是只能将DLL合并到EXE中,不支持DLL和DLL的合并。

github地址:https://github.com/Fody/Costura

nuget地址:https://www.nuget.org/packages/Costura.Fody/

使用场景:最终发布只有一个EXE,将依赖的DLL合并到一个EXE中。

使用方法

1、在VS中,通过Nuget为目标EXE工程安装Costura.Fody。
2、重新构建项目。

构建完成后,到项目的输出目录下找到新生成的EXE文件,你同时会发现输出目录下仍然存在那些DLL。不过不用担心,这个EXE已经能够独立运行了。你可以把这些DLL全部删除后再运行EXE试试。

Fody.Costura还支持一些进阶的特性,例如:

  • 临时程序集文件:在运行EXE前自动,自动将DLL从EXE中解压到文件夹系统中,再通过常规的方式加载该DLL。
  • 合并非托管的DLL:Fody.Costura可以合并非托管的DLL,但是不会自动合。如果你的程序涉及非托管DLL,那么你需要通过修改Fody.Costura的配置文件来显示地告诉它你想合并哪些非托管的DLL。
  • 预加载DLL:Fody.Costura可以帮助你在程序启动时预先加载某些DLL,你甚至可以指定这些DLL的加载顺序。

以上这些进阶特性都需要你通过修改Fody.Costura的配置文件来实现,具体的操作步骤可以参考它的官方文档

实现原理介绍

当CLR试图加载一个程序集但加载失败时,它会引发AppDomain.AssemblyResolve事件。我们的程序可以监听这个事件,并且在这个事件的处理函数中返回这个CLR试图加载的程序集,从而使程序得以继续正常运行。

Fody.Costura在构建项目时会把EXE引用到的DLL全部嵌入到EXE文件中。当程序在运行的过程中用到其中某个DLL的时候(此时由于CLR无法找到该DLL文件,导致AppDomain.AssemblyResolve事件被触发)再从EXE文件的嵌入资源中提取所需的DLL。

下面这两个函数就是Fody.Costura实现这部分逻辑的代码。

        public static void Attach()
{
var currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += (s, e) => ResolveAssembly(e.Name);
}
public static Assembly ResolveAssembly(string assemblyName)
{
if (nullCache.ContainsKey(assemblyName))
{
return null;
} var requestedAssemblyName = new AssemblyName(assemblyName); var assembly = Common.ReadExistingAssembly(requestedAssemblyName);
if (assembly != null)
{
return assembly;
} Common.Log("Loading assembly '{0}' into the AppDomain", requestedAssemblyName); assembly = Common.ReadFromEmbeddedResources(assemblyNames, symbolNames, requestedAssemblyName);
if (assembly == null)
{
nullCache.Add(assemblyName, true); // Handles retargeted assemblies like PCL
if (requestedAssemblyName.Flags == AssemblyNameFlags.Retargetable)
{
assembly = Assembly.Load(requestedAssemblyName);
}
}
return assembly;
}

可以看到,Attach方法监听了AppDomain.AssemblyResolve事件。当CLR无法成功加载某个程序集时, AssemblyResolve事件处理函数会被执行。AssemblyResolve会尝试通过Common.ReadFromEmbeddedResources方法从已加载的程序集的嵌入资源中获取目标程序集,并返回给CLR。

Attach方法是在什么时候执行的呢?

其实是这样的,对于C#语言来说,CLR隐藏了一个大招——CLR可以在每个模块(每个程序集都含有一个或多个模块)加载之前执行一些初始化的代码。但是很遗憾,C#语言无法控制这部分代码。Fody.Costura则是在内部将IL代码直接注入到EXE程序集内部模块的初始化函数中,而这部分IL代码其实就是执行了Attach方法。这样一来,EXE程序集被加载后,Attach方法就能够立即得到调用了。

与此相同原理的将DLL添加到EXE的资源(http://blogs.msdn.com/b/microsoft_press/archive/2010/02/03/jeffrey-richter-excerpt-2-from-clr-via-c-third-edition.aspx);

利用Costura.Fody制作绿色单文件程序(C#程序(含多个Dll)合并成一个Exe)的更多相关文章

  1. NSIS:静默释放文件并运行 制作绿色单文件软件

    原文 NSIS:静默释放文件并运行 制作绿色单文件软件 现在所谓的绿色单文件软件,大多与以下代码原理相似:把软件运行需要的文件封装为一个EXE文件,双击时释放到某个目录(大多是TEMP)并运行主程序文 ...

  2. C#程序(含多个Dll)合并成一个Exe

    把C#程序(含多个Dll)合并成一个Exe的超简单方法   开发程序的时候经常会引用一些第三方的DLL,然后编译生成的exe文件就不能脱离这些DLL独立运行了. 但是,很多时候我们本想开发一款只需要一 ...

  3. 将WinForm程序(含多个非托管Dll)合并成一个exe的方法

    原文:将WinForm程序(含多个非托管Dll)合并成一个exe的方法 开发程序的时候经常会引用一些第三方的DLL,然后编译生成的exe文件就不能脱离这些DLL独立运行了. ILMerge能把托管dl ...

  4. 把C#程序(含多个Dll)合并成一个Exe的超简单方法

    开发程序的时候经常会引用一些第三方的DLL,然后编译生成的exe文件就不能脱离这些DLL独立运行了. 但是,很多时候我们本想开发一款只需要一个exe就能完美运行的小工具.那该怎么办呢? 下文介绍一种超 ...

  5. [原创] 绿色单文件封装程序GreenOne V3.0

    1.原理 将包含可执行文件的多个文件 调用Winrar,创建自解压格式压缩文件 设置高级自解压选项中的文本和图标,设置解压后运行的文件为选中的可执行文件. 这种创建单文件封装其实也就是一个Winrar ...

  6. [C#]使用Costura.Fody将源DLL合并到目标EXE

    本文为原创文章,如转载,请在网页明显位置标明原文名称.作者及网址,谢谢! 一.本文主要是使用Costura.Fody工具将源DLL合并到目标EXE,因此,需要从以下任一链接下载: ①从Github地址 ...

  7. 使用Costura.Fody将源DLL合并到目标EXE

    本文为原创文章,如转载,请在网页明显位置标明原文名称.作者及网址,谢谢! 一.本文主要是使用Costura.Fody工具将源DLL合并到目标EXE,因此,需要从以下任一链接下载: ①从Github地址 ...

  8. 如何将你写的脚本程序打包成一个exe可执行程序

    ​    编写的程序打包成一个exe文件,随时可以双击执行,想想是不是很酷.接下来我们一起看一下如何将自己编写的程序打包为一个exe的可执行程序. 将程序打包成exe的好处 除了满足自己的成就感以外, ...

  9. 多个EXCEL文件合并成一个

    Python的numpy处理起来会比较方便,有空实现一下,这里是Excel内部代码的方式: 合并方法如下: 1.需要把多个excel表都放在同一个文件夹里面,并在这个文件夹里面新建一个excel.如图 ...

随机推荐

  1. loadrunner11迭代录制注册账号

    1.创建一个新的web脚本 2.我们就以loadrunner自带的WebTours为例子 3.点击确定后进入Web Tours主页,点击sign up now进行注册 4.输入用户名:test,密码: ...

  2. (网页)angular中实现li或者某个元素点击变色的两种方法(转)

    转自脚本之家: 本篇文章主要介绍了angular中实现li或者某个元素点击变色的两种方法,非常具有实用价值,需要的朋友可以参考下 本文介绍了angular中实现li或者某个元素点击变色的两种方法,分享 ...

  3. C#中禁止跨线程直接访问控件

    C#中禁止跨线程直接访问控件,InvokeRequired是为了解决这个问题而产生的,当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它.此时它将会在内部调用ne ...

  4. [20180423]flashback tablespace与snapshot standby.txt

    [20180423]flashback tablespace与snapshot standby.txt --//缺省建立表空间是打开flashback on,如果某个表空间flashback off, ...

  5. word中从正文开始编码的方法

    假如第1页和第2页是首页和目录,你想从第3页的正文开始设置页码 1. 将光标移到第二页的最后位置,点击插入“分隔符”,选择“分节类型”的“下一页”,确定.这时光标自动移到第三页. 2. 点击插入页码, ...

  6. 转:Vue2.0+组件库总结

    UI组件 element - 饿了么出品的Vue2的web UI工具套件 Vux - 基于Vue和WeUI的组件库 mint-ui - Vue 2的移动UI元素 iview - 基于 Vuejs 的开 ...

  7. Hbase-2.0.0_03_Hbase数据模型

    1. hbase数据模型 1.1. HBase数据模型术语 Table HBase表由多行组成. Row HBase中的一行由一个行键和一个或多个列组成,列的值与这些列相关联.存储行时,按行键按字母顺 ...

  8. Java并发编程(多线程)中的相关概念

    众所周知,在Java的知识体系中,并发编程是非常重要的一环,也是面试中必问的题,一个好的Java程序员是必须对并发编程这块有所了解的. 并发必须知道的概念 在深入学习并发编程之前,我们需要了解几个基本 ...

  9. SQL查询语句,怎样查询重复数据

    SQL查询语句,怎样查询重复数据 2012-02-22 14:50神奇的马骁勇 | 浏览 0 次 有表A, 中有字段id, name, memo现在有很多id重复的数据,怎么把这些重复的都查出来?gr ...

  10. Android逆向分析(2) APK的打包与安装

    http://blog.zhaiyifan.cn/2016/02/13/android-reverse-2/ 2/18日增加对aidl和java编译的描述. 前言 上一次我们反编译了手Q,并遇到了Ap ...