FAQ7-1

Q. Windowsのプログラムのmain()はどこにあるの

 C言語の教科書には,Cのプログラムはmainから始まると書かれていますが,WindowsのCプログラムはWinMainではじまり,mainではありません.どうでしてなのでしょうか.


A. 引数が違うからです.

 Windowsのプログラムがmain()でなくWinMain()なのは,まず第一に引数が違うからです.
 main()には,コマンドラインを意味するargc,argvといった引数があります.ところが,Windowsのプログラムは,インスタンスハンドル,コマンドライン,ウィンドウの表示状態をいった引数を持っているため,main()とは違ったインターフェースになっているものと思われます.
 また,MS-DOSのプログラムや16ビットのWindowsプログラムでは,プログラムが読み込まれたときに最初に実行される関数はmain()やWinMain()ではありません.
 実は_astart()というCのランタイムライブラリに含まれている関数(スタートアップコード)なのです.
 MS-DOSの場合,MS-DOS用のライブラリの中の_astart()がmain()を呼んでいるのでmain()が呼ばれることになっており,Windows用のライブラリをリンクした場合は,_astart()がWinMain()を呼んでいるのでWinMain()が呼ばれることになっているのです.

Cのランタイムライブラリ

 では,Cのランタイム関数を使わなくてもCのランタイムライブラリをリンクしなければいけないのかというと,そういうわけではありません.
 普段はslibcew.libとかをリンクしていたものの代わりにsnocrtw.libといったスタートップコードだけ(だけではないかもしれないけど)のライブラリがあるので,それをリンクすればできるみたいです.

32ビットでは

 ちなみに32ビットのプログラムでは,またまた別の呼ばれ方をしています.
 32ビットのリンカーでは,エントリポイント(最初に実行される関数)を自由に指定できるようになっていて,なにも指定しなければ,EXEの場合,WinMainCRTStartup()という関数が呼ばれるようになっています.
 そのWinMainCRTStartup()は16ビットの_astart()と同様にライブラリの中に含まれていて,WinMainCRTStartup()の中でWinMain()を呼ぶしくみになっています.
 WinMainCRTStartup()は,WinMain()と同じ呼び出し規約&同じ引数になっているので,リンカーでエントリポイントの名前を「WinMain」にしてやれば,ライブラリをリンクする必要はなくなります.
 そのかわりCのランタイムの初期化やC++のコンストラクタが正常に動かなくなるかもしれません.
 エントリポイントとメイン関数の対応表を表7-1に示します.


[表7-1]
OS エントリポイント メイン関数
DOS _astart main
Win16(EXE) _astart WinMain
Win16(DLL) _astart LibMain
Win32(コンソール) mainCRTStartup main
Win32(EXE) WinMainCRTStartup WinMain
Win32(DLL) _DllMainCRTStartup DllMain



Back to FAQ main page