19

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

これを達成するための最良の方法は何ですか?

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

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

4

2 に答える 2

28

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

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

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

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

次に、SetDllDirectory() を pinvoking して 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 ビット モードで実行することが実際に役立つかどうかを検討してください。そこから得られる巨大な仮想メモリ アドレス空間が必要になることはほとんどありません。これが唯一の真の利点です。2 ギガバイトのケースで正しく動作する必要がある 32 ビット バージョンをサポートする必要があります。

于 2012-08-13T14:13:45.980 に答える
5

x86 と x86_64 の両方の DLL インポートを別の名前で追加すると、Environment.Is64BitProcess (または < .Net 4 を使用している場合は IntPtr.size) の値を確認することで、実行時のアーキテクチャに応じて条件付きでそれらを呼び出すことができます。これは、プロジェクトが x86、x86_64、または AnyCPU としてビルドされているかどうかに関係なく機能します。

または、x86 のみを実行するビルド構成と x86_64 のみを実行するビルド構成の 2 つの異なるビルド構成をセットアップし、それぞれに条件付きコンパイル シンボルを指定し、カスタム シンボルで #ifdef を使用します。

于 2012-08-13T12:52:15.273 に答える