Version 10.09
メニューふたたび
「今回は Version 9.06 ( No.167 ) で紹介したメニューの処理をしてみま
す」
『よーするに MFC でできたことをってことだよね』
「そうそう、いつものパターンだけど」
『 MFC と SDK でってことね。で……今はメニューないから、まずメニュー
を作らなきゃいけないんだよね』
「というわけで Version 8.06 ( No.148 ) を見ながら、まずはリソースを
作ります」
『えーっと、まず【リソーススクリプト】を作ってと。ファイル名は
SimpleWindow.rc っと』
「で、右クリックで【挿入】を選んで Menu を新規作成」
『ほいほい。お、何もないメニューが出て来た』
「まずそのメニューの ID だけど」
『 MFC の時は IDR_MAINFRAME じゃなきゃいけなかったんだよね』
「でも SDK の時はそういうの関係ないから、 IDM_MAIN でいいかな」
『それってどうやって変えるの?』
「メニューバーの上で右クリック」
『あ、これでプロパティ出せばいいんだね。うん、変えたよ』
「次はテスト用のメニューを用意します。メニューそのものについては
Version 9.02 ( No.163 ) を参照してもらうとして。まずメニューバーの最
初のをサブメニューにしてもらってその下の最初のアイテムを」
『あの時と同じにしよっと。 ID は ID_MENU_TEST 、キャプションは
【テスト(&T)】、プロンプトは〈テストだよ〉っと』
「とりあえずそれでビルドして実行してみて」
『ほい。……メニュー出ないんですけど〜』
「そう、メニューは自動では出ないんです。プログラムの方も少し修正しな
いと表示されないから。まず、 SimpleDialog の時と同じように」
#include <stdio.h>
#include <Windows.h>
// 下のを追加。
#include "resource.h"
「って感じに resource.h をインクルードしてもらいます」
『ところで resource.h ってなんてファイルなの?』
「まだ調査中。次に、ウィンドウを作るときに表示するメニューを指定しま
す」
// ウィンドウを作ります。
bool CreateAndShowWnd
( const char *const p_pchWndClassName
, HINSTANCE p_hInstance
, int p_iCmdShow
)
{
// ウィンドウを作ります。
HWND hWnd = CreateWindow
( p_pchWndClassName
, "テスト"
, WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, 0
, CW_USEDEFAULT
, 0
, NULL
, LoadMenu( p_hInstance, MAKEINTRESOURCE( IDM_MAIN ) )
, p_hInstance
, NULL
);
if( hWnd == NULL )
{
// ウィンドウの作成に失敗しました。
return false;
}
// ウィンドウを表示します。
ShowWindow( hWnd, p_iCmdShow );
UpdateWindow( hWnd );
return true;
}
「メニューは CreateWindow() の最後から3番目の引数で指定します」
『 LoadMenu() って LoadIcon() とか LoadString() なんかと同じの?』
「そう、リソースからメニューを取ってきてメニューのハンドル、つまり
HMENU として返してきます」
『 MAKEINTRESOURCE() は、初めてじゃないよね』
「 Version 8.07 ( No.149 ) とかで出てきてるね。 API の LoadMenu() は
昔の関数だからそのままリソース ID を渡せなくて、 MAKEINTRESOURCE に
一度渡してその戻り値を使わなきゃいけないんです」
『結局、何してるの? これ』
「これはマクロ。 WinUser.h に MAKEINTRESOURCE 、実際には
MAKEINTRESOURCEA があるから見てみて」
『……? なんかカッコと LPSTR とかとが色々……』
「ま、ようするにキャストしてるだけ」
『あ、それだけなんだ』
「 LoadMenu() の機能自体は普通にリソース ID を受け取れるようになって
るんだけど、昔のだから方が LPSTR なんだよね」
『だからキャストして……ごまかしてるってこと?』
「ま、そういうこと。じゃあ」
『あ、試してなかったね。ビルドして実行! おー、ちゃんとメニューが表
示された!』
「とうわけで、メニューの表示はここまで。次は、メニューを選択した時に
そのメッセージを受け取れるようにします」
『ってゆーかそっちが今回の本命なんだよね』
「なんだけど……実はすごく簡単。ウィンドウプロシージャを次のように修
正して」
// ウィンドウプロシージャ。
LRESULT CALLBACK WndProc
( HWND p_hWnd
, UINT p_uiMessage
, WPARAM p_wParam
, LPARAM p_lParam
)
{
if( p_uiMessage == WM_DESTROY )
{
// ×ボタンが押されました。
PostQuitMessage( 0 );
return 0;
}
else if( p_uiMessage == WM_COMMAND )
{
if( LOWORD( p_wParam ) == ID_MENU_TEST )
{
// ID_MENU_TEST メニュー。
PostQuitMessage( 0 );
return 0;
}
}
// 標準的な処理をします。
return DefWindowProc( p_hWnd, p_uiMessage, p_wParam, p_lParam );
}
『 WM_DESTROY は前もあったのだよね。次の WM_COMMAND のが……あれ?』
「見覚えあるでしょ。 Version 8.09 ( No.151 ) で、ダイアログのボタン
が押されたときの処理をしたでしょ、その時のダイアログプロシージャは」
// ダイアログプロシージャ。
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;
}
}
return FALSE;
}
『うわ、ほとんど同じ!』
「つまり、メニューもボタンも、同じコマンド ID 系の処理ってこと」
『どっちも、押されたら WM_COMMAND が送られてきて、 WPARAM の中に押さ
れたのの ID が入ってる……ホントに簡単ねー』
「呼ばれた時の処理は WM_DESTROY のと同じだから大丈夫だよね」
『あ、ビルドして実行! ホントだ、メニュー選ぶとちゃんと終了する』
「この辺の仕組みは共通だから」
『共通!』
「え!? な、なに?」
『 Version 9.11 ( No.172 ) で言ったけど、メニューもアクセラレーター
もツールバーも同じ仕組み、ってことはボタンも同じ!!』
「そういうこと、この辺は全部同じ WM_COMMAND 系の処理でできるわけで
す。たとえば、ダイアログにもメニューって付けることできるから」
『メニューとボタンを同じ ID にすれば、どっちも処理できる!』
「そういうこと。こういう仕組みってやっぱり MFC だけじゃ分からないか
らね」
『確かに、こういうふうに WM_COMMAND を拾ってみないとわかんなかったか
も』
「もうひとつ付け加えると…… Version 9.06 ( No.167 ) で」
『あ! あのとき、メニューも WM_COMMAND だって言ってた!』
「これは、逆の事が言えるわけ」
『逆?』
「だってあのとき、押したときのイベントハンドラを作るには COMMAND を
選ばなきゃいけないって、教えなきゃ分からなかったでしょ」
『うん、そうだけど』
「でも、もし SDK でプログラムを組んだことがあったら、メニューも
WM_COMMAND が送られてくるって知ってるから」
『そっか、それなら COMMAND だって分かる……あ! ってことはあれっ
て、 SDK で作った人向けってこと!?』
「そういうこと。 SDK で作ったことのある人、メッセージについてちゃん
と知ってる人向けってことだね」
『イベントハンドラもメッセージ名で選んでたもんねぇ。 ClassWizard
使ってるって言っても、完全な初心者向けってわけじゃないんだ』
「最初に出た VC1.0 とかはそういうユーザーは想定してなかっただろうか
らね」
『どゆこと?』
「それまでは SDK だけで作るのが普通だったから」
『むしろメッセージ関係を知らない人が VC を使うなんてなかったんだ』
「 VC1.0 とかは SDK だけで作るのが大変だってことでこういう Wizard や
MFC を提供したって面があるからね」
『……あたしはそーゆー歴史的事情も知ってなきゃいけないの?』
「……実際、この業界の歴史って知ってないと困るかも……」
/*
Preview Next Story!
*/
『プログラミングに歴史の勉強が必要なんて〜』
「問題は勉強が必要なことじゃなくて、情報が少ないことかも」
『え? 今なんていくらでも情報なんて転がってそうだけど』
「転がってても見つからなきゃしょうがないでしょ」
『そりゃそうだけど』
「プログラミングの情報はノウハウ化して文章化されないものも多いから」
『そういうのは探しても見つからないわけね』
「というわけで次回」
< Version 10.10 アクセラレーターふたたび >
『につづく!』
「だから、こういうマイナーな情報も」
『こういうふうにちゃんと教えてくれてるわけねー』