在Visual c# 2010中嵌入DLL's到.exe in
本文关键字:in exe DLL Visual 2010 | 更新日期: 2023-09-27 18:04:14
我正在编写一个使用iTextSharp.dll和WebCam_Capture.dll的c#程序。当我构建程序时,它在调试文件夹中创建了可执行文件,并按预期将这两个dll复制到调试文件夹中。我想把它们合并成一个可执行文件,但是我失败了。这两个库通常在解决方案资源管理器的引用中可见。我还将它们作为资源添加。可执行文件的大小变大了,等于三个文件的总和,然而可执行文件仍然需要这些库在其目录中…我玩了"构建动作"属性的资源文件,但没有改变。我也尝试过合并,但它给了我一个错误。那我该怎么办呢?
更新:这是我从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将多个程序集合并在一起。您已经说过您这样做了,但是您收到了一个错误。虽然我不知道为什么,但您可以使用另一种方法:如果库是开源的(并且它们的许可证与您的许可证兼容),您可以下载源代码,将其添加到您的项目中并进行编译。这将产生一个单独的程序集。
ILMerge页面还列出了Jeffrey Richter的博客,作为解决您问题的另一个选择:
许多应用程序由EXE文件组成,该文件依赖于许多DLL文件。在部署此应用程序时,所有文件必须是部署。但是,您可以使用一种技术来进行部署只是一个单一的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); } };
现在,线程第一次调用引用类型in的方法依赖的DLL文件,则会引发AssemblyResolve事件,并且上面显示的回调代码将找到所需的嵌入式DLL资源并通过调用Assembly的load方法的重载来加载它接受一个Byte[]作为参数。
- 将DLL文件添加到Visual Studio项目中。
- 对于每个文件,进入"属性"并将其构建动作设置为"嵌入式资源"
- 在你的代码中使用GetManifestResourceStream("DLL_Name_Here")检索资源,这会返回一个可以加载的流。
- 编写一个"AssemblyResolve"事件处理程序来加载它。
代码如下:
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
//
}
}
希望有帮助,巴勃罗
我稍微修改了一下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;
}
您正在寻找的答案:
// 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);
}
};
查看应用域上的AssemblyResolve事件。
我没有一个样本,但你基本上检查什么是要求和流回资源DLL。我相信LinqPAD在这方面做得很好——你可以看看Joseph Albahari的反编译器实现。
将此匿名函数代码添加到应用程序构造函数的顶部。这将从同一项目的嵌入资源中添加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);
}
};
我知道这个话题已经过时了,但是我还是把它写下来给将来想要使用它的人。
i基于userSteve.
我建议修改一下。
String thisExe = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
into this
String thisExe = System.Reflection.Assembly.GetExecutingAssembly().EntryPoint.DeclaringType.Namespace;
这样即使命名空间不同于程序集名称
也可以工作如果你想使用DLL从目录,你可以这样使用它(目录资源为例)
String resourceName = thisExe + ".Resources." + embeddedAssembly.Name + ".dll";
如果你仍然找不到这个代码在c# Form应用程序中的位置,将它粘贴到文件"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/