プロセス管理ツールを作りたい
→ データ指向の観点から配列でデータを渡したい
→ 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 件のコメント:
コメントを投稿
コメント表示は承認制に設定しています