将dll库从资源加载到当前域(在主exe文件中嵌入dll) [英] Loading dll library from Resource to Current Domain(Embedding dll in main exe file)

查看:210
本文介绍了将dll库从资源加载到当前域(在主exe文件中嵌入dll)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用以下代码在运行时加载dll库,以便我不必为用户提供大量的dll文件以及主要的可执行文件。我已经把所有的dll文件作为一个嵌入的资源,并且在引用部分我已经包含它们,并将 CopyLocal 属性设置为false。但这里的问题是:
1。所有的DLL都被复制到Bin\Debug文件夹
2。我正在获得 FileNotFoundException
我做了大量的搜索来解决这些问题,最后我在这里。我有一个类似的代码这里,但仍然不能'做任何事情我该怎么办才能防止这个异常?
有一个更好的方法来做同样的事情为一个 Windows窗体应用程序(不是WPF) ...?

  using System; 
使用System.Linq;
使用System.Windows.Forms;
使用System.Diagnostics;
使用System.Reflection;
使用System.Collections.Generic;
使用System.IO;

命名空间MyNameSpace
{
static class Program
{
static int cnt;
static IDictionary< string,Assembly> assemblyDictionary;
[STAThread]
static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve + = OnResolveAssembly;
if(cnt!= 1)
{
cnt = 1;
Assembly executionAssembly = Assembly.GetExecutingAssembly();
string [] resources = executionAssembly.GetManifestResourceNames();
foreach(资源中的字符串资源)
{
if(resource.EndsWith(。dll))
{
using(Stream stream = executionAssembly.GetManifestResourceStream资源))
{
if(stream == null)
continue;

byte [] assemblyRawBytes = new byte [stream.Length];
stream.Read(assemblyRawBytes,0,assemblyRawBytes.Length);
try
{
assemblyDictionary.Add(resource,Assembly.Load(assemblyRawBytes));
}
catch(Exception ex)
{
MessageBox.Show(Failed to load:+ resource +Exception:+ ex.Message);
}
}
}
}
Program.Main();
}
if(cnt == 1)
{
cnt = 2;
System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Highest;
Application.ThreadException + = new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Application.ApplicationExit + = new EventHandler(Application_ApplicationExit);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}

private static Assembly OnResolveAssembly(object sender,ResolveEventArgs args)
{
AssemblyName assemblyName = new AssemblyName(args.Name);

string path = assemblyName.Name +.dll;

if(assemblyDictionary.ContainsKey(path))
{
return assemblyDictionary [path];
}
返回null;
}
}
}

如果我在使用某物我不必要的在我的代码,那么你可以告诉我正确的方式...
我是一个学生工作在 Windows窗体应用程序v4.0 项目我的论文提交。

解决方案

如果仍然是您必须执行此操作,则使用此OnResolveAssembly方法。如果您不想,则无需将其预加载到阵列中。这将在第一次实际需要时加载。



然后只是:




  • some.assembly.dll 文件添加到项目中。


    • 可能不是对项目输出的引用



    • ,但该文件是DLL项目的结果。 b $ b

  • 在文件属性中标记为资源

      //如果程序集以前已经加载到内存中,则不会调用此函数。 
    //如果程序集与应用程序已经在同一个文件夹中,则不会调用此函数。
    //
    private static Assembly OnResolveAssembly(object sender,ResolveEventArgs e)
    {
    var thisAssembly = Assembly.GetExecutingAssembly();

    //获取AssemblyFile的名称
    var assemblyName = new AssemblyName(e.Name);
    var dllName = assemblyName.Name +.dll;

    //从嵌入式资源加载
    var resources = thisAssembly.GetManifestResourceNames()。Where(s => s.EndsWith(dllName));
    if(resources.Any())
    {
    // 99%的情况下只有一个匹配的项目,但是如果没有,
    //你会有改变逻辑来处理这些情况。
    var resourceName = resources.First();
    使用(var stream = thisAssembly.GetManifestResourceStream(resourceName))
    {
    if(stream == null)return null;
    var block = new byte [stream.Length];

    //安全地尝试加载程序集。
    try
    {
    stream.Read(block,0,block.Length);
    return Assembly.Load(block);
    }
    catch(IOException)
    {
    return null;
    }
    catch(BadImageFormatException)
    {
    return null;
    }
    }
    }

    //在资源不存在的情况下,返回null。
    返回null;
    }




-Jesse

PS:这来自 http://www.paulrohde.com/merging-a-wpf-application-into-a-single-exe/


I'm trying to load dll libraries during runtime using the following code so that I don't have to provide the user with lot of dll files along with the main executable file. I have inlude all the dll files as an embedded resource and also in the reference part I have include them and have set the CopyLocal property to false. But the problems here are:
1. All the dll are getting copied to Bin\Debug folder
2. I'm getting FileNotFoundException.
I did lot of searches to get these things resolved and finally I'm here. I got a similar code here but still couldn't do anything. What should I do to prevent this exception...?? Is there a better way to do the same thing for a Windows Form Application(Not WPF)...??

using System;
using System.Linq;
using System.Windows.Forms;
using System.Diagnostics;
using System.Reflection;
using System.Collections.Generic;
using System.IO;

namespace MyNameSpace
{
    static class Program
    {
        static int cnt;
        static IDictionary<string, Assembly> assemblyDictionary;
        [STAThread]
        static void Main()
        {
            AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;
            if (cnt != 1)
            {
                cnt = 1;
                Assembly executingAssembly = Assembly.GetExecutingAssembly();
                string[] resources = executingAssembly.GetManifestResourceNames();
                foreach (string resource in resources)
                {
                    if (resource.EndsWith(".dll"))
                    {
                        using (Stream stream = executingAssembly.GetManifestResourceStream(resource))
                        {
                            if (stream == null)
                                continue;

                            byte[] assemblyRawBytes = new byte[stream.Length];
                            stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
                            try
                            {
                                assemblyDictionary.Add(resource, Assembly.Load(assemblyRawBytes));
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show("Failed to load: " + resource + " Exception: " + ex.Message);
                            }
                        }
                    }
                }
                Program.Main();
            }
            if (cnt == 1)
            {
                cnt = 2;
                System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Highest;
                Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
                Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new MainForm());
            }
        }

        private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
        {            
            AssemblyName assemblyName = new AssemblyName(args.Name);

            string path = assemblyName.Name + ".dll";

            if (assemblyDictionary.ContainsKey(path))
            {
                return assemblyDictionary[path];
            }
            return null;
        }
    }
}

If I'm using something unnecessarily in my code then you can show me the right way... I'm a student working on Windows Form Application v4.0 project for my papers to be submitted.

解决方案

If it is still the case that you must do this, then use this OnResolveAssembly method. There is no need to preload them into an array if you don't want to. This will load them the first time they are actually needed.

Then just:

  • add the some.assembly.dll file to the project.
    • probably not a reference to the project's output
    • but the file that is the result of the DLL project.
  • mark it as a Resource in the file properties.

    // This function is not called if the Assembly is already previously loaded into memory.
    // This function is not called if the Assembly is already in the same folder as the app.
    //
    private static Assembly OnResolveAssembly(object sender, ResolveEventArgs e)
    {
        var thisAssembly = Assembly.GetExecutingAssembly();
    
        // Get the Name of the AssemblyFile
        var assemblyName = new AssemblyName(e.Name);
        var dllName = assemblyName.Name + ".dll";
    
        // Load from Embedded Resources
        var resources = thisAssembly.GetManifestResourceNames().Where(s => s.EndsWith(dllName));
        if (resources.Any())
        {
            // 99% of cases will only have one matching item, but if you don't,
            // you will have to change the logic to handle those cases.
            var resourceName = resources.First();
            using (var stream = thisAssembly.GetManifestResourceStream(resourceName))
            {
                if (stream == null) return null;
                var block = new byte[stream.Length];
    
                // Safely try to load the assembly.
                try
                {
                    stream.Read(block, 0, block.Length);
                    return Assembly.Load(block);
                }
                catch (IOException)
                {
                    return null;
                }
                catch (BadImageFormatException)
                {
                    return null;
                }
            }
        }
    
        // in the case the resource doesn't exist, return null.
        return null;
    }
    

-Jesse

PS: This comes from http://www.paulrohde.com/merging-a-wpf-application-into-a-single-exe/

这篇关于将dll库从资源加载到当前域(在主exe文件中嵌入dll)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆