-
Notifications
You must be signed in to change notification settings - Fork 0
MS_Support64bit
- 戻る(各種、技術毎の移行性、Windows OSの基礎的トピック)
- 64bit対応
- WOW64
- マネージドコードとアンマネージドコードのブリッジ
本ページでは、64bit プラットフォーム移行に伴うアプリケーションの
環境移行、ポーティング移行の作業範囲を扱います。
-
WOW64は、64bit プラットフォーム上で Win32 アプリケーションを
実行する、エミュレーションレイヤー・サブシステム。 - 64bit 版システムファイルを納めた
\System32ディレクトリに対応する形で
32bit 版ファイルを格納した\SysWOW64ディレクトリのコンポーネントを
利用して動作する。 - これにより、32bit アプリケーションはそのまま
64bit プラットフォーム上でも動作する。
補足(紛らわしい命名):
System32が 64bit、
SysWOW64が 32bit である。
直感に反するが、これは「既存の 32bit アプリがSystem32という
パス文字列をハードコードしている」ことへの互換性配慮による。
32bit プロセスからC:\Windows\System32を開くと
自動的にSysWOW64にリダイレクトされる
(ファイル システム リダイレクト)。
リダイレクトを避けたい場合はC:\Windows\Sysnativeという
疑似パスを使う。
- 構造
- WOW64 ホストプロセスによって予約された 4GB の仮想空間に
32bit ABI のコードを読み込み、 - そこで発生した Win64 API に変換可能な API 呼び出しを変換して、
Win64 サブシステムに伝達する。 - 構造体の変換は自動的に行われ、Win32 側では現在動作している OS が
32bit システムか、64bit システムかを意識する必要は全くない。 - ユーザーモードで動作するコンポーネント群は 32bit 版と 64bit 版が用意され、
例えば OLE などは 32bit で閉じた範囲で動作できる。 - 64bit 版で提供されるコードは単一のソースから、
32bit 版と 64bit 版両方をそれぞれコンパイルして作られているため、
機能的差異は無い。
- WOW64 ホストプロセスによって予約された 4GB の仮想空間に
以下に、WOW64を使用する際の注意点を記述する。
-
32(64)bit の ABI から 64(32)bit の ABI を呼べないので
どちらかに揃える。
WOW64では 32bit の ABI に揃える(ABI:実行ファイルやライブラリ)。 -
デバイスドライバ類は WOW64を利用できないので
64bit に対応した物を準備する。 -
レジストリ リダイレクトおよびレジストリ リフレクション、
ファイル システムのリダイレクトの機能がある。 -
ファイルや変数への参照が原因で、問題が発生する場合がある。
(システム変数、環境変数、KNOWNFOLDERID 値、および
Sysnativeエイリアスを含むファイル システム パス フォーム) -
その他、WOW64の制限事項
- アドレス空間は既定で 2.0GB である。
- 16bit プロセスの実行はサポートされない。
- 仮想 DOS マシン(VDM)API は無効化される。
- AWE(Address Windowing Extensions)、スキャッター/ギャザー I/O、
書き込み追跡など、ページサイズに依存する API は、IPF 上では利用できない。 - PAE(Physical Address Extension)は、IPF 上では利用できない。
- DirectX、ハードウェア アクセラレータ API は、IPF 上ではサポートされない。
※ IPF:Itanium Processor Family -
COMを経由した 32bit ABI のコードと 64bit ABI のコードとの
相互な呼び出しが禁止されている。
移行メモ(最新化): 上記のうち Itanium(IPF)に関する制限は
現在は無関係である。Itanium は 2021年に完全に終息し、
Windows Server 2008 R2 が最後の対応 OS であった。
現在「64bit Windows」といえば x64(AMD64) か Arm64 を指す。なお Arm64 Windows では、WOW64 に加えて
- x86 エミュレーション(32bit x86 アプリを実行)
- x64 エミュレーション(Windows 11 以降)
- ARM64EC(x64 と Arm64 のコードを 1 プロセスで混在させる ABI)
という仕組みがあり、「ビット数」に加えて「命令セット」も
考慮が必要になっている。
補足(「相互に呼べない」の要点): 太字にした 「32bit プロセスと 64bit プロセスは、同一プロセス内で混在できない」
が本ページ全体の核である。
- 64bit の EXE は 64bit の DLL / COM しかロードできない。
- 32bit の EXE は 32bit の DLL / COM しかロードできない。
- 跨ぎたい場合はプロセスを分ける(
LocalServer32の COM、
別 EXE + IPC、WCF / 名前付きパイプ)。「32bit の古い COM を使っているので、アプリ全体を 32bit のままにする」
という判断は、この制約から来る。
IISのワーカプロセス(ASP や ASP.NETなどの
Web アプリケーションがホストされる)も 32bit(WOW64)を
サポートする。
補足(現在の設定箇所): IISでは
アプリケーション プールの詳細設定にある
「32 ビット アプリケーションの有効化」(enable32BitAppOnWin64)で
切り替える。
True… そのプールのw3wp.exeが 32bit で起動するFalse(既定)… 64bit で起動する32bit の COMや ODBC ドライバに依存する古いアプリを
動かす際の定番設定である。
同一サーバ上で 32bit と 64bit のアプリを別プールにすれば共存できる
(IIS 6.0 ではできなかった)。
IIS Express を 64bit で動作させることも可能。
- Visual Studioのメニューから[ツール]-[オプション]を開く
- [プロジェクトおよびソリューション]-[Web プロジェクト]を開く
- [Web サイトおよびプロジェクト用 IIS Express の 64 ビットバージョンを使用]の
チェックを ON にする
なお、レガシー ASP は、32bit(WOW64)もサポートする。
ただし、殆どの場合は、使用する COMが「32bit の VB COM」で
開発されているので、WOW64上で 32bit アプリケーションとして
動作させることとなる。
最も大きな問題は 32bit、64bit 間のデータモデルの変更である。
今日では、多くの 64bit コンパイラが LP64 モデルを採用している
(Solaris、AIX、macOS、z/OS のネイティブコンパイラなど)が、
マイクロソフトの VC++コンパイラは LLP64 モデルを
採用している。
-
LP64 モデルの欠点
long型データをint型変数に代入するときに
オーバーフローが発生する可能性がある点である。 -
LLP64 モデルの欠点
ポインタをlong型に cast できないためlong long型
(VC++ コンパイラではINT64、__int64、LONGLONG)を
使用する必要がある点である。
64bit データモデル
| データモデル | short | int | long | long long | ポインタ | 処理系 |
|---|---|---|---|---|---|---|
| LLP64 | 16 | 32 | 32 | 64 | 64 | Microsoft Win64 (x64/IA64) |
| LP64 | 16 | 32 | 64 | 64 | 64 | ほとんどの Unix と Unix 風 OS (Solaris, Linux, etc.) |
| IP64 | 16 | 64 | 32 | 64 | 64 | ? |
| ILP64 | 16 | 64 | 64 | 64 | 64 | HAL |
| SILP64 | 64 | 64 | 64 | 64 | 64 | ? |
補足(これが移植の最大の落とし穴): Windows だけ
longが 32bit
という点が、Linux/Unix との間でコードを行き来させる際の
最も大きな非互換である。long p = (long)ptr; /* Linux では通るが、Windows x64 では切り捨てられる */移植性を確保するには、
ポインタを整数に入れるならintptr_t/uintptr_t、
サイズが要るならsize_t、
明示的な幅ならint64_tを使う(<stdint.h>)。
Windows API ではINT_PTR/LONG_PTR/DWORD_PTRが
同じ役割を担う。
-
必要に応じて 64bit 用 VC++コンパイラを追加インストール、
構成マネージャから 64bit 用のプラットフォームを新規作成することで
64bit COMを作成可能。
ポインタをlong型に cast するようなコードが無ければ
ストレート移行が可能である。 -
また、
regsvr32する際に、(恐らく PE ヘッダを参照することで、)
自動的に「COM の生成情報」の登録先であるレジストリを標準(64bit 用)とするか、
WOW64(32bit 用)とするかの切り替えが為される。
そして、COM を生成するときは、呼出元プロセスが 64bit or 32bit によって
参照先レジストリが切り替えられるため、
適切な COM(64bit or 32bit)を生成することができる。 -
このため、ADODB などのミドルウェアも、64bit サポートがされていれば、
64bit or 32bit(WOW64)の双方のプロセスから利用できる
(余談:WSHのWScript.exe・CScript.exeも
64bit 用、32bit 用の双方が用意されている)。 -
また、.NET では Any CPU のコンパイルが可能なので、
64bit・32bit を意識しないこともありますが、
アンマネージコードと連携する場合は .NET の呼出元プロセスが
64bit or 32bit のどちらで動作しているか注意が必要です。
移行メモ(正誤): 元ページの
Regsrv32は、
正しくはregsvr32である(sとvの順序)。
.NET、ASP.NET
以下、.NET のアプリケーションの 64bit 対応のポイントについて説明する。
100%タイプ セーフなマネージ コードであれば、そのまま移行可能。
- 100%タイプ セーフとは?
- DLL(platform)呼び出し、COM呼び出しをしていないこと。
-
/clr:safeオプションでコンパイルされており、
低レベルな処理の実行が許可されていないこと。- ポインタの宣言と処理
- ポインタと整数型の変換
- 変数のアドレス取得
100%タイプ セーフでない場合は、Windows の 64bit プラットフォームが
LLP64 モデルであることを意識してコードを書きなおす必要がある。
-
IntPtr.Sizeを使用してプラットフォームを識別可能。 -
ポインタを受け取る場合は、
IntPtr型を使用する。 -
Marshalクラスを用いてデータのマーシャリングを行う場合は、
メモリの境界整列(アライメント)を考慮する必要がある。-
LayoutKind.Sequentialを使用する場合はStructLayoutAttribute.Pack -
LayoutKind.Explicitを使用する場合はFieldOffsetAttribute
-
-
BinaryFormatterクラスを使用したバイナリ・シリアライズは、
IntPtrを保存して 32bit ⇔ 64bit プロセス間を跨ぐ場合にのみ問題を起こす。 -
32bit の COMは、
tlbimp.exeを使用して 64bit 用の RCW を
生成することで、WOW64でホストされる
32bit アウトプロセスを呼び出し可能。- 64bit 用の RCW を生成する:
tlbimp.exe foo.dll /machine:x64 /out:Interop.Foo.dll - 32bit の COM を登録する:
regsvr32.exe foo.dll - コンパイル オプションを x64 に変更して RCW を参照設定。
- 64bit 用の RCW を生成する:
-
C#のアンセーフコード、C++/CLI は
問題が起こらないか見直しが必要になる。
移行メモ(正誤): 元ページのコマンド例は
tlbim.exeと
綴られスペースも欠けていたが、正しくは
tlbimp.exe foo.dll /machine:x64 /out:Interop.Foo.dllである。
補足(アウトプロセス COM の前提): 「32bit COM を 64bit プロセスから
呼べる」のは、その COM がLocalServer32(アウトプロセス)である場合に
限られる。InprocServer32(DLL)の 32bit COM は、
どうやっても 64bit プロセスにロードできない
(COMの項を参照)。インプロセス COM を跨ぎたい場合は、COM+ アプリケーションとして
アウトプロセス化する(サロゲートdllhost.exeを使う)という
迂回策がある。
- コンパイル オプション(構成の target platform)を Any CPU か、
x64 に変更する。 - .NET Framework 2.0 以降からのサポート。
.NET Framework 1.0、1.1 は WOW64上で実行する。 - アセンブリに指定されているコンパイル オプションを調査する方法
→ILDASM.exeの[表示]→[ヘッダー]で
COFF Header の Machine Type を確認する。
-
VS2010:EXE を作るプロジェクトのデフォルトが Any CPU から x86 に変更。
理由は、- アーキテクチャ中立の Any CPU EXE は通常、
価値よりもトラブルのほうが多くコスト高。 - 32bit はいずれにしろより速い傾向がある。
- いくつかの機能が 64bit では利用できない。
- アーキテクチャ中立の Any CPU EXE は通常、
-
VS2012 以降:再び、デフォルトは Any CPU に戻っている。
補足(現在の既定と "Prefer 32-bit"): 現在の
.NET Core 以降では、
種別 既定 dotnetCLI / SDK スタイルAny CPU( PlatformTarget未指定)発行時( dotnet publish -r win-x64)RID で明示 となっており、実行時のビット数はどのランタイムで動かすかで決まる。
なお .NET Framework 時代の
「32 ビットを優先する(Prefer 32-bit)」 チェックは、
Any CPU なのに 32bit で動くという紛らわしい挙動を生む。
「Any CPU にしたのに 64bit にならない」という相談の多くは
これが原因なので、移行時には必ず確認したい
(.NET Core 以降にはこの設定は無い)。
-
WOW64 - Wikipedia
https://ja.wikipedia.org/wiki/WOW64 -
WOW64 のベスト プラクティス(要点)
-
@IT:Win32アプリケーションを実行するWOW64
http://www.atmarkit.co.jp/fwin2k/special/win64_02/win64_02_01.html
-
Visual C++ による 64 ビット プログラミング | Microsoft Learn
https://learn.microsoft.com/cpp/build/configuring-programs-for-64-bit-visual-cpp -
x64 ソフトウェア規約
https://learn.microsoft.com/cpp/build/x64-software-conventions -
64 ビット アプリケーション | Microsoft Learn
https://learn.microsoft.com/dotnet/framework/64-bit-apps
Tags: 移行, プログラミング, .NET開発, Windows
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。