這一篇能夠看做是《Visual Studio 版本轉換工具WPF版開源了》的續,關於《Visual Studio 版本轉換工具WPF版開源了》能夠參看地下地址(兩篇是同樣的):html
** 博客園的Markdown編輯器真的不行,仍是麻煩你們穩步到http://my.oschina.net/chinesedragon/blog/309223觀看吧 **git
前幾一寫了一個小工具————《Visual Studio版本轉換工具》,因爲使用了WPF作爲界面,所以這個小程序運行必須附帶兩個DLL:Microsoft.Expression.Interactions.dll和System.Windows.Interactivity.dll,同時因爲本身也寫了一個庫,一個小程序須要附帶3個DLL,這種體驗真的很不爽,因而就着手把DLL嵌入到EXE中去。小程序
對於C#程序,要把DLL嵌入到EXE中去,最權威和最多見的方法就是使用ILMerge這個工具,這是個命令行工具,有不少參數,能夠將DLL很完美的嵌入到EXE中去,若是嫌命令行麻煩,也有人開源開發了圖形界面ILMergeGUI,這兩個工具的下載和幫助地址以下:app
下載ILMerge或者同時下載ILMerge-GUI,使用圖形界面和使用命令行是同一個道理,只是圖形界面簡單些,因此這裏以命令行說明。
我是下載ILMerge安裝後,把ILMerge.exe複製到C:\Windows目錄下去了,這樣能夠直接在命令行中使用而不用去設置環境變量,無論怎樣,只要可以在命令行下使用這個工具就行。
ILMerge有不少參數,其中有幾個比較重要:編輯器
ILMerge也使用Nuget發佈了工具,使用Nuget的好處想必你們都知道,因此推薦使用這種方法。
第一步, 使用Nuget圖形或Nuget命令下載ILMerge.MSBuild.Taskside
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) -> $(MergedAssembly)" Importance="high" /> <ILMerge InputAssemblies="@(MergeAsm)" OutputFile="$(MergedAssembly)" TargetKind="SameAsPrimaryAssembly" /> </Target>
這樣編譯後就能夠了。
學習
第一步,修改項目文件,將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文件,在程序啓動時加載資源ui
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
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還有不少用法,能夠到項目文檔學習。
Nuget是個十分強大的工具,使用Nuget在不少時候可使解決方法變得簡單,給Nuget贊一個!
再作下廣告,Visual Studio版本轉換工具WPF版的代碼託管地址是:http://git.oschina.net/shupengluo/VSConverter,歡迎交流。
最後,再小小地鄙視下微軟,^_^