CPU架构独立P/Invoke:DllName或路径可以是"动态的"吗?

Che*_*tah 10 .net pinvoke dllimport 32bit-64bit

有没有办法让P/Invoke(DllImport)签名引用的特定DLL依赖于CPU架构?

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

本机DLL中的所有方法签名在64位上都相同,但DLL的名称不同(Foo.dll与Foo_x64.dll).有没有办法通过P/Invoke签名或app.config条目我可以让它根据正在运行的CPU架构选择加载哪个DLL?

如果不是不同的DLL名称,它在不同的文件夹中是相同的名称,它是否打开任何其他选项?

注意:因为此用户空间DLL的版本必须与安装的硬件内核驱动程序匹配,所以DLL不与我们的应用程序捆绑在一起,而是依靠供应商安装程序将其放在%的目录中路径%.

Gre*_*osz 11

"如果不是不同的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);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

它包括在P/Invoke本身尝试加载之前显式加载本机库及其完整路径.

你怎么看?


Jar*_*Par 4

没有办法拥有单个 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();
  }
}
Run Code Online (Sandbox Code Playgroud)

然而,这不是首选方法。一种更简单的方法是使 DLL 在多个平台上具有相同的名称,并创建与平台无关的 PInvoke 签名。这是大多数/所有 Windows 库所采用的方法。