.net CPU体系结构独立的P/Invoke:DllName或path是否可以是;动态的;?

.net CPU体系结构独立的P/Invoke:DllName或path是否可以是;动态的;?,.net,pinvoke,dllimport,32bit-64bit,.net,Pinvoke,Dllimport,32bit 64bit,有没有办法让p/Invoke(DllImport)签名引用特定的DLL取决于CPU体系结构 我正在开发一个应用程序,该应用程序从第三方供应商的本机dll加载大量方法签名,在本例中,用户空间接口dll加载到一个硬件。该供应商现在已经开始提供x86和x64版本的DLL,我认为我的应用程序将受益于作为64位进程运行。除了这个DLL,所有的东西都是.NET代码,所以构建“任何CPU”都可以 本机DLL中的所有方法签名在64位上是相同的,但DLL的名称不同(Foo.DLL与Foo_x64.DLL)。是否有

有没有办法让p/Invoke(DllImport)签名引用特定的DLL取决于CPU体系结构

我正在开发一个应用程序,该应用程序从第三方供应商的本机dll加载大量方法签名,在本例中,用户空间接口dll加载到一个硬件。该供应商现在已经开始提供x86和x64版本的DLL,我认为我的应用程序将受益于作为64位进程运行。除了这个DLL,所有的东西都是.NET代码,所以构建“任何CPU”都可以

本机DLL中的所有方法签名在64位上是相同的,但DLL的名称不同(Foo.DLL与Foo_x64.DLL)。是否有任何方法可以通过P/Invoke签名或app.config条目让它根据运行的CPU体系结构选择要加载的DLL

如果不同文件夹中的DLL名称相同,而不是不同的DLL名称,则会打开其他选项吗


注意:由于此用户空间DLL的版本必须与硬件安装的内核驱动程序相匹配,因此DLL不会与我们的应用程序捆绑在一起,而是依赖于供应商安装程序将其放置在%PATH%的目录中。

无法拥有单个PInvoke签名并获得您想要的行为。该属性被烧成元数据,并且必须具有常量值。你可以做的一件事就是使用多种方法

public static class NativeMethods32 {
  [DllImport("Foo.dll")]
  public static extern int SomeMethod();
}

public static class NativeMethods64 {
  [DllImport("Foo_x864.dll")]
  public static extern int SomeMethod();
}

public static class NativeMethods {
  public static bool Is32Bit { return 4 == IntPtr.Size; }
  public static SomeMethod() {
    return Is32Bit ? 
      NativeMethods32.SomeMethod(); 
      NativeMethods64.SomeMethod();
  }
}
然而,这不是首选的方法。更简单的方法是使DLL在多个平台上具有相同的名称,并创建一个平台无关的PInvoke签名。这是大多数/所有windows库采用的方法

如果不同文件夹中的DLL名称相同,而不是不同的DLL名称,是否会打开其他选项

也许这对你有用:

public static class NativeMethods
{
  // here we just use "Foo" and at runtime we load "Foo.dll" dynamically
  // from any path on disk depending on the logic you want to implement
  [DllImport("Foo", EntryPoint = "bar")]
  private void bar();

  [DllImport("kernel32")]
  private unsafe static extern void* LoadLibrary(string dllname);

  [DllImport("kernel32")]
  private unsafe static extern void FreeLibrary(void* handle);

  private sealed unsafe class LibraryUnloader
  {
    internal LibraryUnloader(void* handle)
    {
      this.handle = handle;
    }

    ~LibraryUnloader()
    {
      if (handle != null)
        FreeLibrary(handle);
    }

    private void* handle;

  } // LibraryUnloader

  private static readonly LibraryUnloader unloader;

  static NativeMethods()
  {
    string path;

    if (IntPtr.Size == 4)
      path = "path/to/the/32/bit/Foo.dll";
    else
      path = "path/to/the/64/bit/Foo.dll";

    unsafe
    {
      void* handle = LoadLibrary(path);

      if (handle == null)
        throw new DllNotFoundException("unable to find the native Foo library: " + path);

      unloader = new LibraryUnloader(handle);
    }
  }
}
它包括在p/Invoke自身尝试加载本机库之前,显式加载本机库及其完整路径


你觉得怎么样?

我为目标开发了一个特殊的库:。它引入了带有动态库路径解析(动态)的新
RuntimeDllImport
属性。默认情况下,您可以编写

[RuntimeDllImport("NativeLib", 
   CallingConvention = CallingConvention.Cdecl, EntryPoint = "sum")]
int Sum(int a, int b);
而这个库将取决于环境。例如,Win/Linux、x86/x64的路径:

x86/NativeLib.dll
x86/libNativeLib.so
x64/NativeLib.dll
x64/libNativeLib.so

相同名称的东西不适用于我的情况,因为1)这是第三方供应商DLL 2)DLL安装到系统路径中的文件夹中,以便应用程序可以在64位操作系统上自动找到它们(谢天谢地,供应商不再安装到%SystemRoot%\system32)3,32位和64位DLL都需要可用#1意味着我不能摆弄#2与#3冲突。我最终使用了一种类似于你建议的解决方案。我用所有方法定义了一个接口,并使用LinFu在运行时创建了一个代理对象,该对象将转发到正确的静态方法。它将与Window/MS.NET一起使用,但是Mono呢?不知道Mono,请告诉我们您发现了什么您不必使用
不安全的
关键字,您可以使用
IntPtr
键入并放弃
void*
。对于其他平台,也有类似的API可以在运行时加载链接库,我怀疑这些系统上的实现会类似。只是不同于
LoadLibrary
的API调用。顺便说一句,
freebrary
不需要,除非您确实需要从内存中卸载库,只有当DLL的生命周期与应用程序的生命周期不同时才会出现这种情况。@tig指针的大小告诉您当前的体系结构是32位还是64位,我认为复制是另一种情况,因为这个问题比那个问题早四年:)