Version 8.10
コマンドと通知メッセージ
「前回は、ボタンを押したらダイアログを閉じるようにしました」
『ボタン押したときのメッセージを受け取って、 EndDialog() で閉じるん
だよね。そう考えると簡単かも』
「それは簡単に考えてるから」
『どゆこと?』
「ダイアログのメッセージを受け取るダイアログプロシージャ。同じよう
に、ウィンドウはすべて、ウィンドウプロシージャを持ってます」
『ダイアログプロシージャはウィンドウプロシージャの一種なんだもんね』
「そうそう、だからダイアログもウィンドウプロシージャを持ってるって言
えるし、それにウィンドウは全部持ってるわけだから、たとえばボタンも」
『ウィンドウプロシージャを持ってるんだ』
「……不思議に思わない?」
『何が?』
「ボタンを押したときのメッセージって、ボタンが受け取るけど」
『あ! ってことはボタンのウィンドウプロシージャが受け取って、それっ
てダイアログのダイアログプロシージャが受け取らない……けど受け取って
るね』
「そう、この辺の仕組みをちゃんと把握しておくのが大事かな。まず、実際
にマウスを左クリックしたとかってメッセージについて」
『マウスを動かしたら WM_MOUSEMOVE みたいな?』
「そう、そんな感じのメッセージ。マウスの左クリック、ってメッセージは
なくて、左ボタンを押したときのメッセージとして WM_LBUTTONDOWN ってい
うのがあります」
『ほー、下げるのと上げるのとで別なのね。上げるのは WM_LBUTTONUP なん
だ』
「ボタンが押されたとかは、実際にはマウスの左ボタンが上がった時だか
ら」
『ボタン的には、 WM_LBUTTONUP がボタンが押されたって印なわけね』
「このメッセージについては、実際に Spy++ でボタンのメッセージを見て
いくと分かるから、一度してみて」
『 Spy++ については Version 5.28 ( No.093 ) を参照〜』
「というわけで、実際に〈ボタンで左クリックした〉ってメッセージはボタ
ンのウィンドウプロシージャが受け取ってます」
『つまりダイアログプロシージャが受け取ってないから、他の方法で受け取
らなきゃいけないわけね』
「そゆこと。そのための方法は3つあります」
『ひとつは、前回の WM_COMMAND ね』
「もう一度ダイアログプロシージャだけ見てみようか」
// ダイアログプロシージャ。
BOOL CALLBACK DialogProc
( HWND p_hDlgWnd
, UINT p_uiMessage
, WPARAM p_wParam
, LPARAM p_lParam
)
{
if( p_uiMessage == WM_COMMAND )
{
if( LOWORD( p_wParam ) == IDOK )
{
// OK ボタンが押されました。
EndDialog( p_hDlgWnd, IDOK );
return TRUE;
}
else if( LOWORD( p_wParam ) == IDCANCEL )
{
// キャンセルボタンが押されました。
EndDialog( p_hDlgWnd, IDCANCEL );
return TRUE;
}
}
return FALSE;
}
『ボタンが押されると WM_COMMAND ってメッセージが送られてきて、その
WPARAM の LOWORD に押されたボタンの ID が入ってるわけね』
「この WM_COMMAND は、ボタンを押したときだけじゃなく、メニューが選択
されたときや、アクセラレーターが実行されたときにも送られてきます」
『メニューはダイアログじゃないときの話よね。それはいいとして、アクセ
ラレーターって何?』
「アクセラレーターはリソース、あ、ダイアログとかアイコンとかのリソー
スって意味だけど、そのリソースのひとつ」
『ホントだ、【挿入】で Accelerator ってのがある』
「これを使うと、たとえば Ctrl+A とか押したときに、なんかのコマンドを
実行できるようになるんです」
『なんかのコマンド? あ、 WM_COMMAND が送られるってことね』
「そゆこと。でもこれってあんまり使わないかも」
『余計なことされるとイヤだし。カスタマイズできるんなら別だけど』
「それやるとかなり大変……と、話を戻して。この WM_COMMAND は便利だけ
ど、これだけだとちょっと問題があるんだよね」
『問題?』
「ダイアログコントロールの中では、ボタンしか使えない」
『使えない……』
「まぁ使えなくはないんだけど、たとえばエディットボックスだと……やっ
てみようか。エディットボックスを貼り付けて、その ID を IDC_E_TEST に
して」
『ぺたほい』
「ダイアログプロシージャはこう」
BOOL CALLBACK DialogProc
( HWND p_hDlgWnd
, UINT p_uiMessage
, WPARAM p_wParam
, LPARAM p_lParam
)
{
if( p_uiMessage == WM_COMMAND )
{
if( LOWORD( p_wParam ) == IDC_E_TEST )
{
OutputDebugString( "IDC_E_TEST\n" );
return TRUE;
}
}
return FALSE;
}
『ボタンとほとんど同じね。ビルドして実行! うお、何やってもひっかか
る!』
「クリックしても、文字を入力しても、どんどん送られてきます。だから、
受け取ることはできるんだけど」
『なんで送られてきたかは分からないからどーしよーもないのね』
「いや、分かるんです」
『げ! そーゆーことは先に言ってよ』
「まぁまぁ。この〈どういう理由でコマンドが送られてきたのか〉は
HIWORD( p_wParam ) に入ってます。たとえばこんな感じ」
BOOL CALLBACK DialogProc
( HWND p_hDlgWnd
, UINT p_uiMessage
, WPARAM p_wParam
, LPARAM p_lParam
)
{
if( p_uiMessage == WM_COMMAND )
{
if (
( LOWORD( p_wParam ) == IDC_E_TEST )
&&
( HIWORD( p_wParam ) == EN_UPDATE )
)
{
OutputDebugString( "IDC_E_TEST, EN_UPDATE\n" );
return TRUE;
}
}
return FALSE;
}
『まず WPARAM の下2バイトが IDC_E_TEST かどうかチェックして、そのあ
と上2バイトが EN_UPDATE かどうか調べてて、その時だけ入るようにして
るのね』
「実際に試してみて」
『ほい。お、今度は文字を入力した時だけ出るようになった。それが
EN_UPDATE なの? 確かにアップデートだし』
「それが WM_COMMAND が送られてきた〈理由〉。これを【通知コード】また
は【通知メッセージ】って言います」
『つうちめっせーじ?』
「そう、英語だと Notify Code または Notify Message 。一般的には
〈コード〉よりも〈メッセージ〉の方が使われてるかも」
『のてぃふぁいめっせーじね。カタカナより、通知メッセージの方が分かり
やすいかも。だって、その〈意味〉を通知するって意味なんでしょ?』
「うーん、ちょっと違うかも。通知コードはダイアログコントロールからダ
イアログに送られてくるときに渡されるものだから」
『コントロールからダイアログへの通知?』
「そっちの方が意味としては強いかな。通知メッセージはホントはメッセー
ジじゃなくて、上で見たように LPARAM に入ってます」
『だから通知コードって言うこともあるのね』
「でも通知コードって呼ばれてるのはあんまり聞かない……話を戻して、通
知メッセージは EN_UPDATE みたいに N が付いてます」
『 E が Edit の E 、 N が Notify の N ね』
「ちょっとメッセージを整理しておこうか。普通のメッセージは WM_ で始
まるよね」
『 WM_COMMAND とかね』
「通知メッセージは、たとえばエディットボックスだったら EN_ で、ボタ
ンだったら BN_ で始まります」
『そっか、それがわかればそれで検索すれば通知メッセージ一覧が出るね』
「そうそう、そうやって調べるといいかもね。たとえば MSDN の
Edit Control Messages ってページにはエディットボックス関連のメッセー
ジ一覧が載ってて」
『 EN_UPDATE とかもあるね。あれ? EM_CANUNDO とかって何? EM_ か
ら始まってる』
「これはエディットボックスに送るメッセージ。こういう、コントロールに
送るメッセージとかもあるんです。コントロールを操作するためにね」
『ボタンだったら BM_ なんだ。 M は Message の M ?』
「たぶん」
『コントロールまわりだと、全部で3つのメッセージがあるってことなの
ねー』
「まとめると」
WM_ : 普通のメッセージ。ウィンドウプロシージャで受ける
*M_ : コントロールに送って操作する。 EM_ とか
*N_ : 通知メッセージ。コントロールから WM_COMMAND と一緒に来る
「あ、最後のはちょっと違うかな」
『違う?』
「というわけで次回に続く!」
/*
Preview Next Story!
*/
『メッセージひとつでも結構奥が深いよねー』
「でも次回は MFC の話」
『なんですとー!?』
「やっぱり、 MFC は便利だから」
『なら MFC だけにすればいいのに』
「ううん、っていうか、 MFC を参考に、 MFC を使わない方法を」
『勉強しようってことね』
「というわけで次回」
< Version 8.11 ツリービューコントロールを作ろう! >
『につづく!』
「 MFC は使わないに越したことないから……」
『でも MFC は便利なんでしょ?』
「便利なんだよね……」