c#如何把一个main()和若干个dll打包生成单一的exe文件?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c#如何把一个main()和若干个dll打包生成单一的exe文件?相关的知识,希望对你有一定的参考价值。

请高手指点迷津。
不懂的请不要回答,请不要误导新手。
谢谢了。

开发程序的时候经常会引用一些第三方的DLL,然后编译生成的exe文件就不能脱离这些DLL独立运行了。
这里需要用到一款名为Fody.Costura的工具。Fody.Costura是一个Fody框架下的插件,可通过Nuget安装到VS工程中。安装之后,就可以将项目所依赖的DLL(甚至PDB)文件全部打包到EXE文件里。

使用方法
在VS中,通过Nuget为目标EXE工程安装Costura.Fody。
重新构建项目。
构建完成后,到项目的输出目录下找到新生成的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。
对于C#语言来说,CLR隐藏了一个大招——CLR可以在每个模块(每个程序集都含有一个或多个模块)加载之前执行一些初始化的代码。但是很遗憾,C#语言无法控制这部分代码。Fody.Costura则是在内部将IL代码直接注入到EXE程序集内部模块的初始化函数中,而这部分IL代码其实就是执行了Attach方法。这样一来,EXE程序集被加载后,Attach方法就能够立即得到调用了。
参考技术A 首先安装.net framework 2.0或以上
安装后找到所在文件夹
比如我的是win2003 目录是C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727
看里面是不是有很多.exe程序,有一个就是要用到的,名字叫csc.exe
这个文件很重要他是c#编译器,vs也是用它来生成程序的
开始-运行-cmd
以我的目录为例
cd: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727
打开这个目录
csc.exe X:\..\*.cs /reference:X:\..\*.DLL /target:X:\..\*.exe
带引用DLL的程序就可以生成了
X就是盘符(c,d..z)也就是.cs,.dll文件的全路径,*在此可做通配符,/target就是生成的文件的存放位置,*在此处应该是新程序的名字

这个程序很强(废话,编译器可不是一般人能做出来的),你可以输入
csc /?
他会列出它的各个参数及说明

找了点资料给你看看

参考资料:http://junmail.javaeye.com/blog/196944

参考技术B 有一种办法 你能搞到DLL里的代码 然后把代码放到你的程序里
如果不能搞到代码 那就去引用吧
参考技术C 把所有的代码放到一个命名空间中,也就是把所有代码放到一个项目里面。

C#和Java的文件压缩。

我用Java写了个程序压缩文件,由于找到的包不支持生成rar格式的压缩文件,最后用程序调用WinRaR的Rar.exe完成了程序。 发现压缩一个80M的文件,需要40秒。
同事的C#的程序用了ICSharpCode.SharpZipLib.dll。 发现压缩一个80M的文件,需要20秒。
问题:Java的比C#慢没什么疑问,但奇怪的是我用WinRAR压缩一个80M的文件也是接近40秒,C#的程序怎么会比WinRAR快(注意是rar格式)?
还有ICSharpCode.SharpZipLib.dll,不是不支持rar格式吗什么时候可以了,我记得rar格式的压缩算法还没公开?

zip和rar用的不同的压缩算法,
zip的比较简单,计算复杂度低,压缩比也低。zip的deflate算法公开,经过几十年优化已被总结出很快的实现。内存最小可以只要32K
rar是私有格式,压缩比较高,内存也需要典型的4MB。
刚出来时,rar针对32位386设计的,硬件要求比zip高一个数量级。
另外在进程调用子进程,系统IO开销,和对子进程分配的较小的执行优先级。都可能导致速度慢。追问

还有ICSharpCode.SharpZipLib.dll,不是不支持rar格式吗什么时候可以了,我记得rar格式的压缩算法还没公开?

追答

SharpZipLib 并不支持rar。
支持, gzip, zlib and raw deflate, as well as BZip2

你用SharpZipLib生成rar,很可能是tar误认,或者zip冒充的rar文件。

参考技术A java只支持zip,tar等跨平台的压缩格式 。。rar是window的。

以上是关于c#如何把一个main()和若干个dll打包生成单一的exe文件?的主要内容,如果未能解决你的问题,请参考以下文章

c#如何将一个类库打包成两个dll

dll文件如何用C语言生成

C#如何用程序把文本文件打包成dll文件

如何将cs文件编译成exe和dll,先谢! C#

C#和Java的文件压缩。

C#将引用的dll嵌入到exe文件中