メッセージ
メッセージループ
これまでは、ウィンドウの出現に対して
メッセージボックスを出現させてプログラムを一時停止させてきました
この章では、ユーザーの要求でアプリケーションを終了できるように説明します
今回は、Windowsのイベント駆動に関する基本的な知識を身につけましょう
Win32 では、ウィンドウの処理に メッセージ と呼ばれる物を使います
メッセージは、ユーザーがウィンドウに対して要求した内容を格納しています
メッセージはキューとして格納されています
これを メッセージキュー と呼び、アプリケーションはキューからメッセージを取り出します
メッセージの管理は MSG 構造体型変数で行います
この構造体は、WINUSRE.H で次のように定義されています
typedef struct tagMSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG , * PMSG;
実際には少し違ったりするので、直接ヘッダファイルを調べても良いでしょう
ここで、WPARAM と LPARAM という型が出てきました
これは、メッセージのやり取りに使う専用の 32ビット 型です //WPARAMは Win16 で16ビット
hwnd には、メッセージを受け取る関数を持つウィンドウのハンドルが入ります
メッセージを受け取る関数とは、前回も触れた「ウィンドウプロシージャ」です
message は、メッセージを識別する整数が入ります
wParam と lParam は、メッセージの付加情報が入る場所で
意味や内容はメッセージによって様々です
time は、メッセージがポストされた時間
pt は、メッセージがポストされた時のカーソル位置を格納します
POINT 型は構造体型で、WINDEF.H で定義されています
typedef struct tagPOINT {
LONG x;
LONG y;
} POINT;
x と y には、二次元空間の x と y 座標を表す数値が格納されます
メッセージキューからメッセージを受け取るには GetMessage() 関数を使用します
この関数は、指定されたMSG構造体変数にメッセージを格納します
BOOL GetMessage(LPMSG lpMsg , HWND hWnd , UINT wMsgFilterMin , UINT wMsgFilterMax);
第一引数の LPMSG 型 は、MSG構造体のポインタ型です
lpMsg に、MSG構造体変数のポインタを渡します
hWnd には、メッセージを受け取るウィンドウのハンドルを渡します
アプリケーションで表示している全てのウィンドウから受け取る場合はNULL を指定します
wMsgFilterMin は、受け取るメッセージの最小値
wMsgFilterMax は、受け取るメッセージの最大値を指定することで
受け取るメッセージのフィルタリングを行います
フィルタリングを行わない場合は、第三、第四引数は 0 を指定します
戻り値は、通常は 0 以外の値 TRUE を返します
WM_QUIT というメッセージを受け取った時のみ FALSE を返します
エラーが発生した時は - 1 を返すので、エラーチェックの時のみ数値で確認してください
WM_QUIT は、アプリケーションの終了動作に関係しているのですが
このメッセージについては、後ほどウィンドウプロシージャの時に詳しく説明します
Windows から、常にメッセージを受け取るためには
GetMessage() 関数で繰り返しメッセージを受け取る必要があります
そのため、ウィンドウの生成後にメッセージを受け取るためのメッセージループを生成します
ループ内で、受け取ったーメッセージをチェックし
指定したメッセージであれば、ループを抜け出しプログラムを終了するようにしましょう
ここでは、マウスの左ボタンをアップした時のメッセージ WM_LBUTTONUPを使います
ただし、メッセージを使用するのは私たちだけではありません
その他の最低限の動作を保証するために、ウィンドウプロシージャにも渡さなくてはならないのです
そのためには DispatchMessage() 関数を用います
LONG DispatchMessage(CONST MSG *lpmsg);
lpmsg には GetMessage() で受け取ったメッセージを格納した
MSG 構造体変数のポインタを渡します
この関数は、ウィンドウプロシージャにメッセージを送出(ディスパッチ)します
戻り値はウィンドウプロシージャの戻り値が返りますが、一般的に無視します
#include<windows.h>
int WINAPI WinMain(
HINSTANCE hInstance ,
HINSTANCE hPrevInstance ,
PSTR lpCmdLine ,
int nCmdShow ) {
HWND hwnd;
MSG msg;
hwnd = CreateWindow(
TEXT("BUTTON") , TEXT("Kitty on your lap") ,
WS_CAPTION | WS_VISIBLE ,
100 , 100 , 200 , 200 , NULL , NULL ,
hInstance , NULL
);
if (hwnd == NULL) return 0;
while (TRUE) {
GetMessage(&msg , NULL , 0 , 0);
if (msg.message == WM_LBUTTONUP) break;
DispatchMessage(&msg);
}
return 0;
}
上のプログラムはウィンドウクラスに "BUTTON" を指定しています
システム定義の "STATIC" では、入力を受けつけないからです
もちろん、ウィンドウクラスはあなたが定義して登録したものでもかまいません
MSG 構造体でメッセージが格納されているメンバは message でした
このプログラムでは、WinMain() 関数内で直接それをチェックしています
メッセージが WM_LBUTTONUP であれば
つまり、マウスの左ボタンがアップされればループを抜け出します
メッセージは通常は、このようにキューにポストされる
しかし、ポストせずに直接ウィンドウプロシージャに送られるメッセージもあります
因みに、上のプログラムは ShowWindow() 関数を使用していません
代わりに CreateWindow() 関数のスタイル指定で、WS_VISIBLE を指定しています
このスタイルは、可視状態のウィンドウを作成するスタイルです
GetMessage()
BOOL GetMessage(LPMSG lpMsg , HWND hWnd , UINT wMsgFilterMin , UINT wMsgFilterMax);
指定された MSG 構造体型変数にメッセージを格納します
lpMsg - メッセージ情報を格納する、MSG 構造体型変数のポインタを指定します
hWnd - メッセージを取得するウィンドウのハンドルを指定します。全ての場合は NULL
wMsgFilterMin - メッセージの最小値を指定し、フィルタリングします。しない場合は0
wMsgFilterMax - メッセージの最大値を指定し、フィルタリングします。しない場合は0
戻り値 - WM_QUIT を受け取った時は 0、そうでないなら 0 以外、エラーの時は -1 を返します
DispatchMessage()
LONG DispatchMessage(CONST MSG *lpmsg);
指定されたメッセージをウィンドウプロシージャにディスパッチします
lpmsg - ディスパッチするメッセージを格納した MSG 構造体変数のポインタを指定します
戻り値 - ウィンドウプロシージャの戻り値が返ります