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:

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文件)的更多相关文章

  1. 将visual sdudio+Qt5.12 制作的程序打包成单个exe

    在GitHub上下载了个qt程序,由于C++不太会,经过安装qt.修改编码等一系列操作终于可以运行了. 生成的exe在运行时依赖很多dll或者图片文件,直接拷贝到其他电脑上无法运行,可以将依赖的dll ...

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

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

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

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

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

    原文:利用Costura.Fody制作绿色单文件程序(C#程序(含多个Dll)合并成一个Exe) 开发程序的时候经常会引用一些第三方的DLL,然后编译生成的exe文件就不能脱离这些DLL独立运行了.这 ...

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

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

  6. 用Pyinstaller把Python3.7程序打包成可执行文件exe

    1.通过pip3 install pyinstaller 安装成功 2.然后执行命令,首先:需要切换到程序所在的目录 执行命令 pyinstaller -F -w <文件名.py>,-F代 ...

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

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

  8. 使用rar把程序打包成一个exe

    根目录--全部文件--右键添加到压缩文件 常规--创建自解压压缩文件 高级--自解压选项 解压路径--Finger(自己写)--在"Program Files"中创建 设置--解压 ...

  9. 调用cmd.exe执行pdf的合并(pdftk.exe)

    今天调查一个pdf文件的抽取,合并功能,用到下面这个工具(pdftk): https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/ 在cmd.exe里执 ...

随机推荐

  1. Linux内核源代码解析之——sock's buffer参数

    本文原创为freas_1990,转载请标明出处:http://blog.csdn.net/freas_1990/article/details/11539695 关于socket与sock的关系再简单 ...

  2. fileziller 恢复 站点管理器 内的ftp帐号方法

    由于系统坏了重装了系统,以前的fileziller中配置的服务器链接信息列表很多,新装fileziller后即使复制以前的安装目录过来,站点管理器内还是空荡荡的. 这些服务器链接的配置信息非常重要,如 ...

  3. 使用MVC模式开发一简单的销售额查询系统

    与上一篇比较,只改变了index.jsp文件中form的提交路径 <form action="ShowServlet" method="post"> ...

  4. EasyUI - 后台管理系统 - 登陆模块

    效果: --- --- Html代码: <div id="login"> <p>账户:<input type="text" id= ...

  5. Win2003 Server磁盘配额揭密之启用篇

    Win2003 Server磁盘配额揭密之启用篇 [ 作者:茶乡浪子    转贴自:it168.com    点击数:4973    更新时间:2005-1-17  ]   本文要向大家介绍如何利用W ...

  6. 配置VS2008下的Qt开发环境有感

    写一篇小小的日志为了在VS2008中安装Qt的插件,花了我很多的时间.1.vs2008在win7中破解问题我的VS2008已经安装好了,不知道为何,当初没有破解,现在只剩下15天限制了.于是为了破解, ...

  7. Sql Server 函数的操作实例!(返回一条Select语句查询后的临时表)

    Sql Server 函数的操作实例!(返回一条Select语句查询后的临时表) SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE FUN ...

  8. Design Pattern Chain of Reponsibility 责任链模式

    本程序实现一个责任链模式查询人名的资料. 開始都是查询第一个人,问其是否有某人的资料,假设有就返回结果,假设没有第一个人就会询问第二个人,第二个人的行为和第一个人的行为一致的,然后一致传递下去,直到找 ...

  9. Cocos2dx引擎10-事件派发

    本文介绍Cocos2dx事件(以下简称Event)处理机制中的事件分发模块,在Event发生后,进过一系列处理,最后将会分发Event: 1.dispatchEvent& dispatchTo ...

  10. CodeForce 439C Devu and Partitioning of the Array(模拟)

     Devu and Partitioning of the Array time limit per test 1 second memory limit per test 256 megabytes ...