从加载资源DLL库到当前域(主exe文件嵌入DLL)(Loading dll library fro

2019-08-02 21:48发布

我试着用下面的代码加载运行时DLL库,这样我就不必与主可执行文件一起提供大量的dll文件的用户。 我已经inlude所有的dll文件作为嵌入资源,并在参考部分我有包括它们,并有CopyLocal属性设置为false。 但这里的问题是:
1.所有DLL越来越复制到BIN \ Debug文件夹
2.我得到FileNotFoundException异常 。
我做了很多的搜索,以得到这些东西解决了,最后我在这里。 我有一个类似的代码, 在这里 ,但仍然不能做任何事情。 我应该怎么做才能防止这种例外...? 有没有更好的办法做Windows窗体应用程序(不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;
        }
    }
}

如果我使用不必要的东西在我的代码,那么你能告诉我正确的方式......我是学生,在Windows窗体应用程序V4.0项目工作提交我的论文。

Answer 1:

如果它仍然是你必须这样做的话,那么使用这种方法OnResolveAssembly。 没有必要将其预加载到一个数组,如果你不想。 这将加载他们,他们真正需要的第一次。

然后,只需:

  • some.assembly.dll文件添加到项目中。
    • 可能不是该项目的输出参考
    • 但该文件是DLL项目的结果。
  • 标记为在文件属性的资源

     // 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:这来自http://www.paulrohde.com/merging-a-wpf-application-into-a-single-exe/



Answer 2:

尝试以下方法:

  • 对于每一个.DLL资源:
    • 如果该文件的媒体链接存在AppDomain.Current.BaseDirectory然后继续下一个资源
    • 否则,保存资源的AppDomain.Current.BaseDirectory 。 在一个try-catch做到这一点,如果失败的话,通知用户。 对于这个步骤成功完成,你需要在安装文件夹(通常是“Program Files”下的子文件夹)的写权限。 这将通过运行程序作为管理员,该文件被写入文件系统上的第一次只AO来解决。
  • Ιf的组件是由你的VS项目中引用,那么你不必自己加载它们。 要理解为什么这项工作的,你需要了解组件是如何由CLR所在 。
  • 否则你将需要加载自己使用的每一个装配Assembly.Load称取无论是string或和AssemblyName作为参数。


文章来源: Loading dll library from Resource to Current Domain(Embedding dll in main exe file)
标签: c# dll byte exe