ILMerge 替代方案,如何将应用程序的依赖 DLL 嵌入 EXE 文件中?

发布于 2024-10-24 08:26:30 字数 1298 浏览 2 评论 0原文

正如此处所述,我试图将 dll 嵌入到 exe 应用程序中,以便仅分发一个 exe,但是当我尝试在安装了完整 .NET 4 的 xp 计算机上运行我的应用程序时,它只是崩溃时没有错误,我将以下代码放在主方法上

[STAThread]
        static void Main()
        {
            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);
                }
            };

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new frmrPrincipal());
        }

,我有一个名为 dlls 的文件夹,我将其放置

Functions.Shared.dll
Alex.UI.dll
Alex.Controls.dll

并将其构建操作设置为“嵌入式资源”。

如果我删除那段代码并将 dll 设置为通过单击一次安装程序来包含,则它可以正常工作。顺便说一句,我使用 .NET Framework 4 完整配置文件和 VS2010 SP1

As stated here im trying to embed the dlls in the exe application in order to just distribute one exe, but when i try to run my application on a xp machine with full .NET 4 installed it just crashes with no error, im placing the following code on the main method

[STAThread]
        static void Main()
        {
            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);
                }
            };

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new frmrPrincipal());
        }

i have a folder named dlls where im placing

Functions.Shared.dll
Alex.UI.dll
Alex.Controls.dll

and im setting its Build Action to "Embedded Resource".

if i remove that piece of code and set the dlls to be included by click once installer it works fine. btw im Using .NET Framework 4 Full profile and VS2010 SP1

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

末骤雨初歇 2024-10-31 08:26:30

当它尝试抖动 Main() 方法时,抖动会变得剧烈。 AssemblyResolve 还没有注册,先有鸡还是先有蛋的问题。您只能使用 Main 中可用的类型,因此您必须远离 frmrPrincipal。使用一些辅助方法可以解决该问题,但现在您必须使用 [MethodImpl] 抑制内联。如果你不让 ngen.exe 完成它的工作,你也会搬起石头砸自己的脚。

using System.Runtime.CompilerServices;
...
    [STAThread]
    static void Main()
    {
        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
        {
            // etc..
        }
        AvoidJitterBombing();
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    private static void AvoidJitterBombing() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new frmrPrincipal());
    }

The jitter goes kaboom when it tries to jit the Main() method. AssemblyResolve isn't registered yet, chicken and egg problem. You can only use types in Main that are available, so you'll have to stay away from frmrPrincipal. Using a little helper method can solve that problem, but now you'll have to suppress inlining with [MethodImpl]. You are also shooting your foot by not allowing ngen.exe to do its job.

using System.Runtime.CompilerServices;
...
    [STAThread]
    static void Main()
    {
        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
        {
            // etc..
        }
        AvoidJitterBombing();
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    private static void AvoidJitterBombing() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new frmrPrincipal());
    }
风蛊 2024-10-31 08:26:30

我最近玩过这个,从这段代码或一段非常相似的代码开始,我认为 resourceName 的构造是错误的。尝试在解析方法的开头放置一个断点,然后在执行程序集上调用 GetManifestResourceNames() 以查看它实际上为嵌入资源提供的名称。

我怀疑它可能是“dlls.Functions.Shared”等而不是“AssemblyLoadingAndReflection.Functions.Shared”

I played with this recently, starting from this or a very similar piece of code, and I think the construction of the resourceName is wrong. Try putting a breakpoint at the beginning of the resolve method, and then calling GetManifestResourceNames() on the executing assembly to see what name it is actually giving your embedded resources.

I suspect it's probably "dlls.Functions.Shared" and so forth instead of "AssemblyLoadingAndReflection.Functions.Shared"

寒江雪… 2024-10-31 08:26:30

您可以查看 .NETZ,我们与 ClickOnce 一起用于 WinForms 应用程序部署。

You might take a look at .NETZ, we used for WinForms application deployment along with ClickOnce.

七婞 2024-10-31 08:26:30

我怀疑您正在尝试加载带有非托管代码的 dll。对于托管 dll,只需读取并加载内存中的程序集即可,或者您甚至可以从某个位置加载,甚至无需读取。对于混合模式程序集,我仅通过将字节写入文件并从其位置加载来获得成功。

class Program
{
    [STAThread]
    static void Main()
    {
        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
        {
            string assemblyName = new AssemblyName(args.Name).Name;
            if (assemblyName.EndsWith(".resources"))
                return null;

            string dllName = assemblyName + ".dll";
            string dllFullPath = Path.Combine(GetMyApplicationSpecificPath(), dllName);

            using (Stream s = Assembly.GetEntryAssembly().GetManifestResourceStream(typeof(Program).Namespace + ".Resources." + dllName))
            {
                byte[] data = new byte[stream.Length];
                s.Read(data, 0, data.Length);

                //or just byte[] data = new BinaryReader(s).ReadBytes((int)s.Length);

                File.WriteAllBytes(dllFullPath, data);
            }

            return Assembly.LoadFrom(dllFullPath);
        };

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new frmrPrincipal());
    }
}

其中 Program 是类名。为了避免先有鸡还是先有蛋的问题,您必须确保在访问程序集之前声明处理程序,并且不要访问加载(程序集解析)部分内的程序集成员(或实例化任何必须处理程序集的内容)。另请注意确保 GetMyApplicationSpecificPath() 不是任何临时目录,因为其他程序或您自己可能会尝试删除临时文件(并不是说在您的程序访问 dll 时它会被删除,但至少 AppData 的位置很好)。另请注意,每次都必须写入字节,不能仅从位置加载,因为 dll 已经驻留在该位置。

I suspect you are trying to load a dll with unmanaged code. For managed dlls merely reading and loading the assembly in memory would do or you can load from a certain location without even reading. For mixed mode assemblies, I had success only by writing the bytes to a file and loading from its location.

class Program
{
    [STAThread]
    static void Main()
    {
        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
        {
            string assemblyName = new AssemblyName(args.Name).Name;
            if (assemblyName.EndsWith(".resources"))
                return null;

            string dllName = assemblyName + ".dll";
            string dllFullPath = Path.Combine(GetMyApplicationSpecificPath(), dllName);

            using (Stream s = Assembly.GetEntryAssembly().GetManifestResourceStream(typeof(Program).Namespace + ".Resources." + dllName))
            {
                byte[] data = new byte[stream.Length];
                s.Read(data, 0, data.Length);

                //or just byte[] data = new BinaryReader(s).ReadBytes((int)s.Length);

                File.WriteAllBytes(dllFullPath, data);
            }

            return Assembly.LoadFrom(dllFullPath);
        };

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new frmrPrincipal());
    }
}

where Program is the class name. To avoid chicken and egg problem, you have to ensure you declare the handler before accessing assembly and that you do not access the assembly members (or instantiate anything that has to deal with the assembly) inside the loading (assembly resolving) part. Also take care to ensure GetMyApplicationSpecificPath() is not any temp directory since temp files could be attempted to get erased by other programs or by yourself (not that it will get deleted while your program is accessing the dll, but at least its a nuisance. AppData is good location). Also note that you have to write the bytes each time, you cant just load from location just 'cos the dll already resides there.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文