在Visual C#2010中将DLL嵌入到.exe中

我正在使用一个使用iTextSharp.dll和WebCam_Capture.dll的C#程序。 当我构建程序时,它在debug文件夹中创建可执行文件,它还会按预期将这两个dll复制到debug文件夹中。 我想将它们合并为一个可执行文件,但是我失败了。 通常在解决方案资源管理器中的参考中可以看到这两个库。 我还将它们添加为资源。 可执行文件大小变得更大,等于三个文件的总和,但是可执行文件仍然需要在其目录中使用这些库…我使用资源文件的“构建操作”属性但没有更改。 我也试过ILmerge,但它给了我一个错误。 所以我该怎么做?

更新:这是我从ILmerge得到的:

An exception occurred during merging: Unresolved assembly reference not allowed: System.Core. at System.Compiler.Ir2md.GetAssemblyRefIndex(AssemblyNode assembly) at System.Compiler.Ir2md.GetTypeRefIndex(TypeNode type) 

顺便说一句,这只是一个Windows应用程序,一个表格将被填写并打印为pdf,并通过网络摄像头拍照(如果有的话)。 谢谢大家!

您可以使用ILMerge将多个程序集合并在一起。 你已经说过你这么做了,而且你收到了一个错误。 虽然我不知道为什么,但您可以使用另一种选择:如果库是开源的(并且它们的许可证与您的许可证兼容),您可以下载源代码,将其添加到项目中并进行编译。 这将导致单个assembly。

ILMerge页面还列出了Jeffrey Richter的博客作为解决问题的另一种方法:

许多应用程序由依赖于许多DLL文件的EXE文件组成。 部署此应用程序时,必须部署所有文件。 但是,有一种技术可用于部署单个EXE文件。 首先,确定您的EXE文件所依赖的所有DLL文件,这些文件不作为Microsoft .NET Framework本身的一部分提供。 然后将这些DLL添加到Visual Studio项目中。 对于您添加的每个DLL文件,显示其属性并将其“构建操作”更改为“嵌入式资源”。这会导致C#编译器将DLL文件嵌入到EXE文件中,您可以部署此一个EXE文件。

在运行时,CLR将无法找到从属DLL程序集,这是一个问题。 要解决此问题,请在应用程序初始化时,使用AppDomain的ResolveAssembly事件注册回调方法。 代码看起来应该是这样的:

 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文件中的类型的方法时,将引发AssemblyResolve事件,并且上面显示的回调代码将找到所需的嵌入式DLL资源,并通过调用Assembly的Load方法的重载来加载它。以Byte []为参数。

  1. 将DLL文件添加到Visual Studio项目。
  2. 对于每个文件,转到“属性”并将其构建操作设置为“嵌入式资源”
  3. 在您的代码上使用GetManifestResourceStream(“DLL_Name_Here”)检索资源,这将返回可加载的流。
  4. 编写一个“AssemblyResolve”事件处理程序来加载它。

这是代码:

 using System; using System.Collections.Generic; using System.Reflection; using System.IO; namespace WindowsForm { public partial class Form1 : Form { Dictionary _libs = new Dictionary(); public Form1() { InitializeComponent(); AppDomain.CurrentDomain.AssemblyResolve += FindDLL; } private Assembly FindDLL(object sender, ResolveEventArgs args) { string keyName = new AssemblyName(args.Name).Name; // If DLL is loaded then don't load it again just return if (_libs.ContainsKey(keyName)) return _libs[keyName]; using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("YourNamespaceGoesHere." + keyName + ".dll")) // <-- To find out the Namespace name go to Your Project >> Properties >> Application >> Default namespace { byte[] buffer = new BinaryReader(stream).ReadBytes((int)stream.Length); Assembly assembly = Assembly.Load(buffer); _libs[keyName] = assembly; return assembly; } } // // Your Methods here // } } 

希望它有所帮助,巴勃罗

我稍微修改了Pablo的代码,它对我有用。
它没有正确获取DLL的资源名称。

 IDictionary _libs = new Dictionary(); public Form1() { AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); InitializeComponent(); } // dll handler System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { string keyName = new AssemblyName(args.Name).Name; // If DLL is loaded then don't load it again just return if (_libs.ContainsKey(keyName)) return _libs[keyName]; using (Stream stream = Assembly.GetExecutingAssembly() .GetManifestResourceStream(GetDllResourceName("itextsharp.dll"))) // <-- To find out the Namespace name go to Your Project >> Properties >> Application >> Default namespace { byte[] buffer = new BinaryReader(stream).ReadBytes((int)stream.Length); Assembly assembly = Assembly.Load(buffer); _libs[keyName] = assembly; return assembly; } } private string GetDllResourceName(string dllName) { string resourceName = string.Empty; foreach (string name in Assembly.GetExecutingAssembly().GetManifestResourceNames()) { if (name.EndsWith(dllName)) { resourceName = name; break; } } return resourceName; } 

您正在寻找的答案:

 // To embed a dll in a compiled exe: // 1 - Change the properties of the dll in References so that Copy Local=false // 2 - Add the dll file to the project as an additional file not just a reference // 3 - Change the properties of the file so that Build Action=Embedded Resource // 4 - Paste this code before Application.Run in the main exe AppDomain.CurrentDomain.AssemblyResolve += (Object sender, ResolveEventArgs args) => { String thisExe = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name; System.Reflection.AssemblyName embeddedAssembly = new System.Reflection.AssemblyName(args.Name); String resourceName = thisExe + "." + embeddedAssembly.Name + ".dll"; using (var stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) { Byte[] assemblyData = new Byte[stream.Length]; stream.Read(assemblyData, 0, assemblyData.Length); return System.Reflection.Assembly.Load(assemblyData); } }; 

在我们的应用程序构造函数的顶部添加此匿名函数代码。 这将从同一项目中的嵌入资源添加dll。

 AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { string resourceName = new AssemblyName(args.Name).Name + ".dll"; string resource = Array.Find(this.GetType().Assembly.GetManifestResourceNames(), element => element.EndsWith(resourceName)); using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resource)) { Byte[] assemblyData = new Byte[stream.Length]; stream.Read(assemblyData, 0, assemblyData.Length); return Assembly.Load(assemblyData); } }; 

查看app域上的AssemblyResolve事件。

我没有样本,但您基本上检查要求的内容并流回资源DLL。 我相信LinqPAD做得很好 – 你可以看一下Joseph Albahari用反编译器等的实现。

我知道这个话题已经过时但我会为将来想要使用它的人写这个话题。

我基于userSteve的代码。

我建议改变这个。

 String thisExe = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name; 

进入这个

 String thisExe = System.Reflection.Assembly.GetExecutingAssembly().EntryPoint.DeclaringType.Namespace; 

这样,即使名称空间与程序集名称不同,它也会起作用

如果你想从目录中使用DLL,你可以像那样使用它(目录资源作为示例)

 String resourceName = thisExe + ".Resources." + embeddedAssembly.Name + ".dll"; 

如果你仍然找不到C#表单应用程序中的这个代码将它粘贴到上面的文件“Program.cs”中:

 Application.Run(new Form_1()); 

以下线:

 Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); 

您没有使用WPF引用,但如果您使用WPF,则可能是您的错误原因。 如果没有,ILMerge应该可以正常工作。 如果您使用的是WPF,这里有一个效果很好的解决方案:

http://blogs.interknowlogy.com/2011/07/13/merging-a-wpf-application-into-a-single-exe/