ダイアログボックスを作る(2)

では、前回のソースの解説をします。

まずは基礎知識から。
ダイアログボックスは、一個のウィンドウです。また、ダイアログに並べた ボタン、エディットコントロール、アイコンなどの個々のコントロールも、それぞれが一個のウィンドウです。 各ウインドウは、ウインドウハンドルというHWND型の値(実際は整数orポインタ)で区別されます。 ただし、このウィンドウハンドルは、実行時にならないと分かりません。

一方、コントロールは、コントロールIDという整数値でも区別できます。 ダイアログテンプレートの記述を見ると、

    PUSHBUTTON "再生",  IDPLAY,   44, 35, 40, 14
    PUSHBUTTON "閉じる",IDCANCEL, 96, 35, 40, 14
ヘッダファイルを見ると、
#define IDPLAY 104
などと記述してあります。
もう分かりましたね。このIDPLAYが再生ボタンのコントロールIDです。 これはコンパイル時に既に分かっている定数です。なお、IDCANCELは、windows.hの中で定義されています。 似たようなので、今回は使っていませんが、IDOKというのもあります。

そして、コントロールIDからウィンドウハンドルを求めることができます。それには、GetDlgItem() というAPIにダイアログのウインドウハンドルと、コントロールのコントロールIDを渡します。 するとその戻り値がコントロールのウインドウハンドルです。

では、実際のソースの説明。まず、easyplay()関数を見てください

#ifdef __cplusplus
extern "C"
#endif
先頭に妙なものがついてますが、これはC++でも大丈夫なようにするおまじないで、 C言語でコンパイルするなら必要ないものです。
BOOL FAR PASCAL easyplay(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam){
BOOL(実際にはint)を返す、呼び出し規約がFAR PASCALである、引数を四つ持つ、普通の関数のように 見えますね。でも、このeasyplay()を直接呼び出している部分は、ソース中のどこにもありません。

実はこれは、コールバック関数と言いまして、OSから呼び出されるものです。Windowsの場合、 ユーザーがキーを押した、マウスを動かしたなどといった「イベント」を処理するために、 「メッセージ駆動」という考え方を全面的に採用しています。 プログラムは「イベント」が発生したときに、どの関数を呼び出してほしいかを、 あらかじめOSに登録しておきます。OSは、実際にイベントが発生した時に、そのイベントの種類を 「メッセージ」という引数にして、その関数を呼び出します。なお、コールバック関数のなかでも、 特にダイアログボックスの動作を記述したものをダイアログプロシージャと呼びます。

第二引数 UINT msg がメッセージの種類を表します。
第三および第四引数は、メッセージの種類ごとに違う「追加パラメータ」です。
WPARAM wParamは、名前に反して、Win32では32ビットになります。よってこれをWORD wParamと 書いてはいけません。(昔はこう書いていた)
なお第一引数 HWND hDlg は、ダイアログボックスのウインドウハンドルです。

では、具体的な処理内容をみていきましょう。

WM_INITDIALOGは、ダイアログが作成された直後に、ただ一度だけ送られてきます。このときSetFocus() というAPIを使ってキーボード入力先を指定しています。SetFocus()の引数は キーボート入力先のウィンドウのウィンドウハンドルです。

ダイアログ上のボタンが押された時には、WM_COMMANDメッセージが送られてきます。 このとき、追加パラメータwParamの下16ビットがコントロールIDになりますので、 どのボタンが押されたかを区別できます。

「再生」ボタンが押されたら、エディットコントロールの文字列を取り出して、それをsndPlaySound() API(その名の通り、音を鳴らします)に渡しています。ウィンドウから文字列を取り出すのは、 一般にGetWindowText()を使いますが、コメントにも書いてある通り、ダイアログボックス上のコントロールにだけ使えるGetDlgItemText()というAPIもあります。

「閉じる」ボタンが押されたら、もしくは右上の「×」ボタンかシステムメニューの「閉じる」が 選択されたら(この三つは共に、コントロールIDがIDCANCELになります)EndDialog() APIを呼び出します。 このEndDialog() APIはその名の通りダイアログを閉じるAPIです。これを忘れると 永久に閉じないダイアログができあがります。

注意。この後のbreakは省略できません。なぜならこのEndDialog()はexit()のような 「戻ってこない関数」ではないからです。動作としてはEndDialog()でダイアログを閉じることを予約し、 EndDialogから戻ってきて、ダイアログプロシージャからリターンして、 それから実際にダイアログが閉じます。

ダイアログプロシージャでメッセージを処理したときは、戻り値としてTRUEを返します。 ダイアログプロシージャでメッセージを処理しなかったときは、FALSEを返すと OS側がそのメッセージに対するデフォルトの処理を実行してくれます。ですので プログラム側は自分が興味のあるメッセージだけ処理すれば良いことになります。 実際、他にもWM_MOUSEMOVEとか様々なメッセージが送られてきていますが、すべて OSのデフォルト処理にまかせています。 なおこのTRUEとFALSEの使い分けに例外が一箇所だけあります。それがWM_INITDIALOGの場合で、 SetFocusしたらFALSE、しなかったらTRUEを返さないといけません。(他のメッセージと逆になる) そのため、このメッセージへの応答を省略することはできません。

長くなってきたので、WinMain()関数などについては、次回に回します。

前のページ

次のページ

一つ上のページに戻る