如何将dll中包含的组件嵌入到exe中,以便可以从内存中运行?

时间:2013-04-04 21:53:55

标签: c# .net

我正在尝试使用位于(引用的).dll中的自定义组件创建一个必须从内存(通过Assembly.Load(bin)所描述的here)运行的程序。

由于内存运行代码运行.exe,如何将组件嵌入到.exe中以便不需要.dll?

我已经尝试过ILMerge,但生成的.exe不会从内存中运行。 我看过this但是如果你引用了.dll(我必须这样做,因为它包含我表单上的组件),我认为它不起作用。

更新

在阅读了NSGaga的回答后,我尝试了以下内容:

  • 将项目中包含的组件.dll设置为嵌入式资源
  • 添加Program.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Windows.Forms;
    
    namespace MyApp
    {
        static class Program
        {
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main()
            {            
                AppDomain.CurrentDomain.AssemblyResolve +=
                (sender, args) =>
                {
                    // System.Diagnostics.Debugger.Break();
                    String resourceName = "MyApp." +
    
                        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);
    
                    }
    
                };
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new MainForm());
            }
        }
    }
    

不幸的是,这不起作用,我得到FileNotFoundException

无法加载文件或程序集“MetroFramework,Version = 1.2.0.0,Culture = neutral,PublicKeyToken = 5f91a84759bf584a”或其中一个依赖项。系统找不到指定的文件。

Application.Run(new MainForm());行发生异常。此外,有断点/添加消息框等,我不相信AssemblyResolve处理程序被调用 - 我做错了什么?

2 个答案:

答案 0 :(得分:1)

你已经回答了很多 - 来自Jeffrey Richter的manual solution应该可以正常工作 - ILMerge有问题(例如WPF)。

自从我玩了很长一段时间以来,你需要做的事情就是粗鲁......

1)准备一下您的应用程序 - 意思是 - 在设置AssemblyResolve处理程序之前,您无法加载任何内容。这也意味着任何事情,例如从'main'调来(甚至之后)必须先“解决”。简而言之,将您需要“引用”的所有内容移动到某些“后期”代码中,

2)尽快添加处理程序。我只想重复一下Richter的代码和一些信息。另请查看http://support.microsoft.com/kb/319292

AppDomain.CurrentDomain.AssemblyResolve +=
(sender, args) =>
{
    // System.Diagnostics.Debugger.Break();
    // Lookup what's your namespace in project properties
    String resourceName = "YourAssemblyNamespace." +
        new AssemblyName(args.Name).Name + ".dll";
    using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
    {
==>
        if (stream == null)
            return null;
==>
        Byte[] assemblyData = new Byte[stream.Length];
        stream.Read(assemblyData, 0, assemblyData.Length);
        return Assembly.Load(assemblyData);
    }
};

3)进行测试 - 将“加载”lib代码移动到某些“点击”或其他东西上 - 然后设置'Break'(就像我做的那样),

4)在根目录中添加你的dll-s`作为嵌入资源' - 就像bmp或其他东西一样。添加外部文件 - 然后将其在属性中设置为“嵌入资源”。

5)构建应用程序 - 注意大小的变化,应该是dll-s中的差异,

6)转到你的bin目录 - 并删除dll-s。不要再次构建项目并远离VS / Debugger,

7)启动应用并观察......

注意: 你可能会得到异常(比如你建议使用的lib) - 你需要处理stream == null。 '问题'是各种各样的dll-s经常被'试图加载(或从应用程序请求)并且它们安全失败 - 因为我们添加'处理程序'我们负责以同样的方式轻微失败。请参阅上面编辑的代码。

您的代码编辑:

您可能需要稍后开始移动窗口 - 您是否检查过该处理程序(断点和全部 - 也执行一些跟踪)。

问题是MainWindow分辨率一旦it gets visible开始 - 即在Main - 并且发生before实际代码运行或处理程序设置。所以...

static void Main(){
    ...
    DoAppSetup();
    // Application.EnableVisualStyles();
    // Application.SetCompatibleTextRenderingDefault(false);
    // Application.Run(new MainForm());
}
static void DoAppSetup(){
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}

......那样你的处理程序应该在任何东西尝试解决之前设置。

答案 1 :(得分:0)

如果您可以直接访问嵌入式资源,那么只需将它们嵌入到EXE中,如果它们位于第三方DLL中,那么您将无法将它们移出并嵌入它们而不会遇到实际问题潜在的法律问题。

如果可以的话,我建议直接嵌入EXE。