使用 .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 类?
传递额外的值 Passing Extra Values |在视图中生成输出URL | 高级路由特性 | 精通ASP-NET-MVC-5-弗瑞曼