目标32位或64位本机DLL取决于环境

时间:2014-04-22 09:25:06

标签: c# .net dll pinvoke

我有一个本机DLL,它有32位和64位版本(x86)。我想创建一个适用于两种体系结构(任何CPU)的包装器,并根据当前环境(32位或64位,在运行时!)加载正确版本的DLL。此过程应自动进行,以便我的DLL用户不需要针对特定​​的体系结构。

有关于如何做到这一点的最佳做法吗?有什么可以指导我的例子吗?

我找到了一种可能的解决方案,它为每个架构使用托管代理,然后使用Assembly.Resolve事件加载正确的版本。但是,除了2个非托管库之外,这需要我有3个托管程序集,这看起来有点矫枉过正。

还有其他解决方案吗?

3 个答案:

答案 0 :(得分:4)

我这样做的方法是在调用对库的任何p /调用之前调用LoadLibrary

  • 使用正在执行的程序集的位数来计算要加载的非托管DLL的版本。
  • 然后调用LoadLibrary加载它,传递DLL的完整路径。
  • 然后当你调用p / invokes时,正确的DLL已经加载到进程中,并且p / invokes绑定到它。

这依赖于32位和64位具有相同名称的非托管DLL。如果情况并非如此,那么你就麻烦了。在这种情况下,您可能需要通过p /调用GetProcAddress显式绑定到DLL。这根本不好玩。或者你实现了Simon在他的回答中描述的那种脚手架。

答案 1 :(得分:4)

以下是我在许多项目中使用的解决方案:

  • 使用" 32位面向名称"命名32位程序集。对于 示例MyAssembly.Native.x86.dll
  • 使用" 64位面向名称"命名64位程序集。例如MyAssembly.Native.x64.dll
  • 将托管程序集编译为'任何Cpu'
  • 将所有内容都放在同一条路径中

以下是我如何声明P / Invoke方法:

[DllImport("MyAssembly.Native.x86.dll", EntryPoint = "MyTest")]
private static extern void MyTest86(MyType myArg);

[DllImport("MyAssembly.Native.x64.dll", EntryPoint = "MyTest")]
private static extern void MyTest64(MyType myArg);

这是相应的“我的测试”。我将永远使用的功能(其他功能只是为了正确的位数绑定)。它具有与其他P / Invoke相同的签名:

public static void MyTest(MyType myArg)
{
    if (IntPtr.Size == 8)
    {
        MyTest64(myArg);
        return;
    }

    MyTest86(myArg);
}

优点是:

  • 您可以在同一路径中发送所有二进制文件(DLL,EXE,...)
  • 您支持具有相同文件布局的32位和64位进程和操作系统
  • 您不必使用Win32 apis来更改dll加载路径

给您带来的不便是:

  • 您将为1'真实'提供3个方法声明。方法
  • 由于比特测试,你会松开一些CPU周期
  • 根据您的上下文,有时您无法更改原生DLL名称,因此您无法执行此操作

答案 2 :(得分:0)

查看Microsoft.WinAny.Helper DynamicNativeLibrary 类,它可以帮助您满足需要。