gcc -nostartfiles その3
何もしないはずのソースコード hello.c を 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) { return 0; }
どうして、メッセージボックスが表示されるのだろうか。
-nostartfiles を使うと、定義してあるだけの関数が自動で実行されるという、奇妙な挙動になるのだろうか。このことについて、実験を行ってみよう。
どうなる?
コードを編集する。
- 関数 hello のあとに、関数 bye を定義する
- 関数 WinMain でメッセージボックスを表示する処理を追加する
#include <windows.h> void hello() { MessageBox(NULL, TEXT("Hello, world!"), TEXT(""), MB_OK); } void bye() { MessageBox(NULL, TEXT("BYE!!"), 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; }
そして、gcc -mwindows -nostartfiles hello.c -o hello.exe
でコンパイル&リンク後、実行する。
こうなる
すると、以下のような振る舞いとなる。
- まず、改変前のコードと同じように「Hello, world!」メッセージボックスが表示される。
- そのメッセージボックスを閉じると、それ以上は何も表示されない。
- hello.exe はバックグラウンドで生き残っている。
この結果からして、-nostartfiles は、定義してある全ての関数を自動で実行するわけではなく、最初に定義された関数のみを実行するようだ。さらには、なんと、WinMain が実行されていないことも判明した。
どうして?
-nostartfiles によって、標準スタートアップファイルのリンクを行わないようにすると、どうやら、本来のエントリポイントである関数 WinMain がそうでなくなり、先頭に定義した関数 hello がエントリポイントになる。
また、メッセージボックスを閉じることで、すべての処理が終了しても、アプリケーションそのものが終了しない原因は、どうやら、プロセスを終了するための関数 ExitProcess が実行されていないからである。ExitProcess は、通常、スタートアップルーチンが行うものなのだ。