.NET の DLL は AnyCPU でビルドすることで、32bit / 64bit どちらの環境でも同じファイルを使い回せます。
しかし、P/Invoke(Platform Invocation Services) を使ってネイティブ DLL を呼び出す場合は、そう簡単にはいきません。
今回は「なぜネイティブ DLL を 32bit / 64bit 両方用意しなければならないのか?」を詳しく解説します。
1. AnyCPU の仕組みをおさらい
-
.NET の DLL(マネージド DLL)は、中間言語(IL)で保存されます。
-
実行時に JIT コンパイラが、実行環境に合わせて 32bit ネイティブコード または 64bit ネイティブコード に変換します。
つまり AnyCPU DLL は自動的に「実行中のプロセスのビット数」に追従して動作するのです。
2. P/Invoke で起こる問題
P/Invoke を使うと、C# や VB.NET のマネージドコードから C/C++ で書かれた ネイティブ DLL を呼び出せます。
例:
このとき、.NET ランタイムは 現在のプロセスのビット数と同じアーキテクチャの DLL をロードしようとします。
-
プロセスが 32bit →
NativeLib.dll
は 32bit DLL でなければならない -
プロセスが 64bit →
NativeLib.dll
は 64bit DLL でなければならない
もし 32bit プロセスから 64bit DLL を読み込もうとすると、「不正なフォーマットです(BadImageFormatException)」 というエラーが発生します。
3. 具体例で考える
例えば、あなたが「数学演算ライブラリ」を作り、C# から C++ の関数を呼び出したいとします。
ネイティブ DLL 側(C++)
これを 32bit 用(x86) と 64bit 用(x64) にそれぞれビルドします。
-
NativeLib32.dll
-
NativeLib64.dll
マネージド DLL 側(C#、AnyCPU)
この DLL を AnyCPU
でビルドすると:
-
32bit アプリから呼ばれると、.NET ランタイムは「32bit DLL を探す」
-
64bit アプリから呼ばれると、.NET ランタイムは「64bit DLL を探す」
つまり ネイティブ DLL を両方用意しなければならないということです。
4. 実運用での対応方法
方法1:DLL を分けて配置する
-
x86\NativeLib.dll
-
x64\NativeLib.dll
アプリの起動時に環境を判定し、DllImport
のパスを切り替える。
方法2:同じ名前でシステムフォルダに配置する
Windows では、32bit と 64bit の DLL をそれぞれ専用のフォルダに置く仕組みがあります。
-
C:\Windows\System32
→ 64bit DLL -
C:\Windows\SysWOW64
→ 32bit DLL
同じ名前の DLL を置いても、プロセスのビット数に応じて自動で切り替わります。
方法3:ランタイムで動的にロードする
LoadLibrary
や NativeLibrary.Load
を使い、実行時に 32bit/64bit を判定して適切な DLL を明示的にロードする。
まとめ
-
AnyCPU DLL は「マネージドコード」部分だけなら両対応可能
-
しかし P/Invoke で呼ぶ「ネイティブ DLL」はプロセスのビット数に合わせたものが必要
-
つまり、実際の運用では ネイティブ DLL を 32bit / 64bit 両方用意して、状況に応じてロードさせる工夫が必要