使用 .Net 提供额外的 platform.dependent .dll

Posted

技术标签:

【中文标题】使用 .Net 提供额外的 platform.dependent .dll【英文标题】:Provide additional platform.dependent .dll with .Net 【发布时间】:2018-07-11 07:53:28 【问题描述】:

我有一个应用程序(.Net 4.6.1,WPF),它需要在生产系统上运行一个特定的 .dll(非托管)。该 DLL 有两个版本(x64 和 x86)。我如何(应该)在我的项目中为不同平台打包 DLL?

当然,有可能创建两个项目,一个只针对 x64,一个分别针对 x86,但我想避免这种开销。

理想情况下,我正在考虑类似文件夹结构的东西

cwd/
    app.exe
    component.dll
    lib/
        x86/
            provided.dll
        x64/
            provided.dll

应用程序在启动时根据运行时平台 (x64/x86) 加载正确提供的 DLL。

很遗憾,我无法更改应用程序本身的程序集加载(在启动时自动完成)。

关于搜索路径,我检查了 [1],但找不到特定于平台的加载信息。

有没有办法(最佳实践)来实现这一目标?

[1]https://docs.microsoft.com/de-de/windows/desktop/Dlls/dynamic-link-library-search-order

【问题讨论】:

您需要以一种或另一种方式将您的应用程序与 x64 dll 一起分发到 64 位系统,反之亦然。您目前如何部署应用程序? 目前,通过处理优化的发布版本以及所需的 DLL 来部署应用程序。在当前的生产环境中,只有 x64 设备,因此主应用程序(Any CPU)以及 x64 的 DLL 运行良好。现场部署了具有 x64 和 x86 架构(Win 7 和 Win 10)的新系统。该应用程序应该可以在自动加载正确 DLL 的两个系统上运行。 由于我无法控制加载顺序本身,因此最好将两个版本中的 DLL 打包在(子)文件夹中,并且运行时链接器可以选择正确的。问题是,这是可能的还是我需要为它提供不同的应用程序二进制文件? 如果您无法修改代码,您将不得不提供不同的二进制文件。但是,如果您手动复制应用程序文件,这应该不是问题。只需提供两个版本的应用程序;一个 32 位和一个 64 位版本。 @mm8 我很害怕...我希望在链接器级别有另一个解决方案 - 感谢您清理问题 - 祝您有美好的一天! 【参考方案1】:

它有办法做到这一点。

执行此操作的简单方法是使 DLL 编译为可在 x86 和 x64 中使用的任何 CPU,但您的 dll 不受管理,可能无法编译为任何 CPU。

使用宏的另一种方法。在 x86 和 x64 中添加差异宏,如在 x86 中添加 x86

你可以编写代码来加载不同的DLL。

#if x86
        public const string DLL_FILE_NAME = "DLL_32.dll";
#else
        public const string DLL_FILE_NAME = "DLL_64.dll";
#endif

        [DllImport(DLL_FILE_NAME, EntryPoint = "Foo", CallingConvention = CallingConvention.Cdecl)]
        private static extern int Foo1(int var1, int var2);

另一种方法是使用调用 x64 和 x86 的两种方法。

    [DllImport("DLL_32.dll", EntryPoint = "Foo",
        CallingConvention = CallingConvention.Cdecl)]
    private static extern int Foo32(int txcuiwKjvwu, int hhmzfadnHexkmr);

    [DllImport("DLL_64.dll", EntryPoint = "Foo",
        CallingConvention = CallingConvention.Cdecl)]
    private static extern int Foo64(int txcuiwKjvwu, int hhmzfadnHexkmr);

您可以使用Environment.Is64BitProcess 将应用程序获取为 x86 或 x64。

   public int Foo(int txcuiwKjvwu, int hhmzfadnHexkmr)
    
        if (Environment.Is64BitProcess)
        
            return Foo64(txcuiwKjvwu, hhmzfadnHexkmr);
        

        return Foo32(txcuiwKjvwu, hhmzfadnHexkmr);
    

最后但并非最不重要的是使用SetDllDirectory 设置目录。

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool SetDllDirectory(string path);
   var path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
      path = Path.Combine(path, Environment.Is64BitProcess ? "x64" : "x86");
      SetDllDirectory(path);

设置查找DLL的Path可以很方便的加载一些非托管的DLL。

【讨论】:

感谢您的回复,但是这些解决方案需要更改我无法控制的程序集加载过程(外部提供的代码,在启动时按名称加载程序集)。将 FooX64.dll 放在同一文件夹中时,可以找到它,但在 x86 运行时会因 badimage 而崩溃,反之亦然。【参考方案2】:

很遗憾,我无法更改应用程序本身的程序集加载(在启动时自动完成)。

然后,您就无法将应用程序与适当的 DLL 一起部署。

您可以提供两个版本的应用;一个包含x86/provided.dll 的32 位版本和另一个包含x64/provided.dll 的64 位版本。然后,用户必须根据他们的 CPU 架构安装适当的版本。

【讨论】:

以上是关于使用 .Net 提供额外的 platform.dependent .dll的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 ASP.NET 从后面的代码中添加一个额外的 css 类?

Asp.net:如何在会员数据库中添加额外的用户详细信息?

传递额外的值 Passing Extra Values |在视图中生成输出URL | 高级路由特性 | 精通ASP-NET-MVC-5-弗瑞曼

Asp.net 身份额外的用户信息,如电子邮件等

为啥 .NET 会在路径中已经存在的斜杠上添加一个额外的斜杠?

.Net Core ConfigureAppConfiguration 添加额外的源覆盖环境特定设置