gcc -nostartfiles 完全版
gcc で C ソースコードをコンパイル&リンクするとき -nostartfiles をつけると、標準スタートアップファイルがリンクされないため、実行ファイルサイズが非常に小さくなる。実行ファイルサイズを小さくしたいときは、この方法を採用するといい。
この方法で実行ファイルを作成すると、一応 Windows アプリケーションとしては動作する。しかしながら、エントリポイントが、常に WinMain 関数になるのではなく、なぜか、コードの先頭に定義した関数になる。
その上、アプリケーションを終了するには、概ね必ず ExitProcess 関数を呼ぶ必要がある。
エントリポイントとなる先頭の関数内では、WinMain 呼び出しと WinMain が終了した際の ExitProcess 呼び出しのみを行うようにすると便利だ。そうすれば、通常通り、標準スタートアップファイルをリンクして実行ファイルを作成した場合でも、同等の振る舞いをするアプリケーションができ上がるからである。
おすすめ
#include <windows.h> void Main() { HINSTANCE hi; HINSTANCE hp; LPSTR cl; STARTUPINFO sui; int cs; int exitcode; GetStartupInfo(&sui); hi = GetModuleHandle(NULL); hp = 0; cl = (LPSTR)__argv; cs = sui.wShowWindow; exitcode = WinMain(hi, hp, cl, cs); ExitProcess(exitcode); } int WINAPI WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR cl, int cs) { HWND hwnd = CreateWindow(TEXT("BUTTON"), TEXT("BOTAN"), WS_SYSMENU, 0, 0, 320, 240, 0, 0, hi, 0); ShowWindow(hwnd, cs); MessageBoxA(NULL, cl, TEXT(""), MB_OK); return 0; }
あとがき
エントリポイントとなる先頭の関数内で、WinMain を呼び出すときは、4 つの引数を渡す必要がある。
- 第一引数には GetModuleHandle(NULL) を渡す
- 第二引数には 0 を渡す
- 第三引数には __argv を渡す
第四引数について
そして、第四引数には、STARTUPINFO 構造体のメンバ wShowWindow を渡す。このメンバの値と、本来の WinMain 第四引数の値は全く同じである。すなわち、ウィンドウを作成し、表示するアプリケーションにおいて、その表示方法を指定する値が入っている。
実際的には、アプリケーションのショートカットを作成し、そのプロパティの項目「実行時の大きさ」を変更して起動したときに効果が表れる。
以下の 2 つの条件を満たしているアプリケーションは、実行時のウィンドウの大きさについて、ユーザーの指定通りにふるまう良いアプリケーションである。
- 「最大化」に変更されていれば、起動時、最大化したウィンドウで表示する
- 「最小化」に変更されていれば、起動時、最小化したウィンドウで表示する
この 2 つの条件を満たすために、WinMain の第四引数こと wShowWindow を利用する。
CreateWindow でウィンドウを作成する際には、第三引数に、ウィンドウのスタイル値を渡さなければならないが、そこに WS_VISIBLE が含まれない場合、ウィンドウを表示するには ShowWindow 関数を実行する必要がある。ShowWindow の第一引数に、メインとしたいウィンドウのウィンドウハンドルを渡した場合、の第二引数には、WinMain の第四引数こと wShowWindow を渡すべきである。そうすることで、先述 2 つの条件を満たすことができる。
ちなみに、CreateWindow の第三引数に WS_VISIBLE が含まれている場合は、ShowWindow するまでもなく、ウィンドウが表示されるが、その際、ウィンドウの大きさは、自動的に wShowWindow の値に伸縮する。
エンディング
gcc -nostartfiles を使うと、実行ファイルサイズが小さくなるが、標準スタートアップファイルがリンクされないため、コードのふるまいが変わる。標準スタートアップファイルは、具体的にどんな処理をしているのかを把握していないため、どうしてそのようなふるまいになるのかが不明である。とりあえず、謎のエントリポイント関数でオリジナルのスタートアップルーチンをシミュレートすることで、特に大きなエラーもないアプリケーションを生成することはできているが、背後でまずいことになっている可能性もある。