简体   繁体   English

将DLL库从资源加载到当前域(在主exe文件中嵌入dll)

[英]Loading dll library from Resource to Current Domain(Embedding dll in main exe file)

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. 我正在尝试使用以下代码在运行时加载dll库,以便不必向用户提供很多dll文件以及主要的可执行文件。 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. 我将所有dll文件都包含为嵌入式资源,并且在参考部分中我将它们包括在内,并将CopyLocal属性设置为false。 But the problems here are: 但是这里的问题是:
1. All the dll are getting copied to Bin\\Debug folder 1.将所有dll复制到Bin \\ Debug文件夹
2. I'm getting FileNotFoundException . 2.我收到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) ...?? 是否有更好的方法可以对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;
        }
    }
}

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. 如果我在代码中不必要地使用了某些内容,那么您可以向我展示正确的方法...我是一名学生,正在研究Windows Form Application v4.0项目,以提交论文。

If it is still the case that you must do this, then use this OnResolveAssembly method. 如果仍然需要执行此操作,请使用此OnResolveAssembly方法。 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. some.assembly.dll文件添加到项目中。
    • probably not a reference to the project's output 可能不是对项目输出的引用
    • but the file that is the result of the DLL project. 但是该文件是DLL项目的结果。
  • 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 -Jesse

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

Try the following: 请尝试以下操作:

  • For each .dll resource: 对于每个.dll资源:
    • If the file allready exists on the AppDomain.Current.BaseDirectory then continue to the next resource 如果该文件已经在AppDomain.Current.BaseDirectory上存在,则继续下一个资源
    • Else save the resource to the AppDomain.Current.BaseDirectory . 否则将资源保存到AppDomain.Current.BaseDirectory Do this in a try-catch and if it fails, notify the user. 尝试尝试执行此操作,如果失败,则通知用户。 For this step to complete successfully you will need write access on the installation folder (usually a subfolder of "Program Files"). 为了成功完成此步骤,您将需要对安装文件夹(通常是“程序文件”的子文件夹)进行写访问。 This will be solved by running the program as an administrator the first time only ao that the files are written on the file system. 这将通过第一次以管理员身份运行该程序来解决,因为只有将文件写入文件系统中。
  • Ιf the assemblies are referenced by your VS project then you do not have to load them yourself. 如果您的VS项目引用了程序集,则不必自己加载它们。 To understand why this work's you will need to understand how assemblies are located by the CLR . 要了解为什么进行这项工作,您将需要了解CLR如何定位程序集
  • Else you will need to load each assembly yourself using one of the Assembly.Load that take either a string or and AssemblyName as a parameter. 否则,您将需要使用其中一个stringAssemblyName作为参数的Assembly.Load之一来自己加载每个程序集。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM