Merging a WPF application into a single EXE(WPF应用程序合并成单个Exe文件)
I always dislike handing off little applications to people. Not because I can’t, but because of the steps involved to make sure it all just works. Small apps are the most problematic because I never want to take the time to create a whole installer project for just a few assemblies, and packaging up a zip file must be accompanied by “Unzip this into a folder in your programs directory and create a shortcut…” which brings us back to the whole installer business we started with.
There are a few tools already out there such as ILMerge by Microsoft Research (Which works great for most .NET-y things, but chokes on WPF applications) and a few paid tools by third party vendors that you could fork over a few hundred for to get. But, I’m a developer, which means I want to do it the Hard Way™. I did a little research and found the following blog posts on setting up and merging in DLL’s as resources into the main assembly and then extracting and loading them into memory when you run your application.
Links:
- http://richarddingwall.name/2009/05/14/wpf-how-to-combine-mutliple-assemblies-into-a-single-exe/
- http://blog.mahop.net/post/Merge-WPF-Assemblies.aspx
- http://www.digitallycreated.net/Blog/61/combining-multiple-assemblies-into-a-single-exe-for-a-wpf-application
There were a few things I didn’t like about each solution. The first one (richarddingwall.name) ends up having you directly adding the .dll’s as resources directly. I hate maintaining things manually, especially when it will run fine on my machine but break when when I move it somewhere else because I forgot to update the resources when I added a new project. The one from blog.mahop.net builds on the previous one and changes the resolve location to a custom class with its own startup method. Better, because it resolves the resources earlier. Finally, the one from Daniel Chambers (digitallycreated.net) added in the final piece that automatically including the assemblies as resources. Unfortunately, the way he looks for culture specific assemblies didn’t work and I had to remove / change it to be closer to the one on mahop.net.
Final solution I’m currently using is as follows:
To the main executable project, unload and edit the .csproj file, and below the following line:
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
Add this XML to the project file, save, and load it back up.
<Target Name="AfterResolveReferences">
<ItemGroup>
<EmbeddedResource Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.dll'">
<LogicalName>%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension)</LogicalName>
</EmbeddedResource>
</ItemGroup>
</Target>
It should look something like this when your done:

You’ll then add a new code file to the main project and add the following code to it (modified to fit how your application is named / structured, in a WPF application, a good place to put it would be App.xaml.cs):
[STAThread]
public static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;
App.Main(); // Run WPF startup code.
}
private static Assembly OnResolveAssembly(object sender, ResolveEventArgs e)
{
var thisAssembly = Assembly.GetExecutingAssembly();
// Get the Name of the AssemblyFile
var assemblyName = new AssemblyName(e.Name);
var dllName = assemblyName.Name + ".dll";
// Load from Embedded Resources - This function is not called if the Assembly is already
// in the same folder as the app.
var resources = thisAssembly.GetManifestResourceNames().Where(s => s.EndsWith(dllName));
if (resources.Any())
{
// 99% of cases will only have one matching item, but if you don't,
// you will have to change the logic to handle those cases.
var resourceName = resources.First();
using (var stream = thisAssembly.GetManifestResourceStream(resourceName))
{
if (stream == null) return null;
var block = new byte[stream.Length];
// Safely try to load the assembly.
try
{
stream.Read(block, 0, block.Length);
return Assembly.Load(block);
}
catch (IOException)
{
return null;
}
catch(BadImageFormatException)
{
return null;
}
}
}
// in the case the resource doesn't exist, return null.
return null;
}
Finally, make sure you update the target method for your main application to be the main method for the project you just added:

And, that’s it!
When you build your application you’ll still see all the assemblies in the output directory, but you should be able to take just the executable, move it somewhere else, and run it just as it is.
Merging a WPF application into a single EXE(WPF应用程序合并成单个Exe文件)的更多相关文章
- 将visual sdudio+Qt5.12 制作的程序打包成单个exe
在GitHub上下载了个qt程序,由于C++不太会,经过安装qt.修改编码等一系列操作终于可以运行了. 生成的exe在运行时依赖很多dll或者图片文件,直接拷贝到其他电脑上无法运行,可以将依赖的dll ...
- C#程序(含多个Dll)合并成一个Exe
把C#程序(含多个Dll)合并成一个Exe的超简单方法 开发程序的时候经常会引用一些第三方的DLL,然后编译生成的exe文件就不能脱离这些DLL独立运行了. 但是,很多时候我们本想开发一款只需要一 ...
- 将WinForm程序(含多个非托管Dll)合并成一个exe的方法
原文:将WinForm程序(含多个非托管Dll)合并成一个exe的方法 开发程序的时候经常会引用一些第三方的DLL,然后编译生成的exe文件就不能脱离这些DLL独立运行了. ILMerge能把托管dl ...
- 利用Costura.Fody制作绿色单文件程序(C#程序(含多个Dll)合并成一个Exe)
原文:利用Costura.Fody制作绿色单文件程序(C#程序(含多个Dll)合并成一个Exe) 开发程序的时候经常会引用一些第三方的DLL,然后编译生成的exe文件就不能脱离这些DLL独立运行了.这 ...
- 如何将你写的脚本程序打包成一个exe可执行程序
编写的程序打包成一个exe文件,随时可以双击执行,想想是不是很酷.接下来我们一起看一下如何将自己编写的程序打包为一个exe的可执行程序. 将程序打包成exe的好处 除了满足自己的成就感以外, ...
- 用Pyinstaller把Python3.7程序打包成可执行文件exe
1.通过pip3 install pyinstaller 安装成功 2.然后执行命令,首先:需要切换到程序所在的目录 执行命令 pyinstaller -F -w <文件名.py>,-F代 ...
- 把C#程序(含多个Dll)合并成一个Exe的超简单方法
开发程序的时候经常会引用一些第三方的DLL,然后编译生成的exe文件就不能脱离这些DLL独立运行了. 但是,很多时候我们本想开发一款只需要一个exe就能完美运行的小工具.那该怎么办呢? 下文介绍一种超 ...
- 使用rar把程序打包成一个exe
根目录--全部文件--右键添加到压缩文件 常规--创建自解压压缩文件 高级--自解压选项 解压路径--Finger(自己写)--在"Program Files"中创建 设置--解压 ...
- 调用cmd.exe执行pdf的合并(pdftk.exe)
今天调查一个pdf文件的抽取,合并功能,用到下面这个工具(pdftk): https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/ 在cmd.exe里执 ...
随机推荐
- Android 点亮屏幕
前言 欢迎大家我分享和推荐好用的代码段~~ 声明 欢迎转载,但请保留文章原始出处: CSDN:http://www.csdn.net ...
- 基于visual Studio2013解决面试题之1403插入排序
题目
- Silverlight技术调查(2)——跨域访问
原文 Silverlight技术调查(2)——跨域访问 此调查web容器采用的是Tomcat,若允许所有域访问,只需在webapps下的根应用ROOT中,加入配置文件:clientaccesspoli ...
- 基于TCP/IP协议的C++网络编程(API函数版)
源代码:http://download.csdn.net/detail/nuptboyzhb/4169959 基于TCP/IP协议的网络编程 定义变量——获得WINSOCK版本——加载WINSOCK库 ...
- struts2 <s:iterator/>怎样取得循环的索引
<s:iterator value="list" id="user" status="L"> <s:property va ...
- 高性能C++网络库libtnet实现:Connection
Connection libtnet只支持IPv4 TCP Connection,之所以这么做都是为了使得实现尽可能的简单.我们主要在Connection类中封装了对tcp连接的操作. Connect ...
- UpdateWindow API函数的作用很明显
待续 摘自<Delphi深度历险>
- 【ASP.NET Web API教程】1 ASP.NET Web API入门
原文 [ASP.NET Web API教程]1 ASP.NET Web API入门 Getting Started with ASP.NET Web API第1章 ASP.NET Web API入门 ...
- HK共享吧解压密码
HK共享吧解压密码 编号一:kIioOK9* 编号二:www.mfhk8.com_!h0jn3G+t@ 编号三:www.mfhk8.com_rz~NWjU)cZ 编号四:www.mfhk8.com_$ ...
- c语言指针具体解释
指针是C语言中广泛使用的一种数据类型. 运用指针编程是C语言最基本的风格之中的一个.利用指针变量能够表示各种数据结构: 能非常方便地使用数组和字符串: 并能象汇编语言一样处理内存地址,从而编出精练而高 ...