プロセス管理ツールを作りたい
→ データ指向の観点から配列でデータを渡したい
→ ListViewに列単位の一括でセット・ゲットできるラッパーを作りたい
→ WM_NOTIFYとはなんぞや(いまここ)
ポイント
- Windows 3.x までの Windows API で通知メッセージの送信には WM_COMMAND が用いられてきたが、その方法にはいくつかの問題点があった
- Win 32 から新しくコントロールが追加された際に、 WM_NOTIFY を用いた通知メッセージの送信機構が採用された
- WM_NOTIFY メッセージの捌き方について例示する
WM_COMMAND について
- Windows 3.x までの Windows API では、コントロールからのメッセージをウィンドウに通知する際に WM_COMMAND メッセージを用いた
- WM_COMMAND では、wParam にコントロールの ID と通知コード、lParam にコントロールのハンドルが格納される
- WM_COMMAND では wParam と lParam が埋まってしまい、新たに追加の通知コードを増設することが困難であった
- 空きが無い点とは別に、WM_COMMAND には送れる情報が少ないという問題点があった
(たとえば、マウスがクリックされた際に送信される BN_CLICKED では、マウスカーソルの場所などの情報を送ることができない。追加のデータを送るためには、別のメッセージを設ける必要がある。)
WM_NOTIFY について
- Windows 3.1 までは WM_COMMAND で事足りていたが、Win32から複雑で洗練されたコントロールが追加されるこにとなった。Windows API の設計者は、新たにメッセージを追加するのではなく、WM_NOTIFY というたった一つのメッセージを追加することでコントロールの追加に対応した
- WM_NOTIFY では wParam にメッセージを送信したコントロールの ID が格納される。一方で、lParam にはNMHDR 構造体か、コントロール依存のより大きな構造体(第一メンバがNMHDR 構造体でありキャストが可能)である
- NMHDR 構造体のメンバはコントロールの ID とウィンドウハンドル、通知コードである
WM_NOTIFY メッセージの捌き方
ListView コントロールのメッセージ処理を例にとり、WM_NOTIFY の捌き方を述べる。ListViewの例
// In window procedure case WM_NOTIFY: return OnNofity(hwndDlg, (NMHDR*)lParam); // Function called in WM_NOTIFY LRESULT OnNofity(HWND hwndDlg, NMHDR* nmhdr) { assert(nmhdr); if (nmhdr->hwndFrom == GetDlgItem(hwndDlg, IDC_LIST1)) { switch (nmhdr->code) { case LVN_COLUMNCLICK: { // Process for column click. LPNMLISTVIEW nmlistview = (LPNMLISTVIEW)nmhdr; } break; case NM_CLICK: { // Process for single click. } break; case NM_DBLCLK: { // Process for double click. } break; default: // none. break; } } return TRUE; }
ウィンドウプロシージャ(もしくはダイアログプロシージャ)の switch 文の case ラベルに WM_NOTIFY を追加する。
WM_NOTIFY にはメッセージクラッカが用意されていないようなので、適当に関数を作る(好みの問題)。
GetDlgItem でダイアログ上 ListView コントロールのリソース ID からウィンドウハンドルを出力している。
NMHDR (lParam) 構造体には通知メッセージ送信元のウィンドウハンドルが格納されているので、これと ListView コントロールのウィンドウハンドルを比較し、一致するのであれば ポインタを LPNMLISTVIEW 構造体にキャストする。
code は通知の種類であり、ListView の場合は LVN_COLUMNCLICK (ListView に限定)や、NM_CLICK と NM_DBLCLK (コントロール間で共通) といったコードがある[2]。
まとめ
Win32 以降のコントロールの通知メッセージは WM_NOTIFY で捌く。WM_NOTIFY にはメッセージクラッカが用意されていない。
感想
自前でラッパークラスを作ろうとすると、WM_NOTIFY の処理に悩む。分かりやすくカプセル化できない?
へんちくりんなことをせず、素直にメッセージ処理はクラス外部のウィンドウ(ダイアログ)プロシージャで行い、一般化できるコントロールの管理とデータ処理はクラスで行うようにするなど、適度に分けるのが良いのかな?
作りたいアプリケーションのデータ設計の分析と、Windows API への十分な理解が大事なんやな。
0 件のコメント:
コメントを投稿
コメント表示は承認制に設定しています