10

P/Invoke (DllImport) 署名によって参照される特定の DLL を CPU アーキテクチャに依存させる方法はありますか?

私は、サード パーティ ベンダーのネイティブ dll (この場合はハードウェアのユーザー空間インターフェイス DLL) から多数のメソッド シグネチャをロードするアプリケーションに取り組んでいます。そのベンダーは現在、x86 バージョンと x64 バージョンの両方の DLL の提供を開始しており、私のアプリは 64 ビット プロセスとして実行することでメリットが得られると思います。この 1 つの DLL を除いて、すべてが .NET コードであるため、「任意の CPU」としてビルドできます。

ネイティブ DLL のすべてのメソッド シグネチャは 64 ビットでも同じですが、DLL の名前が異なります (Foo.dll と Foo_x64.dll)。P/Invoke シグネチャまたは app.config エントリを使用して、実行中の CPU アーキテクチャに基づいてロードする DLL を選択する方法はありますか?

異なる DLL 名ではなく、異なるフォルダーで同じ名前だった場合、他のオプションが開きますか?

注: このユーザー空間 DLL のバージョンがハードウェア用にインストールされたカーネル ドライバーと一致することが不可欠であるため、DLL はアプリにバンドルされていませんが、代わりに、ベンダーのインストーラーに依存して %道%。

4

3 に答える 3

14

「別の 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 自体がネイティブ ライブラリをロードしようとする前に、フル パスを使用してネイティブ ライブラリを明示的にロードする必要があります。

どう思いますか?

于 2009-12-08T13:46:52.533 に答える
4

単一の PInvoke 署名を使用して、必要な動作を取得する方法はありません。属性はメタデータに焼き付けられ、定数値を持つ必要があります。ただし、できるハックの 1 つは、複数のメソッドを用意することです。

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 ライブラリが採用するアプローチです。

于 2009-10-15T17:13:57.193 に答える
1

ターゲット用に特別なライブラリを開発しました: InteropDotNetRuntimeDllImport動的ライブラリ パス解決 (オンザフライ) を使用して新しい属性を導入します。デフォルトの方法では、次のように書くことができます

[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
于 2014-07-24T12:39:23.067 に答える