WPF程序将DLL嵌入到EXE的两种方法

原文:WPF程序将DLL嵌入到EXE的两种方法

WPF程序将DLL嵌入到EXE的两种方法

这一篇可以看作是《Visual Studio 版本转换工具WPF版开源了》的续,关于《Visual Studio 版本转换工具WPF版开源了》可以参看地下地址(两篇是一样的):

  1. 开源中国 http://my.oschina.net/chinesedragon/blog/308336
  2. CNBLOGS http://www.cnblogs.com/luoshupeng/p/3946635.html

** 博客园的Markdown编辑器真的不行,还是麻烦大家稳步到http://my.oschina.net/chinesedragon/blog/309223观看吧 **

引言

前几一写了一个小工具————《Visual Studio版本转换工具》,由于使用了WPF做为界面,因此这个小程序运行必须附带两个DLL:Microsoft.Expression.Interactions.dll和System.Windows.Interactivity.dll,同时由于自己也写了一个库,一个小程序需要附带3个DLL,这种体验真的很不爽,于是就着手把DLL嵌入到EXE中去。

挫折

对于C#程序,要把DLL嵌入到EXE中去,最权威和最常见的方法就是使用ILMerge这个工具,这是个命令行工具,有很多参数,可以将DLL很完美的嵌入到EXE中去,如果嫌命令行麻烦,也有人开源开发了图形界面ILMergeGUI,这两个工具的下载和帮助地址如下:

  1. ILMerge http://www.microsoft.com/en-us/download/details.aspx?id=17630
  2. ILMerge-GUI http://ilmergegui.codeplex.com/
    于是下载了这两个工具,却出现将DLL嵌入到EXE中错误的情况,在网上查了下原因,竟然是ILMerge不支持WPF程序,我勒了个去,微软,你让我说你什么好呢?
    ILMerge可以将Winform程序的DLL完美地嵌入到EXE中去(这一点我亲自测试了下,很不,点赞),但对WPF却不支持,原因是WPF的DLL中含有资源无法解决,微软,你好意思说这个工具是你开发的吗?

Winform程序将DLL嵌入到EXE中(一)——使用命令行 

下载ILMerge或者同时下载ILMerge-GUI,使用图形界面和使用命令行是同一个道理,只是图形界面简单些,所以这里以命令行说明。
我是下载ILMerge安装后,把ILMerge.exe复制到C:\Windows目录下去了,这样可以直接在命令行中使用而不用去设置环境变量,不管怎样,只要能够在命令行下使用这个工具就行。
ILMerge有很多参数,其中有几个比较重要:

  1. /target:目标,有library和Winexe两种选择,当将多个DLL整合成一个DLL时可以使用library,当要整合为EXE时,应该使用Winexe.
  2. /out:输出,最终生成文件的路径和名称.
  3. /log:输入,如果输入是EXE时可以不使用此参数直接写,而如果输入时DLL时,最好使用此参数
    还有其它一些参数,使用时可以百度或者google一下,这是我测试的一张图片:

Winform程序将DLL嵌入到EXE中(二)——使用ILMerge.MSBuild.Tasks

ILMerge也使用Nuget发布了工具,使用Nuget的好处想必大家都知道,所以推荐使用这种方法
第一步, 使用Nuget图形或Nuget命令下载ILMerge.MSBuild.Tasks

PM> Install-Package ILMerge.MSBuild.Tasks   

第二步, 把VS项目文件记事本或者其它文本编辑工具打开,我使用的是Sublime Text 3,并按照如下格式根据实际情况修改:

<!-- Code to merge the assemblies into one:setup.exe -->
<UsingTask TaskName="ILMerge.MSBuild.Tasks.ILMerge" AssemblyFile="$(SolutionDir)\packages\ILMerge.MSBuild.Tasks.1.0.0.3\tools\ILMerge.MSBuild.Tasks.dll" />
<Target Name="AfterBuild">
    <ItemGroup>
      <MergeAsm Include="$(OutputPath)$(TargetFileName)" />
      <MergeAsm Include="$(OutputPath)LIB1_To_MERGE.dll" /> <!-- 这儿改成需要做嵌入的dll名 -->
      <MergeAsm Include="$(OutputPath)LIB2_To_MERGE.dll" />
    </ItemGroup>
    <PropertyGroup>
      <MergedAssembly>$(ProjectDir)$(OutDir)MERGED_ASSEMBLY_NAME.exe</MergedAssembly><!-- 这儿改成需要做输出的exe名 -->
    </PropertyGroup>
	<Message Text="ILMerge @(MergeAsm) -&gt; $(MergedAssembly)" Importance="high" />
	<ILMerge InputAssemblies="@(MergeAsm)" OutputFile="$(MergedAssembly)" TargetKind="SameAsPrimaryAssembly" />
</Target>

这样编译后就可以了。

WPF程序将DLL嵌入到EXE中(一)——将DLL自动转换为嵌入资源

第一步,修改项目文件,将DLL自动转换为嵌入资源。
把VS项目文件记事本或者其它文本编辑工具打开,我使用的是Sublime Text 3,并将下面内容添加到文件末尾:

<Target Name="AfterResolveReferences">
    <ItemGroup>
      <EmbeddedResource Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.dll'">
        <LogicalName>%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension)</LogicalName>
      </EmbeddedResource>
    </ItemGroup>
</Target>

第二步,修改App.xaml文件,在程序启动时加载资源

public partial class App : Application
{
    private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
    {
        Assembly executingAssembly = Assembly.GetExecutingAssembly();
        var executingAssemblyName = executingAssembly.GetName();
        var resName = executingAssemblyName.Name + ".resources";

        AssemblyName assemblyName = new AssemblyName(args.Name); string path = "";
        if (resName == assemblyName.Name)
        {
            path = executingAssemblyName.Name + ".g.resources"; ;
        }
        else
        {
            path = assemblyName.Name + ".dll";
            if (assemblyName.CultureInfo.Equals(CultureInfo.InvariantCulture) == false)
            {
                path = String.Format(@"{0}\{1}", assemblyName.CultureInfo, path);
            }
        }

        using (Stream stream = executingAssembly.GetManifestResourceStream(path))
        {
            if (stream == null)
                return null;

            byte[] assemblyRawBytes = new byte[stream.Length];
            stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
            return Assembly.Load(assemblyRawBytes);
        }
    }

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;
    }
}

第三步,dll嵌入exe后,目录中的dll就没用了,配置Post buid 脚本自动删除dll:

cd $(TargetDir)
del *.dll

有些情况下,以上方法也不行,那么可以尝试 Eazfuscator.NET
Eazfuscator.NET以前免费,现在已经变成收费软件了,不过找个免费的3.3版本也可以支持VS2010和VS2012

WPF程序将DLL嵌入到EXE中(二)——使用LibZ Container

LibZ是ILMerge的另外一个选择,它同样可以把DLL嵌入到EXE中去,在我的测试中它可以完成WPF程序的DLL嵌入到EXE中去,但好像这个组件使用的人不是很多。
LibZ Container的项目主页是http://libz.codeplex.com/
LibZ同样提供了Nuget下载,使用Nuget有很多好处,所以推荐使用这种方式
使用Nuget图形或者命令下载LibZ.Bootstrap

Install-Package LibZ.Bootstrap

然后,配置Post buid 脚本:

set LIBZ=$(SolutionDir)packages\LibZ.Bootstrap.1.1.0.2\tools\libz.exe
%LIBZ% inject-dll --assembly VSConverter.WPF.exe --include *.dll --move

编译通过后就可以了。这里需要注意的是--assembly后的参数是项目生成的文件名.
LibZ还有很多用法,可以到项目文档学习。

参考资料

  1. Combining multiple assemblies into a single EXE for a WPF application
  2. DLL嵌入exe中
  3. LibZ项目

Nuget是个十分强大的工具,使用Nuget在很多时候可以使解决方法变得简单,给Nuget赞一个!
再做下广告,Visual Studio版本转换工具WPF版的代码托管地址是:http://git.oschina.net/shupengluo/VSConverter,欢迎交流。

最后,再小小地鄙视下微软,^_^

时间: 2025-01-02 21:31:06

WPF程序将DLL嵌入到EXE的两种方法的相关文章

Flash文件嵌入音频文件的两种方法

核心提示:本文介绍在flash文档中嵌入音频文件的两种方法,使其可以在Flash player中正常播放. 本文介绍在flash文档中嵌入音频文件的两种方法,使其可以在Flash player中正常播放. 1.建立 Sound 对象用 load() 方法加载外部的 MP3 来播放; 2.让 Sound 对象监听 sampleData 事件,这样可以播放由程序动态生成的声音,例如: 下面的示例播放简单的正弦波. 以下是引用片段: var mySound:Sound = new Sound(); f

实例学习PHP程序对用户身份认证实现两种方法

用户在设计和维护站点的时候,经常需要限制对某些重要文件或信息的访问.通常,我们可以采用内置于WEB服务器的基于HTTP协议的用户身份验证机制. 当访问者浏览受保护页面时,客户端浏览器会弹出对话窗口要求用户输入用户名和密码,对用户的身份进行验证,以决定用户是否有权访问页面.下面用两种方法来说明其实现原理. 一.用HTTP标头来实现 标头是服务器以HTTP协议传送HTML信息到浏览器前所送出的字串.HTTP采用一种挑战/响应模式对试图进入受密码保护区域的用户进行身份验证.具体来说,当用户首次向WEB

win7打开exe文件提示“无法打开exe可执行文件”两种解决方法

  win7打开exe文件提示"无法打开exe可执行文件"两种解决方法          1.打开"计算机"或任意文件夹,点击"组织"-"文件夹和搜索选项"; 2.在"文件夹选项"框中点击"查看"选卡,然后在下面"高级设置"下框中将"隐藏已知文件类型的扩展名"前面的 勾去掉,点击应用并确定; 3.在桌面空白处鼠标右击选择"新建-文本文档&

如何读取dll里资源文件 的几种方法

问题描述 一.当前程序集System.Xml.XmlDocumentdoc=newSystem.Xml.XmlDocument();//xml直接嵌入程序集读取的方法System.IO.Streamsm=Assembly.GetExecutingAssembly().GetManifestResourceStream("XW.Common.Address.xml");doc.Load(sm);//直接将流转成xmlbyte[]bs=newbyte[sm.Length];sm.Read(

用PHP程序实现支持页面后退的两种方法

用PHP程序实现支持页面后退的两种方法 在开发过程中,往往因为表单出错而返回页面的时候填写的信息都不见了,为了支持页面回跳,可以通过两种方法实现. 第一,使用Header方法设置消息头Cache-control header('Cache-control: private, must-revalidate');  //支持页面回跳 第二,使用session_cache_limiter方法 //注意要写在session_start方法之前session_cache_limiter('private

转:部署和分发.NET应用程序的两种方法

部署和分发.NET应用程序的两种方法(技术巅峰 2001年10月09日 16:56)微软的.NET计划是一项激动人心的浩大工程,随着VS.NET Beta2版本的发布,.NET技术也逐渐趋于稳定和成型,越来越多的公司和技术爱好者投入到.NET的开发中来,而现在及早开始.NET的学习和相关开发正是好时机.但是,目前存在着的一个明显事实是,所有的基于.NET技术的应用程序或者产品都需要.NET的运行库支持,因为.NET在程序部署和分发方面有些类似,它需要.NET Framework SDK的支持(J

FMS3系列(一):第一个FMS程序,连接到FMS服务器(Flash/Flex两种实现)

FMS是个很牛X的东西,到底有多牛X我不想在这里多说,有兴趣的朋友可以baidu一把了解一下,如果实在是不想动手,那你就点下面的连接吧,我搜索了点资料简单的总结了一下. 你可以点击这里了解一些关于FMS的基本知识: 了解一些FMS的基本概念 通常做FMS都是和Flash或是Flex结合开发的,特别是在视频流这方面相当的突出,成功案例也不少,比如http://www.tudou.com, www.ku6.com , http://www.15dv.com 等视频网站都与FMS挂钩.本人也是因为工作

部署和分发.NET应用程序的两种方法(转)

    微软的.NET计划是一项激动人心的浩大工程,随着VS.NET Beta2版本的发布,.NET技术也逐渐趋于稳定和成型,越来越多的公司和技术爱好者投入到.NET的开发中来,而现在及早开始.NET的学习和相关开发正是好时机.但是,目前存在着的一个明显事实是,所有的基于.NET技术的应用程序或者产品都需要.NET的运行库支持,因为.NET在程序部署和分发方面有些类似,它需要.NET Framework SDK的支持(JAVA应用程序需要JDK的支持才可以运行),不幸的是,目前的Win9x系列以

加速ASP程序的运行速度的两种方法

程序|速度 1.使用表格嵌套?  在页面中建立复杂的结构,一般通过在页面中放置HTML表格来实现.如果要建立一个这样的页面:这个页面有一个顶部导航栏一个左边导航栏,一个右边的内容区.可以用一个两行两列的大表格来建立它.第一行中,合并两个列,然后插入一个顶部导航栏.第二行左边的列中,插入一个表格来显示导航按钮.右边的栏中,放置一个表格来实际内容.(见图一)这样嵌套的表格生成的代码是这样的:  <TABLE BORDER="0">  <TR>  <TD COL