Win32API プログラミング第二回>メッセージの処理

前回、「窓を開く」プログラムを作りました。ウインドウクラスを「登録」して、そのウインドウクラスに基づいてウインドウを作る。その後作ったウインドウを表示・更新する、という流れを見てみましたが、あの後プログラムは

  while (GetMessage (&msg,NULL,0,0)) { /* メッセージループ */

      TranslateMessage(&msg);
      DispatchMessage(&msg);

  }

というループに入りましたね。このループはメッセージループと呼ばれ、Windowsのシステムから送られてきたメッセージを、メッセージ処理用の関数に送る処理を行っています。
 メッセージ処理の関数は、ウインドウクラス内で

wndclass.lpfnWndProc = WndProc; /* メッセージ処理関数 */

として設定した関数です。このように、プログラムからではなく、 システムの方から呼ばれる関数はコールバック関数と呼ばれます。

メッセージ処理の流れ

メッセージとは、あるイベントが起こった事を知らせるために、システムから実行中のプログラム(ウインドウやスレッド)に送られるものです。通知されるイベントは、マウスボタンがクリックされたりマウスカーソルが動いたり、キーボードのキーが押されたり、ウインドウの×ボタンが押されて閉じられようとしたり、とさまざまですがメッセージループはこのメッセージを受け取って、メッセージ処理関数に渡すループなのです(ただし、 メッセージの中にはメッセージループを通さずに、直接メッセージ処理関数に送られるものもあります)。
GetMessageは、文字どおりメッセージを得るための関数で、この関数は一度呼び出されるとメッセージが来るまで待ち続けます。さらに、この関数はWM_QUIT を受け取ると0を返すので、WM_QUITメッセージが送られてくるとプログラムも終了するようになっています(C では数値を論理型とみなす場合0だと偽でそれ以外は真でしたね)。ループ内のTranslateMessageはキーボード関連のイベントを翻訳し、DispatchMessageはメッセージをWindowsシステムに転送する関数です。メッセージがDispatch されると、Windowsはそのメッセージとメッセージのパラメータを引数としてメッセージ処理関数を呼び出す、という流れになっています。
このように、Windows プログラミングは基本的にはメッセージへの応答、という形で処理を書く事になるので、送られてくるメッセージの種類や、パラメータの詳しい意味についても調べてみると良いでしょう。

  LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {

      switch (iMsg) {

          case WM_DESTROY : /* 終了処理 */

              PostQuitMessage(0);
              return 0;

      }

      return DefWindowProc (hwnd, iMsg, wParam, lParam) ;

  }

メッセージ処理関数は、上のように送られてきたメッセージが何のメッセージかを調べ、メッセージに応じて処理します。 ただし、自分で処理しないメッセージは、そのままDefWindowProcに渡せばWindows の方で処理してくれますので、 すべてのメッセージを処理する必要はありません。wParamlParamはメッセージのパラメータで、メッセージに関連した情報(例えばマウス関連メッセージの場合なら、マウスカーソルの座標など)が入っています。
今回処理するメッセージは一つだけ。×ボタンをクリックするなどして、ウインドウが閉じられようとしている時に送られるWM_DESTROYメッセージです。このメッセージを受け取ると、PostQuitMessageWM_QUITメッセージをWindows に送ります(このように、メッセージは受け取るだけでなく自分の方から送る事も可能)。このメッセージを送ると、GetMessageが0を返してメッセージループが終了し、プログラム自体も終了するわけです。なお、メッセージ処理の関数は、自分でメッセージを処理した時には0を、DefWindowProc に渡した時はその戻り値を返すようにします。

これで「窓を開く」プログラム全体をざっと見渡しました。次回からは少しづつ具体的な処理をしてみましょう。

・プログラム(前回と同じ)
=======================================================================
#include <windows.h>

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow){

	HWND hwnd;
	MSG  msg;
	WNDCLASSEX  wndclass ;

	wndclass.cbSize        = sizeof(wndclass);        /* 構造体の大きさ */
	wndclass.style         = CS_HREDRAW | CS_VREDRAW; /* スタイル */
	wndclass.lpfnWndProc   = WndProc;                 /* メッセージ処理関数 */
	wndclass.cbClsExtra    = 0;
	wndclass.cbWndExtra    = 0;
	wndclass.hInstance     = hInstance;               /* プログラムのハンドル */
	wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION); /* アイコン */
	wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);     /* カーソル */
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); /* ブラシ */
	wndclass.lpszMenuName  = NULL;              /* メニュー */
	wndclass.lpszClassName = "Test Window";   /* クラス名 */
	wndclass.hIconSm       = LoadIcon (NULL, IDI_APPLICATION);

	RegisterClassEx (&wndclass); /* ウインドウクラスTest Windowを登録 */

	hwnd = CreateWindow (
           "Test Window",        /* ウインドウクラス名 */
	   "窓を開く",           /* ウインドウのタイトル */
            WS_OVERLAPPEDWINDOW, /* ウインドウスタイル */
            32,32,               /* ウインドウ表示位置 */
            256,256,             /* ウインドウの大きさ */
            NULL,                /* 親ウインドウのハンドル */
            NULL,                /* メニューのハンドル */
            hInstance,           /* インスタンスのハンドル */
            NULL);               /* 作成時の引数保存用ポインタ */

	ShowWindow (hwnd,iCmdShow);      /* ウインドウを表示 */
	UpdateWindow (hwnd);

	while (GetMessage (&msg,NULL,0,0)) { /* メッセージループ */

		TranslateMessage(&msg);
		DispatchMessage(&msg);

	}

	return msg.wParam ;

}

LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {

	switch (iMsg) {

		case WM_DESTROY : /* 終了処理 */

			PostQuitMessage(0);
			return 0;

	}

	return DefWindowProc (hwnd, iMsg, wParam, lParam) ;

}
=======================================================================

プログラムソース表示

VC++でビルドしてみましょう。


プログラミング資料庫 > Windowsプログラミング研究室