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

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

有关于如何做到这一点的最佳实践吗? 任何可以指导我的例子?

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

还有其他解决方案吗?

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

  • 使用“32位面向名称”命名32位程序集。 例如MyAssembly.Native.x86.dll
  • 使用“64位面向名称”命名64位程序集。 例如MyAssembly.Native.x64.dll
  • 将托管程序集编译为’Any 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); 

这里是相应的’MyTest’函数,这是我将永远使用的函数(其他函数只是为了正确的位数绑定)。 它具有与其他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名称,因此您无法执行此操作

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

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

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

看一下Microsoft.WinAny.Helper和It’a DynamicNativeLibrary类,它可以帮助您满足您的需求。