将dll与wpf合并成一个.exe文件
我目前正在做一个项目,我们有很多的依赖关系。 我想将所有引用的dll编译到.exe中,就像使用embedded式资源一样。 我已经尝试ILMerge,但它不能处理.xaml资源。
所以我的问题是:有没有办法将WPF项目与多个依赖关系合并成一个.exe文件?
.NET反应器具有合并组件的function,而且其价格并不昂贵。
这对我来说就像一个魅力:),它是完全免费的。
添加代码以防博客消失。
1)将此添加到您的.csproj
文件中:
<Target Name="AfterResolveReferences"> <ItemGroup> <EmbeddedResource Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.dll'"> <LogicalName>%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension)</LogicalName> </EmbeddedResource> </ItemGroup> </Target>
2)让你的Main Program.cs
看起来像这样:
[STAThreadAttribute] public static void Main() { AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly; App.Main(); }
3)添加OnResolveAssembly
方法:
private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args) { Assembly executingAssembly = Assembly.GetExecutingAssembly(); AssemblyName assemblyName = new AssemblyName(args.Name); var 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; var assemblyRawBytes = new byte[stream.Length]; stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length); return Assembly.Load(assemblyRawBytes); } }
Costura是一个开源工具,用于处理合并wpf程序集。
{smartassembly}就是这样一个产品。 它可以隐藏或embedded你的DLL。
试试这个: http : //www.smartassembly.com/
你也可以在你的应用程序上做很多改进,以便运行得更快。
是的。 你可以使用它的WPF。
更新2015年8月6日:ILRepack 2.0.0(这是ILMerge的开源替代品)现在支持大部分WPF案例合并: https ://twitter.com/Gluckies/status/607680149157462016
正如在ILMerge网站上发布的那样 ,把这些DLL作为资源从杰弗里·里希特(Jeffrey Richter)
许多应用程序由依赖于许多DLL文件的EXE文件组成。 部署此应用程序时,必须部署所有文件。 但是,有一种技术可以用来部署一个EXE文件。 首先,找出您的EXE文件所依赖的所有DLL文件,这些文件不作为Microsoft .NET Framework本身的一部分提供。 然后将这些DLL添加到您的Visual Studio项目。 对于添加的每个DLL文件,显示其属性,并将其“Build Action”更改为“Embedded Resource”。这会导致C#编译器将DLL文件embedded到EXE文件中,并且可以部署这个EXE文件。 在运行时,CLR将无法find依赖的DLL程序集,这是一个问题。 为了解决这个问题,当你的应用程序初始化时,用AppDomain的ResolveAssembly事件注册一个callback方法。 代码应该是这样的:
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { String resourceName = "AssemblyLoadingAndReflection." + new AssemblyName(args.Name).Name + ".dll"; using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) { Byte[] assemblyData = new Byte[stream.Length]; stream.Read(assemblyData, 0, assemblyData.Length); return Assembly.Load(assemblyData); } };
现在,线程首次调用一个引用依赖DLL文件中的types的方法时,AssemblyResolve事件将被引发,上面显示的callback代码将find所需的embedded式DLL资源,并通过调用Assembly的Load方法的重载来加载它以Byte []作为参数。
使用Costura.Fody – 它可以作为Nuget Pkg,以最好的和最简单的方式来embedded资源在您的大会。
Install-Package Costura.Fody
将其添加到项目后,它会自动将所有添加的引用embedded到主程序集中。
尝试.Netz( http://madebits.com/netz/ ) – 它是免费的(如啤酒),并做一些很好的事情,如果你的目标是一个EXE。
下面是Matthieu引用代码的一个调整版本,它不需要知道命名空间来提取代码。 对于WPF,将其放入应用程序启动事件代码中。
AppDomain.CurrentDomain.AssemblyResolve += (s, args) => { // Note: Requires a using statement for System.Reflection and System.Diagnostics. Assembly assembly = Assembly.GetExecutingAssembly(); List<string> embeddedResources = new List<string>(assembly.GetManifestResourceNames()); string assemblyName = new AssemblyName(args.Name).Name; string fileName = string.Format("{0}.dll", assemblyName); string resourceName = embeddedResources.Where(ern => ern.EndsWith(fileName)).FirstOrDefault(); if (!string.IsNullOrWhiteSpace(resourceName)) { using (var stream = assembly.GetManifestResourceStream(resourceName)) { Byte[] assemblyData = new Byte[stream.Length]; stream.Read(assemblyData, 0, assemblyData.Length); var test = Assembly.Load(assemblyData); string namespace_ = test.GetTypes().Where(t => t.Name == assemblyName).Select(t => t.Namespace).FirstOrDefault(); #if DEBUG Debug.WriteLine(string.Format("\tNamespace for '{0}' is '{1}'", fileName, namespace_)); #endif return Assembly.Load(assemblyData); } } return null; };
为了在编译时使它们可用,我创build了一个名为ExternalDLLs的文件夹,并将dll复制到那里,并将它们设置为EmbeddedResource,如上所述。 要在代码中使用它们,您仍然需要设置对它们的引用,但将Copy local设置为False。 为了让代码无误地编译,你还需要在你的代码中使用stats来设置dll的命名空间。
这是一个小工具,它通过embedded的资源名称进行旋转,并在输出窗口中显示其名称空间。
private void getEmbeddedResourceNamespaces() { // Note: Requires a using statement for System.Reflection and System.Diagnostics. Assembly assembly = Assembly.GetExecutingAssembly(); List<string> embeddedResourceNames = new List<string>(assembly.GetManifestResourceNames()); foreach (string resourceName in embeddedResourceNames) { using (var stream = assembly.GetManifestResourceStream(resourceName)) { Byte[] assemblyData = new Byte[stream.Length]; stream.Read(assemblyData, 0, assemblyData.Length); try { var test = Assembly.Load(assemblyData); foreach (Type type in test.GetTypes()) { Debug.WriteLine(string.Format("\tNamespace for '{0}' is '{1}'", type.Name, type.Namespace)); } } catch { } } } }
- 将其添加到.csprofj文件中:
>
<Target Name="AfterResolveReferences"> <ItemGroup> <EmbeddedResource Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.dll'"> <LogicalName>%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension)</LogicalName> </EmbeddedResource> </ItemGroup> </Target>
-
右键单击project / properties / application / starup对象/selectSinhro.Program
-
将此添加到您的program.cs文件中:
使用System.Reflection; 使用System.IO; 使用System.Globalization;
[STAThreadAttribute] static void Main() { AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly; ... private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args) { Assembly executingAssembly = Assembly.GetExecutingAssembly(); AssemblyName assemblyName = new AssemblyName(args.Name); string 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); } }
来源: http : //www.digitallycreated.net/Blog/61/combining-multiple-assemblies-into-a-single-exe-for-a-wpf-application