読者です 読者をやめる 読者になる 読者になる

はじめてのWin32 プロジェクト


このエントリーをはてなブックマークに追加

Microsoft Visual C++ 2010 Express で、Win32 プロジェクトを選んだときに用意されるスケルトンについて、調べたことをメモとしてまとめておく。

main関数

以下のコードが自動生成される。

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

 	// TODO: ここにコードを挿入してください。
	MSG msg;
	HACCEL hAccelTable;

	// グローバル文字列を初期化しています。
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_WIN32_PROJECT, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// アプリケーションの初期化を実行します:
	if (!InitInstance (hInstance, nCmdShow))
	{
		return FALSE;
	}

	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32_PROJECT));

	// メイン メッセージ ループ:
	while (GetMessage(&msg, NULL, 0, 0))
	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	return (int) msg.wParam;
}

順番に見ていく。

エントリポイント
int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)

Windowsプログラミングではmain関数の代わりに_tWinMain関数がエントリポイントとなる。
APIENTRY は、WinDef.h にて

#define APIENTRY    WINAPI
#define WINAPI      __stdcall

と定義されている。__stdcallとは、WIN32 APIの呼び出し規約のうちの1つ。引数をスタックに積む順番や、スタックに積まれた引数の後始末の方法などを決めている。他の規約には __cdecl と __fastcall がある(あまりよく分かっていない)。以下のサイトが参考になる。

_tWinMain についている _t は、このWinMain関数がTCHAR型に対応していることを表す。TCHAR型は、UNICODE版でも非UNICODE版でも同一のコードでコンパイルを可能にするために用意された便利な型。TCHAR型に関しては
http://www.ruche-home.net/?%A5%D7%A5%ED%A5%B0%A5%E9%A5%DF%A5%F3%A5%B0%2F%BE%AE%A5%CD%A5%BF%BD%B8%2FUnicode%C2%D0%B1%FE%A5%B3%A1%BC%A5%C7%A5%A3%A5%F3%A5%B0
が参考になる。教科書によっては _tWinMain関数ではなく WinMain関数で解説してあることもある。この場合は、例えばLPSTR型をLPTSTR型に読み換えたり、文字列"String"を_T("String")またはTEXT("String")に読み換えたりする必要があるので注意。

次に、_tWinMain関数の引数を見ていく。

  • HINSTANCE hInstance
    • アプリケーションの現在のインスタンスハンドル。このプログラムをユニークに識別するためのもの。
  • HINSTANCE hPrevInstance
    • 現在のWindowsでは常にNULL。
  • LPTSTR lpCmdLine
    • プログラムの起動時に使われたコマンド行。LPTSTR型は、LP(Long Pointer) + T(TCHAR) + STR(文字列)と分解して考えれば分かりやすい。
  • int nCmdShow
    • プログラムを実行したときのウィンドウの表示状態。例えば、通常のウィンドウで開始する SW_SHOWNORMAL や、最大化で開始する SW_SHOWMAXIMIZED などの値が格納されている。これらの値は、exeのショートカットのプロパティを開いたときにある「実行時の大きさ」を指定したときなどに渡すことができる。
UNREFERENCED_PARAMETERマクロ
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);

は、WinNT.hで次のように定義されたマクロ。

#define UNREFERENCED_PARAMETER(P)          (P)

実質、何もしていない。これは、未使用の変数があったときにコンパイラから警告されるのを防ぐためのもの。試しに、コンパイラの警告レベルを Level3 (/W3) から 最高レベルのEnableAllWarnings (/Wall) に引き上げ、これらのマクロをコメントアウトしてコンパイルを試みると、" 'lpCmdLine' : 引数は関数の本体部で 1 度も参照されません。"などという警告が出されるようになる。

LoadStringマクロ
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);

この関数は、変数szTitleで確保された領域に、ID IDS_APP_TITLEで指定される文字列をコピーする。コピーされる文字列は、自動的に作られる.rcファイル内のSTRINGTABLEにて自動的に定義されている。

残りの MyRegisterClass(hInstance), InitInstance (hInstance, nCmdShow), メッセージループについては次回。

参考文献は、本文で示したリンク、および以下の本。