メモ帳の切れ端

備忘録的な何かです。

WinAPI不定期小話 『第1話. 怖くない! WinMain』

Windowsアプリケーションを開発するときに欠かせない, WinAPIのMain関数, WinMainについて説明します.

1. WinMainとは

WinMainとは, Windowsアプリケーションを作成するときに必要なやつです. Windowsアプリケーションでは,

int main(){
    return 0;
}
int WINAPI WinMain(Arg...){
    /*なんか処理を行う*/
    return 0;
}

2. Conclusion

結論から先に書いておくと, 使うべき関数は_tWinMainで、こいつの引数はほぼ要らないよ! っていう話です. 後述しますが, これらの引数はここで保存しなくても必要になったら取得できるのでマジで要らないんです.

3. WinMainを詳しく見る

そもそもWinMain関数ですが, WinMain, wWinMain, _tWinMainの3種類があります.

int WINAPI WinMain(
  HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
int WINAPI wWinMain(
    HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR pCmdLine, int nCmdShow);
#include<tchar.h>
int WINAPI _tWinMain(
    HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow);

さて, こちらの3つの関数ですが, まず違いが分かるでしょうか? そう!! 第3引数が違いますね! LPSTRLPWSTRLPTSTRの3種類があることが分かります. ではこれらの違いは何でしょうね. また, 他の意味の分からない引数も一体何なのでしょうね. あと, 引数名ですが, そもそも言ってしまえば引数名とかどうでもいいんですが, 大体みんなこんな感じの名前を付けるのでそれに倣ってこんな感じの命名で進めていきます.

3-1. 第1引数 hInstance

まずこのHINSTANCE型は一体何でしょうか. これはHandle of Instance, インスタンスのハンドルです. は? 何言ってんだ意味分かんねぇんだけど? ってなると思います. これは雑に説明してしまうと、各アプリケーションに割り当てられた番号の値が保持されていて, つまりこの数字を参照することによって各アプリケーションを参照することが出来るのです. ところで, この値はGetModuleHandle(nullptr);関数を使う事によって取得できたりするんですよ. だからこの値保持する必要ないんですよね.

結論: 第1引数 hInstanceは要らない

3-2. 第2引数 hPrevInstance

これなんですけど, Windowsアプリケーションにおいて常にNULLです. 要りません. 結論: 第2数 hPrevInstanceは要らない

3-3. 第3引数

さて, ここで問題の第3引数です. こいつのやってること自体は簡単で, コマンドライン引数を取得しているだけなんです. ちなみにこの値もGetCommandLine();関数で取得できるんですよね. まぁちょっと得られる値が微妙に違うんですけど大体同じです. じゃあ保持しなくていいですよね. そもそもLPSTRLPWSTRLPTSTRの意味なんですけど, それぞれLong PointerのSTRとWSTRとTSTRです. Longってのは"歴史的に"以前より長い(大きい)バイト長ってだけで, Pointerはポインター, STRはStringの意味で, C++ではchar型のことを指しています. つまり, それぞれ

LPSTR;    //Long Pointer to STRing. char型のポインター
LPWSTR;    //Long Pointer to WSTRing. wchar型のポインター
LPTSTR;    //Long Pointer to TSTRing. tchar型のポインター

となります. じゃあcharとかwcharとかtcharってなんやねんってなりますよね. ここら辺は難しい文字コードの話なんですが, 早い話がcharってのが普通のやつで, wcharはワイド文字ってやつでtcharってのは環境によってcharwcharのどちらかに変化する万能君です. つまり, tcharを使うのがいいぞって話です. つまり, LPTSTRを使っている_tWinMainが一番賢いWinMainとなります.

結論: 要らないけどtcharが一番賢いのでLPTSTR, つまり_tWinMainを使おう

3-4. 第4引数 nCmdShow

これだけがちょっとクセモノです. この値はShowWindowっていうウィンドウの表示方法, フルスクリーンとか通常モードとか最小化とかそういう関数の引数として使います。ここだけは唯一保持しておいて同じ値を上記の関数の引数に使用しなければいけないんですが、大体の場合SW_SHOWか, ラッパしていたらSW_SHOWDEFAULTが値として入っていると思うので、それを直接指定してもオーケーです.

結論: 時々使うかもしれないんだけど、基本的に要らない

4. 終わりに

WinAPIはとても複雑なので,WinMain関数を語るだけでもこれだけかかってしまいました. しかし普通に使う分にはそこまで考える必要はありませんので, 結果的には_tWinMainをほとんどの引数を無視して使えばいいわけです. こう言ってしまうとプロに怒られてしまうかもしれませんが, もっと軽い気持ちでいろんな人にWindowsのネイティブ開発をしてもらいたいものです.次回以降ではウィンドウの作成のお話しをしたいと思います. お楽しみに~