では引き続き、Part 2. のエントリでは、.NET Framework 2.0 のアプリケーションがどのようにして 64 ビット(または 32 ビット)で動作するのか、についてみていくことにします。.NET Framework では、IL (中間言語)と呼ばれるものが利用されているため、x86, x64, IA64 すべてに対応する .exe ファイルや .dll ファイルを作成することができます。にもかかわらず、Visual Studio を開くと、
……と、こんなスイッチがあるわけなのですが、いったいこれは何なのか? これを理解するためには、.NET Framework のコンパイル動作を正しく把握する必要があります。これについて以下の手順で解説していくことにします。
[Step 7. IL コードとネイティブコード]
.NET Framework の開発言語である C# や VB で書いたコードは、コンパイルしてもすぐに x86 や x64 などの命令コード(ネイティブコード)には変換されません。
このため、.NET で書かれた .exe ファイルや .dll ファイルは、x86 Windows OS 上で動作させれば 32 ビット動作し、x64 Windows OS 上で動作させれば 64 ビット動作します。つまり、ひとつのファイルで、32 / 64 ビット両方の動作をさせることができるようになっています。
[Step 8. コンソールアプリケーションにおけるコンパイルスイッチの意味]
一般に、アプリケーションプログラムが MSIL のみで記述されている、つまり完全に .NET コードのみで記述されている場合には、上記のような動作は全く問題がありません。しかし、この .NET のアプリケーションが周辺のライブラリファイルなどを利用している場合には、問題が生じることがあります。
例えば、.NET のコンソールアプリケーションが Access .mdb ファイルにアクセスするために内部で Jet OLE DB プロバイダを使っている場合を考えてみましょう。実は、Jet OLE DB プロバイダは 64 ビット版ドライバが提供されていません。このため、.NET アプリケーションが 64 ビット動作してしまうと、ドライバが見つからずにエラーが発生する、という現象が起こります。
となると、このようなコンソールアプリケーションは、x64 Windows OS 上であっても 64 ビット動作されては困る、ということになります。このような場合に利用するのが、最初に示したプラットフォームスイッチです。Visual Studio 2008 のツールバーには、下図に示すようなプラットフォームスイッチがあります。
ここから構成マネージャを開き、アクティブソリューションプラットフォームを追加していくと、CPU 名を追加していくことができます。
64 ビット版 Windows OS でも、32 ビット版の Jet OLE DB プロバイダであれば同梱されています。このため、先の Jet OLE DB プロバイダを使うアプリケーションの場合には、このスイッチとして "x86" を指定しておき、32 ビットコードに変換されるようにしておかないと、64 ビット OS 上で正しく動作させることができなくなります。
ここで留意していただきたいのは、このプラットフォームスイッチはアセンブリファイルに出力される MSIL コードそのものを変えるものではない、という点です。このプラットフォームスイッチで変更されるのは PE ヘッダ情報内のフラグである、という点に注意してください。
ですので、プラットフォームスイッチを変えなければならないのは、以下のようなケースに限られます。
x86 オプションをつけないと危険なものについては、Migrating 32-bit Managed Code to 64-bit などの資料に取りまとめられていますので、こちらについても参照してみるとよいでしょう。
ちなみにこのような理由から、32 ビットマシンや 32 ビット OS を使っている場合であっても、64 ビット C# アプリケーションのコンパイルができます。なぜなら、単にヘッダ情報を "x64" として MSIL コードを出力するだけだからです。(もちろん、出力された .exe ファイルは 32 ビット OS 上では動作しませんが。)
[Step 9. ライブラリアプリケーションにおけるコンパイルスイッチの意味]
上記の解説を踏まえれば、ライブラリアプリケーション(dll ファイル)におけるスイッチの意味についても明らかです。このスイッチは、要するにどのようなプロセスからこの dll ファイルを利用してよいのか、を規定するものになります。
例えば、下図のように Jet OLE DB プロバイダを利用するクラスライブラリ(dll ファイル)をコンパイルする場合には、"x86" オプションをつけておくべきです。なぜなら、64 ビットプロセスがこの dll ファイルを呼び出しても、正しく動作することができないからです。
当たり前のことですが、.dll ファイルは、プロセスからロードされて利用されるライブラリです。なので、クラスライブラリ側に、プロセスの動作モード(32 ビット/64 ビット)を切り替える権利や機能はありません。最初に .exe ファイルを起動した時点で、プロセスの動作モード(32 or 64 ビット)はすでに決定しており、そこから呼び出せるかどうかが .dll ファイルのスイッチにより決定されます。以下に、.exe ファイルと .dll ファイルのスイッチの組み合わせ例を示しますので、じっくり見てみてください。
[Step. 10] 動作モードやヘッダフラグの確認方法
なお、アプリケーションの内部から、現在自分が 64 ビット/32 ビットどちらで動作しているのかを知る一番簡単な方法は、IntPtr.Size プロパティをチェックするというものです。
この方法では、x64, IA-64 の区別はつきませんが、通常はこれで十分でしょう。(どうしてもそこまで切り分けたい場合には、GetSystemInfo() Win32 API を利用します。)
また、PE ヘッダの確認を行う場合には、Windows SDK に含まれる CorFlags.exe ツールを利用します。これを利用すると、Any CPU, x86, x64/Itanuim などのいずれのヘッダを持つのかを比較的簡単に見分けることができます。(この中の PE, 32BIT フラグに着目します。こちらの方法も x64, Itanium を見分けられないのがちょっと残念な感じですが;)
C:\>corflags "C:\Documents and Settings\nakama\My Documents\Visual Studio 2005\P
rojects\ConsoleApplication1\ClassLibrary1\bin\x86\Debug\ClassLibrary1.dll"
Microsoft (R) .NET Framework CorFlags Conversion Tool. Version 2.0.50727.42
Copyright (c) Microsoft Corporation. All rights reserved.
Version : v2.0.50727
CLR Header: 2.5
PE : PE32
CorFlags : 3
ILONLY : 1
32BIT : 1
Signed : 0
[ここまでのまとめ]
では、今回のエントリのポイントの復習です。
と、長々と書きましたが、要点をまとめるとたったひとつです。
「特定プラットフォームでしか動作しないモジュールを作る場合には、必ず x86, x64 などのオプションをつけてコンパイルすること」
この一点だけをちゃんと守ってもらえれば OK です。
……がしかし、IIS 上で動作する ASP.NET アプリケーションの場合はちょっと話が複雑になります。これについては次回のエントリにて^^。