我正在使用一个使用iTextSharp.dll和WebCam_Capture.dll的C#程序。当我构建程序时,它会在调试文件夹中创建可执行文件,并且它还会按预期将这两个dll复制到调试文件夹中。我想将它们合并为一个可执行文件,但是我失败了。通常在解决方案资源管理器中的参考中可以看到这两个库。我还将它们添加为资源。可执行文件大小变得更大,等于三个文件的总和,但可执行文件仍然需要在其目录中使用这些库...我使用资源文件的“构建操作”属性但没有更改。我也试过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格式打印,并通过网络摄像头拍照(如果有的话)。谢谢大家!
答案 0 :(得分:9)
您可以使用ILMerge将多个程序集合并在一起。你已经说过你这么做了,而且你收到了一个错误。虽然我不知道为什么,但您可以使用另一种选择:如果库是开源的(并且它们的许可证与您的许可证兼容),您可以下载源代码,将其添加到项目中并进行编译。这将导致单个组件。
ILMerge页面还列出了Jeffrey Richter's blog作为解决问题的另一种方法:
许多应用程序都包含一个依赖于许多DLL的EXE文件 文件。部署此应用程序时,所有文件必须是 部署。但是,您可以使用一种技术进行部署 只是一个EXE文件。首先,确定您的所有DLL文件 EXE文件取决于不作为Microsoft .NET的一部分提供的文件 框架本身。然后将这些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 :(得分:7)
以下是代码:
using System;
using System.Collections.Generic;
using System.Reflection;
using System.IO;
namespace WindowsForm
{
public partial class Form1 : Form
{
Dictionary<string, Assembly> _libs = new Dictionary<string, Assembly>();
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
//
}
}
希望它有所帮助, 巴勃罗
答案 2 :(得分:3)
我稍微修改了Pablo的代码,它对我有用 它没有正确获取DLL的资源名称。
IDictionary<string, Assembly> _libs = new Dictionary<string, Assembly>();
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;
}
答案 3 :(得分:3)
您正在寻找的答案:
// 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);
}
};
答案 4 :(得分:1)
在我们的应用程序构造函数的顶部添加此匿名函数代码。这将从同一项目中的嵌入资源中添加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);
}
};
答案 5 :(得分:0)
查看应用域中的AssemblyResolve事件。
我没有样本,但您基本上检查了要求的内容并重新流回资源DLL。我相信LinqPAD做得很好 - 你可以看一下Joseph Albahari用反编译器等的实现。
答案 6 :(得分:0)
我知道这个话题已经过时了,但是我会把它写给想要使用它的未来的人。
我的代码基于 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#表单应用程序中此代码的位置,请将其粘贴到文件&#34; Program.cs&#34;上面一行:
Application.Run(new Form_1());
及以下行:
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
答案 7 :(得分:-1)
您没有使用WPF引用,但如果您使用WPF,则可能是导致错误的原因。如果没有,ILMerge应该可以正常工作。如果您使用的是WPF,这是一个运行良好的解决方案:
http://blogs.interknowlogy.com/2011/07/13/merging-a-wpf-application-into-a-single-exe/