gcc -nostartfiles その4
gcc で -nostartfiles オプションを有効にすると、できあがりの実行ファイルサイズが小さくなる代わりに、処理の流れが変化する。すなわち、コード中で最初に定義した関数がエントリポイントとなる。
どうしよう?
#include <windows.h> void hello() { MessageBox(NULL, TEXT("Hello, world!"), TEXT(""), MB_OK); } int WINAPI WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR cl, int cs) { MessageBox(NULL, TEXT("I am in WinMain"), TEXT(""), MB_OK); return 0; }
先頭に関数 hello を定義し、続いて関数 WinMain を定義する。このコードをコンパイル&リンクしてできた実行ファイルを起動すると、関数 hello が呼ばれ、WinMain は呼ばれないことが確認できる。
よくしよう
これでは、正常なアプリケーション動作にならないので、コードを変更し、手動で WinMain を呼ぶようにする。
#include <windows.h> void Main() { int exitcode = WinMain(0, 0, "", 0); ExitProcess(exitcode); } int hello() { MessageBox(NULL, TEXT("Hello, world!"), TEXT(""), MB_OK); return 0; } int WINAPI WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR cl, int cs) { MessageBox(NULL, TEXT("I am in WinMain"), TEXT(""), MB_OK); return 0; }
関数 Main をコードの先頭に追加する。これによって、エントリポイントは Main になる。このソースコード hello.c を gcc -mwindows -nostartfiles hello.c
でコンパイル&リンクして実行すると、画面上に「I am in WinMain」というメッセージがポップアップする。
I am in WinMain
このメッセージボックスを閉じると、アプリケーションが終了する。
よくなった
新しいエントリポイント関数 Main では、以下の処理を行っている。
- 関数 WinMain を実行する。引数として、とりあえずダミーの値を渡す。
- 関数 WinMain の戻り値を変数 exitcode に保存する。
- 関数 ExitProcess を実行する。引数として、変数 exitcode を渡す。
ひとまず、これで、一般的な Windows アプリケーションの処理の流れをシミュレートすることができた。WinMain には、ダミーの値を渡しているが、WinMain 内で、それらの値を本物と見なして使用することがなければ、問題ない。
アプリケーションの終了は、ExitProcess で行っている。通常、標準スタートアップファイルがこの手の API を自動で叩いてくれるようなのだが、-nostartfiles を適用すると行われないため、手動で叩いている。