gcc -nostartfiles その6
gcc の -nostartfiles オプションを有効にしてコンパイル&リンクすると、ファイルサイズが小さくなるかわりに、エントリポイントが、先頭に定義した関数にすりかわる。そこで、その関数で WinMain を呼ぶことにより、スタンダードな C ソースコードの流れをシミュレートする。
#include <windows.h> void Main() { HINSTANCE hi = GetModuleHandle(NULL); HINSTANCE hp = 0; LPSTR cl = __argv; int exitcode = WinMain(hi, hp, cl, 0); ExitProcess(exitcode); } int WINAPI WinMain(HINSTANCE hi, HINSTANCE hp, LPSTR cl, int cs) { MessageBox(NULL, TEXT("I am in WinMain"), TEXT(""), MB_OK); return 0; }
第一引数
第一引数には、GetModuleHandle(NULL) で取得できるインスタンスハンドルを渡す。
第二引数
第二引数にも、HINSTANCE 型の値を指定する必要があるが、この値は、16 ビットのアプリケーションでのみ使用される。現代で一般的な 32 ビットおよび 64 ビットアプリケーションでは不要であり、かつ、本来の WinMain においても、0 が入っているので、0 でよい。
第三引数
第三引数には、本来の WinMain では、コマンドライン引数の文字列が入っている。たとえば、上記の hello.c をコンパイル&リンクし、実行ファイル hello.exe を作成したとする。そして、hello.exe を hello a b c
というふうに、引数をつけて起動すると、"a b c" という文字列が入る。
むずかしい方法
GetCommandLine() で "hello a b c" を得ることはできるが、そこから "a b c" だけを抜き出すことは困難である。もっとも簡単そうな方法は、CommandLineToArgvW(GetCommandLineW(), (int)cmdlen) などとして、"hello" と "a" と "b" と "c" に分解された配列を得たのち、lstrcat を用いて、添え字 1 以後すべてを半角空白でつなげて、"a b c" を組み立てるというものだが、これで得られる "a b c" は LPWSTR である。WinMain の第三引数の型は LPSTR であるため、渡すことができない。
また、ワイド文字列からマルチバイト文字列に変換する wcstombs という関数があり、これを使って、LPWSTR の "a b c" を LPSTR "a b c" に変換することができればよいのだが、非常に大がかりな処理をしなければならないだろう。
かんたんな方法
一方で、__argv
というビルトイン変数を使う方法がある。__argv
には、本来の WinMain 第三引数に渡る文字列と同等の文字列が入っている。gcc コンパイラからの警告を出されないために、この変数を LPSTR 型にキャストするか、LPSTR 型の変数にアドレスを代入するかして、WinMain の第三引数に渡すとよい。