在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格式,如果可以的话,可以通过网络摄像头拍摄照片。感谢所有!

在Visual c# 2010中嵌入DLL's到.exe in

可以使用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[]作为参数。

  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<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/