x64/x86に応じてC# DllImportターゲットコードを変更する 質問する

x64/x86に応じてC# DllImportターゲットコードを変更する 質問する

DLLImport を使用してインポートする外部 C++ DLL があります。アプリケーションが x64 でコンパイルされている場合は、この DLL の x64 バージョンをインポートする必要があり、x86 ビルドの場合は、x86 DLL が必要です。

これを達成するための最善の方法は何でしょうか?

理想的には、プリプロセッサ ディレクティブが欲しいのですが、これは C# では機能しないのでしょうか?

詳細: DLL は、AnyCPU に設定されているプロジェクトによってインポートされています。親プロジェクトは、アプリケーションが x64 としてコンパイルされるか、x86 としてコンパイルされるかを決定するプロジェクトです。私たちは、異なる顧客向けに両方のバージョンをコンパイルしており、両方のバージョンで子プロジェクトを共有したいと考えています。

ベストアンサー1

これは主に展開の問題であり、インストーラーでターゲット マシンの Windows バージョンに基づいて適切な DLL をコピーするだけです。

しかし、誰もそれを好みません。正しい DLL の関数を動的にピン呼び出しするのは非常に面倒で、エクスポートされた関数ごとにデリゲート型を記述し、LoadLibrary + GetProcAddress + Marshal.GetDelegateForFunctionPointer を使用してデリゲート オブジェクトを作成する必要があります。

しかし、誰もそんなことはしたくありません。もっと楽な方法は、関数を 2 回宣言して異なる名前を付け、[DllImport] 属性の EntryPoint プロパティを使用して実際の名前を指定することです。次に、実行時にどちらを呼び出すかをテストします。

しかし、誰もそんなことはしたくありません。最も効果的な方法は、Windows に正しい DLL をロードさせるようにすることです。まず最初に、Windows が検索しないディレクトリに DLL をコピーする必要があります。最善の方法は、ビルド ディレクトリに「x86」および「x64」サブディレクトリを作成し、それぞれに適切な DLL をコピーすることです。これを行うには、ディレクトリを作成して DLL をコピーするビルド後のイベントを記述します。

次に、SetDllDirectory() を呼び出して Windows に通知します。指定したパスは、Windows が DLL を検索するディレクトリに追加されます。次のようになります。

using System;
using System.Runtime.InteropServices;
using System.Reflection;
using System.IO;

class Program {
    static void Main(string[] args) {
        var path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
        path = Path.Combine(path, IntPtr.Size == 8 ? "x64" : "x86");
        bool ok = SetDllDirectory(path);
        if (!ok) throw new System.ComponentModel.Win32Exception();
        //etc..
    }
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool SetDllDirectory(string path);
}

コードを 64 ビット モードで実行することが実際に役立つかどうかを検討してください。64 ビット モードで得られる巨大な仮想メモリ アドレス空間が必要になることはほとんどなく、これが唯一の本当のメリットです。2 ギガバイトのケースで正しく動作する必要がある 32 ビット バージョンもサポートする必要があります。

おすすめ記事