今回はメッセージクラッカーについて取り扱います
メッセージクラッカーはメッセージを横取りするという意味です
メッセージクラッカーを使うことでメッセージの処理がやりやすくなります
次のウィンドウプロシージャをメッセージクラッカーで書きなおします
//-----------------------------------------------------// // ウィンドウプロシージャ // デフォルトの処理はDefWindowProc関数で行う // // 引数: hWnd ウィンドウハンドル // msg メッセージ // wParam パラメータ // lParam パラメータ // // 戻り値:処理結果 //-----------------------------------------------------// LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){ switch(msg){ case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, msg, wParam, lParam); }
メッセージクラッカーを使って書きなおすと次のようになります
//------------------------------------------------------// // ウィンドウ破棄メッセージ処理 // // 引数: hWnd ウィンドウハンドル //------------------------------------------------------// void OnDestroy(HWND hWnd){ PostQuitMessage(0); } //-----------------------------------------------------// // ウィンドウプロシージャ // デフォルトの処理はDefWindowProc関数で行う // // 引数: hWnd ウィンドウハンドル // msg メッセージ // wParam パラメータ // lParam パラメータ // // 戻り値:処理結果 //-----------------------------------------------------// LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){ switch(msg){ HANDLE_MSG(hWnd,WM_DESTROY,OnDestroy); } return DefWindowProc(hWnd, msg, wParam, lParam); }
ここで
HANDLE_MSGというのがメッセージクラッカーと呼ばれるマクロです
使い方は
HANDLE_MSG(ウィンドウハンドル、メッセージの種類、メッセージを処理する関数)
のように使います
windowsx.hヘッダーに次のように定義されています
#define HANDLE_MSG(hwnd, message, fn) \ case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))
ここで
\は改行されていても一行として認識するために付けてあります
##というマクロはmessageの名前を連結します
つまり、
HANDLE_MSG(hWnd,WM_DESTROY,OnDestroy);
は
case (WM_DESTROY): return HANDLE_WM_DESTROY((hWnd), (wParam), (lParam), (OnDestroy));
のように展開されます
さらに、
編集→検索と置換→クイック検索
もしくはCTRL+Fでwindowsx.hを次のように検索してください
HANDLE_WM_DESTROYはwindowsx.hに次のように定義されています
/* void Cls_OnDestroy(HWND hwnd) */ #define HANDLE_WM_DESTROY(hwnd, wParam, lParam, fn) \ ((fn)(hwnd), 0L)
それをさらに展開したのが最終的な展開結果です
case WM_DESTROY:return ((OnDestroy)(hWnd),0);
HANDLE_WM_DESTROYのように
他のメッセージも同様に「HANDLE_なんとか」とwindowsx.h内に定義がされています
ここで話がそれますが
((OnDestroy)(hWnd),0)
はどうゆう意味でしょうか
「,」はカンマ演算子とよばれ
a = (x, y, z);
とやるとx,y,zと順番に評価され
aには、zが代入されます
つまり、ここでの場合はOnDestroy関数が評価(実行)され、ウィンドウプロシージャの戻り値に0が返ります
では、メッセージクラッカーを使うためにはメッセージごとに
どのような関数を用意してやればいいでしょうか?
答えは
/* void Cls_OnDestroy(HWND hwnd) */
に書いてあるような
引数と戻り値を持つ関数を用意してやればよいことになります
つまり、WM_DESTROYに対しては
void OnDestroy(HWND hWnd)
という関数を用意しました
つまり、基本的にコメントアウトに書いてある関数を作成し
その関数を渡せば、メッセージクラッカーを使うことができます
このようにメッセージクラッカーを使うときは逆引き的に調べます
メッセージクラッカーを使う利点は
メッセージごとに処理をわけることができるので
ウィンドウプロシージャに長々メッセージ処理のコードを書かずに済むという利点があります
また、メッセージのパラメータがメッセージごとに適切な型で明記されているので
メッセージ処理がしやすいという利点があります
全ソースコードは下から
main.cpp