2012-08-13 13 views
14

可能性の重複:
preprocessor directive…C#変更C#DLLIMPORTターゲットコードのx64に応じて/ x86の

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

これを達成する最も良い方法は何ですか?

理想的には、私はいくつかのプリプロセッサディレクティブを望んでいますが、これはCで動作しないことを理解していますか?

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

+0

両方のバージョン(プライベートメソッド)をインポートしますが、環境に応じて正しいコードをクライアントコードに公開するのはどうですか? .NET 4では、[Environment.Is64BitOperatingSystem](http://msdn.microsoft。com/ja-us/library/system.environment.is64bitoperatingsystem.aspx)。注意:私は依存するネイティブDLLのために2つの異なるバージョンのC#アプリケーションを保持しません(このためにプリプロセッサは使用しません)。 –

+0

マイケル - それはほとんど私の質問ですが、私は彼らの解決策が動作しないことを意味する1つの余分な合併症があります。私のdllはanycpuであるプロジェクトによってインポートされ、親プロジェクトはアプリケーションがx64かx86かどうかを判断します。 – Sugrue

+0

@Sugrue次にランタイムソリューションを使う必要があります。両方をインポートし、 'Environment.Is64BitProcess'か' sizeof (void *) '、または' IntPtr.Size'です。 –

答えて

22

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

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

しかし、誰もこれをやりたいとは思っていません。あまり厄介なことは、関数を2回宣言し、異なる名前を付け、[DllImport]属性のEntryPointプロパティを使って実名を指定することです。次に実行時に呼び出すテストを行います。

しかし、誰もこれをやりたいとは思っていません。最も効果的なやり方は、正しいDLLをロードするためのWindowsの操作です。まず、DLLがWindowsがそれを探していないディレクトリにコピーする必要があります。最も良い方法は、ビルドディレクトリに "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ビットモードで実行するコードを実際に使用することを検討してください。唯一の本当のメリットである巨大な仮想メモリアドレス空間を必要とすることは非常にまれです。 2ギガバイトの場合でも正しく動作する必要のある32ビットバージョンをサポートする必要があります。

+0

良い解決策。 PhonicUKとMichael Graczykも良いソリューションを持っていますが、これには繰り返しコードは含まれていません。 – Sugrue

+1

個人的には、いつも私にとって気難しいDLL検索パスを変更するのではなく、フルパスを渡す 'LoadLibrary'への明示的な呼び出しを好みます。基本的な考え方はもちろん同じです。 –

+0

LoadLibraryは2番目の段落の対象です。悪いアイデア。 –

5

異なる名前のx86とx86_64 DLLのインポートを両方追加すると、実行時にEnvironment.Is64BitProcess(または、< .Netを使用している場合はIntPtr.size)の値をチェックして、 4)。これは、プロジェクトがx86、x86_64、またはAnyCPUとしてビルドされているかどうかにかかわらず動作します

また、x86とx86_64の2つの異なるビルド構成を設定し、それぞれに条件付きコンパイルシンボルを与え、カスタムシンボルの#ifdef。

+0

私はOPが '#ifdef'を使う方法を知らないと思うので、あなたは彼のための簡単なコード例を提供できますか、おそらくライブラリをロードするコード例もありますか?しかし、例がなくても+1を与えました。 –

+0

'Environment.Is64BitProcess'本当に感謝しました – LuckyLikey

関連する問題