【Delphi】Windows 32bit アプリケーションに 2GB を超える仮想メモリ空間を割り当てる

# はじめに
窓の杜でこのような記事が出ていました。

https://forest.watch.impress.co.jp/docs/news/1503384.html

今回の問題は「**Large Address Aware** 対応 32bit アプリケーションが Windows 10 / 11 環境 (WOW64) で実行されている時に **CopyFile()** に失敗する事がある」というものです。

# Large Address Aware
Large Address Aware が有効な 32bit Windows では各ユーザープロセスに 2GB を超える仮想アドレス空間が割り当てられるようになり、WOW64 環境 (64bit Windows) では各ユーザープロセスに 4GB の仮想アドレス空間が割り当てられるようになります。

| Windows | 仮想アドレス空間 |
|:---|:---:|
| Large Address Aware が有効でない 32bit Windows | 2GB |
| Large Address Aware が有効な 32bit Windows | &lt; 3GB |
| 64bit Windows (WOW64) | 4GB |

ユーザープロセスに 2GB を超える仮想アドレス空間が割り当てられている場合、32bit アプリケーションの PE ヘッダフラグに **IMAGE_FILE_LARGE_ADDRESS_AWARE** 立っていると、2GB を超えるメモリを扱う事ができます。

アプリケーションを Large Address Aware 対応にしたいのであれば、<font color="Crimson">Integer によるポインタ操作をしていない事が条件</font>です。ポインタを Integer でキャストしている場合には正常動作しない可能性があります。


**See also:**

 - [4 GB のチューニング: BCDEdit と Boot.ini (learn.microsoft.com)](https://learn.microsoft.com/ja-jp/windows/win32/memory/4-gigabyte-tuning)
 - [Windows で 3 GB スイッチを有効にする方法 (Autodesk)](https://www.autodesk.co.jp/support/technical/article/caas/sfdcarticles/sfdcarticles/JPN/How-to-enable-a-3GB-switch-on-Windows-Vista-Windows-7-or-Windows-XP-s.html)
 - [4-Gigabyte Tuning (Wikipedia: en)](https://ja.wikipedia.org/wiki/4-Gigabyte_Tuning)
 - [2 GB limit (Wikipedia: en)](https://en.wikipedia.org/wiki/2_GB_limit)
 - [/LARGEADDRESSAWARE (大きいアドレスの処理) (learn.microsoft.com)](https://learn.microsoft.com/ja-jp/cpp/build/reference/largeaddressaware-handle-large-addresses?view=msvc-170)

## Delphi アプリケーションを Large Address Aware 対応にするには？

### 1.プロジェクトオプションで追加する
プロジェクトオプションの `［PE ヘッダーの追加フラグを設定］`に値を指定します。IMAGE_FILE_LARGE_ADDRESS_AWARE は 0x0020 (32) です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/98d2d0e9-47d6-af76-e84d-ebdfa4644995.png)
`［PE ヘッダーの追加のオプションフラグを設定］`という似たような設定があるので間違えないように注意してください。

:::note warn
0 以外の値がセットされていたら **or** する必要があります。
:::

**See also:**

 - [［リンク］(DocWiki)](https://docwiki.embarcadero.com/RADStudio/Alexandria/ja/%EF%BC%BB%E3%83%AA%E3%83%B3%E3%82%AF%EF%BC%BD)

### 2.コンパイラ指令 {$SetPEFlags} で追加する
コンパイラ指令 `{$SetPEFlags}` で追加する事もできます。プロジェクトファイルに記述します。

```pascal
uses
  .., Winapi.Windows;

  ...

{$SetPEFlags IMAGE_FILE_LARGE_ADDRESS_AWARE}
```

`{$SetPEFlags}` コンパイラ指令は Delphi 7 以降で使えますが、定数が `Winapi.Windows.pas` (または `Windows.pas`) に定義されていない場合があります。その際には値 ($0020) で指定するか、以下の定義を行ってください。

```pascal
 IMAGE_FILE_LARGE_ADDRESS_AWARE = $0020;
```

:::note
{$SetPEFlags} は複数回記述できます。つまり、値を OR する必要はありません。
:::

**See also:**

 - [PE（portable executable）ヘッダー フラグ（Delphi）(DocWiki)](https://docwiki.embarcadero.com/RADStudio/Alexandria/ja/PE%EF%BC%88portable_executable%EF%BC%89%E3%83%98%E3%83%83%E3%83%80%E3%83%BC_%E3%83%95%E3%83%A9%E3%82%B0%EF%BC%88Delphi%EF%BC%89)

## アプリケーションが Large Address Aware 対応かどうか調べるには？

[dumpbin.exe？](https://docs.microsoft.com/ja-jp/cpp/build/reference/dumpbin-reference?view=vs-2019) Delphi (や C++Builder) をインストールした環境なら、`<インストールフォルダ>\bin` に **TDUMP.EXE** と **GREP.EXE** があるので、これらを使います。
```
tdump -e ファイル名 | grep "^Flags"
```

`ファイル名` に調べたい実行ファイル (*.exe) を指定します。実行すると、次のような結果が得られます。

```txt
STDIN
Flags                    122 [ executable linenumbers symbols largeaddr backwards 32bit ]
```

フラグに `largeaddr` が含まれていれば Large Address Aware 対応アプリケーションです。

**See also:**

 - [TDUMP.EXE (DocWiki)](http://docwiki.embarcadero.com/RADStudio/ja/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB_%E3%83%80%E3%83%B3%E3%83%97_%E3%83%A6%E3%83%BC%E3%83%86%E3%82%A3%E3%83%AA%E3%83%86%E3%82%A3%EF%BC%9A_TDUMP.EXE)

# おわりに

今回の問題は「**Large Address Aware** 対応アプリケーションで CopyFile() に失敗する事があるよ！」というものでした。アプリケーションが Large Address Aware 対応でなかったり、64bit EXE なのであれば影響を受けません。

IMAGE_FILE_LARGE_ADDRESS_AWARE フラグはデフォルトで無効となっているので、特に問題になる事はないでしょう。

そういえば Delphi の IDE 自体は [10 Seattle 以降で Large Address Aware 対応](https://docwiki.embarcadero.com/RADStudio/Alexandria/ja/Seattle_%E3%81%AE%E6%96%B0%E6%A9%9F%E8%83%BD#.E3.83.A1.E3.83.A2.E3.83.AA.E3.81.AB.E9.96.A2.E3.81.99.E3.82.8B.E6.94.B9.E5.96.84)になっているのですが、こちらの方は影響を受けなかったのでしょうか？

**See also:**

 - [32bit アプリを 64bit Windows 7 で動かす「WOW64」(ASCII)](https://ascii.jp/elem/000/000/480/480200/)
 - [第2回　Win32 アプリケーションを実行する WOW64」(@IT)](https://atmarkit.itmedia.co.jp/ait/articles/1007/01/news131.html)