レガシー Windows API(概要)について

ここで紹介しているAPIは、Windows95、Windows NT3.5時代のAPI群であり、最新のAPIは含まれていないことに注しして欲しい。なお、当時の解説書は現在よりもより詳細に解説しているため、参考になるはずである。

  • レイアウトを変換する際、崩れているページがあります。
  • 概要およびSampleコードはありますが、APIの解説はありません。

ご要望があれば旧版のWin32 API(HELP形式)をお譲りします。問い合わせフォームより申し込みください。

Windows API ダイアログ ボックスの概要

Microsoft(R) Windows(TM) では、 「ダイアログ ボックス」とは、 ユーザの入力を取得するためにアプリケーションが一時的に作成するウィンドウです。通常、 アプリケーションは、 ダイアログ ボックスは、 コマンドの追加情報をユーザーに要求するために使われます。ダイアログ ボックスには、 ユーザーがテキストを入力したり、 オプションを選択したり、 コマンドの動作を指示するためのコントロール (子ウィンドウ) があります。

Windowsではダイアログ ボックスを作成、 管理するための関数やメッセージ、 定義済みコントロールを用意しているため、 アプリケーションのユーザー インターフェイスの開発が容易になっています。このトピックでは、 ダイアログ ボックスに関する関数とメッセージを示し、 それらを使ってダイアログ ボックスを作成して使用する方法を説明しています。

また、 Windowsでは、 [ファイル]メニューの[開く][印刷]などのコマンドをサポートするための定義済みの「コモン」ダイアログ ボックスを用意しています。このようなコマンドを使うときは、 そのコマンドを実行するアプリケーションの種類にかかわらず、 コモン ダイアログ ボックスを使ってユーザーの入力を取得してください。アプリケーションでコモン ダイアログ ボックスを使う方法について、 詳しくはコモン ダイアログ ボックス ライブラリの概要を参照してください。

次に示すトピックでは、 Win32のダイアログ ボックスについて説明しています。

ダイアログ ボックスの使用が適切な場合

オーナー ウィンドウ

メッセージ ボックス

モーダル ダイアログ ボックス

モードレス ダイアログ ボックス

ダイアログ ボックス テンプレート

ダイアログ ボックス プロシージャ

ダイアログ ボックスのキーボード インターフェイス

ダイアログ ボックスの設定

カスタム ダイアログ ボックス

ダイアログ ボックスの使用

メッセージ ボックスの表示

モーダル ダイアログ ボックスの作成

モードレス ダイアログ ボックスの作成

ダイアログ ボックスの初期化

メモリ内のテンプレートの作成

ダイアログ ボックス関数とメッセージ

ダイアログ ボックス構造体

 

 

ダイアログ ボックスの使用が適切な場合

ほとんどのアプリケーションでは、 ユーザーの入力が必要なコマンドで追加情報を要求するのにダイアログ ボックスを使います。入力を取得するには、 ダイアログ ボックスを使ってください。たとえば、 [ファイル]メニューの[開く]コマンドにはオープンするファイルの名前が必要なため、 ダイアログ ボックスを使って、 ファイル名を入力するようにユーザーに要求します。このような場合、 ユーザーがコマンドを選択したらダイアログ ボックスを作成し、 ユーザーが情報を供給したらすぐにダイアログ ボックスを破棄します。

また、 ユーザーがほかのウィンドウで作業しているときに情報やオプションを表示するのにもダイアログ ボックスが使われます。たとえば、 ワード プロセッサでは、 テキスト検索コマンドでダイアログ ボックスを使います。アプリケーションがテキストを検索している間、 ダイアログ ボックスは表示されたままです。テキストを検索した後、 ユーザーは、 ダイアログ ボックスに戻って同じ言葉を検索したり、 ダイアログ ボックスのテキストを変更して新しい言葉を検索できます。通常、 このようにダイアログ ボックスを使用する場合、 ユーザーがコマンドを選択したときにダイアログ ボックスを作成し、 アプリケーションが終了するかユーザーがダイアログ ボックスを明示的にクローズするまでダイアログ ボックスを表示したままにします。

ダイアログ ボックスのさまざまな使い方をサポートするため、 Windowsでは、 モーダルとモードレスの2種類のダイアログ ボックスを用意しています。「モーダル ダイアログ ボックス」では、 ユーザーが情報を供給するかダイアログ ボックスをキャンセルするまでアプリケーションの処理は進みません。モーダル ダイアログ ボックスは、 情報をさらに入力しなければ続行できないコマンドで使われます。「モードレス ダイアログ ボックス」では、 情報を供給した後、 ユーザーはダイアログ ボックスをクローズせずに以前の作業に戻ることができます。モーダル ダイアログ ボックスは1つの関数を呼び出すだけで作成、 作業の実行、 破棄が行えるため、 モードレス ダイアログ ボックスよりも管理が簡単です。

ダイアログ ボックスがモーダルかモードレスかにかかわらず、 ダイアログ ボックスのスタイルと内容を記述するダイアログ ボックス テンプレートと、 作業を実行するためのダイアログ ボックス プロシージャを供給しなければなりません。「ダイアログ ボックス テンプレート」とは、 ダイアログ ボックスとそれに含まれるコントロールの形式の記述です。このテンプレートは、 アプリケーションの実行可能ファイルからロードされるリソースとして作成するか、 アプリケーションの実行時にメモリ内に作成します。「ダイアログ ボックス プロシージャ」とは、 アプリケーション定義のコールバック関数で、 ダイアログ ボックスに対する入力やダイアログ ボックスが実行すべき作業が発生したときにWindowsが呼び出します。ダイアログ ボックス プロシージャはウィンドウ プロシージャに似ていますが、 役割は異なります。

通常、 ダイアログ ボックスを作成するには、 DialogBox関数かCreateDialog関数を使います。DialogBoxは、 モーダル ダイアログ ボックスを作成します。CreateDialogは、 モードレス ダイアログ ボックスを作成します。これらの関数は、 アプリケーションの実行可能ファイルからダイアログ ボックス テンプレートをロードし、 テンプレートの仕様に一致するポップアップ ウィンドウを作成します。これ以外にも、 メモリ内のテンプレートからダイアログ ボックスを作成する関数や、 ダイアログ ボックスを作成したときにダイアログ ボックス プロシージャに追加情報を渡す関数があります。

通常、 ダイアログ ボックスは、 定義済みの専用のウィンドウ クラスに所属します。Windowsは、 モーダル ダイアログ ボックスとモードレス ダイアログ ボックスの両方でこのウィンドウ クラスと対応するウィンドウ プロシージャを使います。ダイアログ ボックス関数は、 呼び出されると、 ダイアログ ボックスのウィンドウとダイアログ ボックス内のすべてのコントロールのウィンドウを作成し、 特定のメッセージだけをダイアログ ボックス プロシージャに送ります。ダイアログ ボックスが表示されているときは、 定義済みのウィンドウ プロシージャがすべてのメッセージを管理し、 一部のメッセージは自分で処理して、 残りのメッセージはダイアログ ボックス プロシージャに渡して処理させます。アプリケーションが定義済みのウィンドウ クラスやウィンドウ プロシージャに直接アクセスすることはありませんが、 ダイアログ ボックス テンプレートとダイアログ ボックス プロシージャを使ってダイアログ ボックスのスタイルと動作を変更することはできます。

 

 

オーナー ウィンドウ

ほとんどのダイアログ ボックスには、 オーナー ウィンドウ (単にオーナーとも呼ばれます) があります。ダイアログ ボックスを作成するとき、 オーナーのウィンドウ ハンドルを指定することによってオーナーを設定します。ダイアログ ボックスが常にオーナーの上に表示されるように、 Windowsは、 オーナーを使ってダイアログ ボックスのZ順序を判断します。また、 Windowsは、 オーナーのウィンドウ プロシージャにメッセージを送ってダイアログ ボックス内のイベントを通知する場合もあります。

オーナーが表示または非表示されると、 Windowsは、 そのダイアログ ボックスを自動的に表示または非表示します。つまり、 ダイアログ ボックスには、 オーナー ウィンドウの状態の変化を検出するための特別な処理は不要です。

通常、 ダイアログ ボックスはメニューのコマンドで使われるため、 オーナー ウィンドウはメニューを持つウィンドウになります。オーナーを持たないダイアログ ボックスを作成することもできますが、 そのようなことはあまり行わないでください。たとえば、 モーダル ダイアログ ボックスにオーナーがなければ、 Windowsがアプリケーションのほかのウィンドウを使用不能にすることができず、 ユーザーがほかのウィンドウで作業できるようになるため、 モーダル ダイアログ ボックスの意味がなくなります。

モードレス ダイアログ ボックスにオーナーがなければ、 アプリケーションのほかのウィンドウが非表示されたり破棄されても、 Windowsはそのダイアログ ボックスを非表示にしたり破棄することはありません。これでもモーダル ダイアログ ボックスの目的は果たせますが、 ダイアログ ボックスの非表示や破棄が適切に行われるように特別な処理を行わなければなりません。

 

 

メッセージ ボックス

メッセージ ボックスとは、 メッセージを表示したり簡単な入力を要求するために使われる特別なダイアログ ボックスです。通常、 メッセージ ボックスには、 テキスト メッセージと、 1つ以上のプッシュ ボタンが含まれます。メッセージ ボックスを作成するには、 表示するテキストとボタンの個数と種類を指定してMessageBox関数またはMessageBoxEx関数を呼び出します。MessageBoxEx関数により、 メッセージ ボックス内の定義済みのプッシュ ボタンのテキストに使う言語を指定することもできます。

メッセージ ボックスはダイアログ ボックスですが、 メッセージ ボックスの作成と管理はすべてWindowsが行います。つまり、 ダイアログ ボックス テンプレートやダイアログ ボックス プロシージャをアプリケーションが提供する必要はありません。Windowsは、 メッセージ ボックス用に指定されたテキストとボタンに基づいてテンプレートを作成し、 ダイアログ ボックス プロシージャを供給します。

メッセージ ボックスはモーダル ダイアログ ボックスであり、 Windowsは、 DialogBox関数が使用するのと同じ内部関数を使ってメッセージ ボックスを作成します。アプリケーションがMessageBoxまたはMessageBoxExを呼び出すときにオーナー ウィンドウを指定したときは、 Windowsはオーナーを使用不能にします。また、 MB_TASKMODALを指定してダイアログ ボックスを作成することによって、 現在のタスクに属するトップ レベル ウィンドウを使用不能にするようにWindowsに指示できます。

Windowsは、 モーダル ダイアログ ボックスのときと同様に、 WM_CANCELMODEWM_ENABLEなどのメッセージをオーナーに送ります。オーナー ウィンドウは、 このようなメッセージで要求された動作を実行しなければなりません。

 

 

モーダル ダイアログ ボックス

モーダル ダイアログ ボックスは、 コントロール メニュー、 タイトル バー、 細い境界線を持つポップアップ ウィンドウです。つまり、 ダイアログ ボックス テンプレートで、 WS_POPUPWS_SYSMENUWS_CAPTIONDS_MODALFRAMEの各スタイルを指定しなければなりません。WS_VISIBLEスタイルを指定することもできますが、 Windowsは、 ダイアログ ボックス テンプレートでWS_VISIBLEスタイルが指定されているかどうかにかかわらず常にダイアログ ボックスを表示します。WS_CHILDスタイルのモーダル ダイアログ ボックスは作成しないでください。このスタイルのダイアログ ボックスは自分自身を使用不能にするため、 それ以降の入力がアプリケーションに届かなくなります。

モーダル ダイアログ ボックスを作成するには、 DialogBox関数かDialogBoxIndirect関数を使います。DialogBoxには、 ダイアログ ボックス テンプレートを含むリソースの名前または識別子が必要です。DialogBoxIndirectには、 ダイアログ ボックス テンプレートを含むメモリ オブジェクトのハンドルが必要です。また、 DialogBoxParam関数とDialogBoxIndirectParam関数もモーダル ダイアログ ボックスを作成します。これらの関数は上記の関数と同じですが、 ダイアログ ボックスを作成するときに指定されたパラメータをダイアログ ボックス プロシージャに渡します。

Windowsは、 モーダル ダイアログ ボックスを作成すると、 アクティブ ウィンドウにします。ダイアログ ボックス プロシージャがEndDialog関数を呼び出すかWindowsがほかのアプリケーションのウィンドウをアクティブ化するまで、 ダイアログ ボックスはアクティブなままです。ダイアログ ボックスが破棄されるまで、 ユーザーやアプリケーションはオーナー ウィンドウをアクティブにすることはできません。

モーダル ダイアログ ボックスを作成するとき、 オーナー ウィンドウがまだ使用不能になっていなければ、 Windowsはウィンドウとそのウィンドウの子ウィンドウを自動的に使用不能にします。ダイアログ ボックスが破棄されるまで、 オーナー ウィンドウは使用不能のままです。ダイアログ ボックス プロシージャはいつでもオーナー ウィンドウを使用可能にできますが、 オーナーを使用可能にするとモーダル ダイアログ ボックスの意味がなくなるため、 そのようなことは行わないでください。ダイアログ ボックス プロシージャを破棄するとき、 モーダル ダイアログ ボックスのためにオーナーが使用不能になっていれば、 Windowsはオーナー ウィンドウを再び使用可能にします。

Windowsは、 モーダル ダイアログ ボックスを作成するとき、 現在マウス入力をキャプチャしているウィンドウにWM_CANCELMODEメッセージを送ります。このメッセージを受け取ったアプリケーションは、 マウス キャプチャを解放して、 ユーザーがマウスをモーダル ダイアログ ボックスに移動できるようにしなければなりません。Windowsはオーナー ウィンドウを使用不能にするため、 オーナーがこのメッセージを受け取ってマウスを解放しなければ、 マウス入力はすべて失われます。

Windowsは、 モーダル ダイアログ ボックスのメッセージを処理するため、 自分自身のメッセージ ループを開始して、 アプリケーション全体のメッセージ キューを一時的に制御します。Windowsは、 ダイアログ ボックス専用ではないメッセージを受け取ると、 適切なウィンドウにそのメッセージをディスパッチします。Windowsは、 WM_QUITメッセージを取得すると、 アプリケーションのメッセージ キューにそのメッセージをポストしなおして、 アプリケーションのメイン メッセージ ループがメッセージを取得できるようにします。

アプリケーションのメッセージ キューが空になると、 Windowsは、 オーナー ウィンドウにWM_ENTERIDLEメッセージを送ります。アプリケーションは、 このメッセージを使って、 ダイアログ ボックスが画面に表示されているときにバックグラウンドで処理を実行できます。アプリケーションは、 このメッセージをこのように使う場合、 (PeekMessage関数などを使って) 頻繁に制御を譲渡して、 モーダル ダイアログ ボックスがユーザー入力を受け取れるようにしなければなりません。モーダル ダイアログ ボックスを作成するときにDS_NOIDLEMSGスタイルを指定することによって、 ダイアログ ボックスがWM_ENTERIDLEメッセージを送らないようにすることができます。

モーダル ダイアログ ボックスを破棄するには、 EndDialog関数を使います。ほとんどの場合、 ユーザーがダイアログ ボックスのコントロール メニューから[閉じる]コマンドを選択するか、 ダイアログ ボックス内の[OK]ボタンか[キャンセル]ボタンを押すと、 ダイアログ ボックス プロシージャはEndDialogを呼び出します。ダイアログ ボックス プロシージャは、 EndDialog関数を呼び出すときに値を指定することによって、 DialogBox関数などの作成関数が返す値を指定できます。Windowsは、 ダイアログ ボックスを破棄してからこの値を返します。この戻り値は、 ダイアログ ボックスが作業を正常に完了したか、 それともユーザーがキャンセルしたかを判断するのに使われます。ダイアログ ボックス プロシージャがEndDialog関数を呼び出すまで、 Windowsは関数から制御を返しません。

 

 

モードレス ダイアログ ボックス

モードレス ダイアログ ボックスは、 コントロール メニュー、 タイトル バー、 太い境界線を持つポップアップ ウィンドウです。つまり、 ダイアログ ボックス テンプレートで、 WS_POPUPWS_SYSMENUWS_BORDERWS_CAPTIONの各スタイルを指定しなければなりません。テンプレートでWS_VISIBLEスタイルが指定されていなければ、 Windowsはダイアログ ボックスを自動的には表示しません。

モードレス ダイアログ ボックスを作成するには、 CreateDialog関数かCreateDialogIndirect関数を使います。CreateDialogには、 ダイアログ ボックス テンプレートを含むリソースの名前または識別子が必要です。CreateDialogIndirectには、 ダイアログ ボックス テンプレートを含むメモリ オブジェクトのハンドルが必要です。また、 CreateDialogParam関数とCreateDialogIndirectParam関数も、 モードレス ダイアログ ボックスを作成します。これらの関数は、 ダイアログ ボックスを作成するときに指定されたパラメータをダイアログ ボックス プロシージャに渡します。

CreateDialogなどの作成関数は、 ダイアログ ボックスのウィンドウ ハンドルを返します。アプリケーションやダイアログ ボックス プロシージャは、 このハンドルを使ってダイアログ ボックスを管理できます。たとえば、 ダイアログ ボックス テンプレートでWS_VISIBLEスタイルが指定されていなければ、 ShowWindow関数にこのウィンドウ ハンドルを渡してダイアログ ボックスを表示します。

モードレス ダイアログ ボックスは、 オーナー ウィンドウを使用不能にしたりオーナーにメッセージを送ることはありません。Windowsは、 ダイアログ ボックスを作成するとアクティブ ウィンドウにしますが、 ユーザーやアプリケーションはアクティブ ウィンドウをいつでも変更できます。モードレス ダイアログ ボックスは、 非アクティブ化されても、 オーナー ウィンドウがアクティブでもオーナー ウィンドウよりも上に表示されます。

アプリケーションは、 ダイアログ ボックスへの入力メッセージを取得してディスパッチしなければなりません。ほとんどのアプリケーションは、 メイン メッセージ ループでこの処理を行います。しかし、 ユーザーがキーボードを使ってダイアログ ボックスを移動したりコントロールを選択できるようにするため、 アプリケーションはIsDialogMessage関数を呼び出さなければなりません。この関数について詳しくは、 ダイアログ ボックスのキーボード インターフェイスを参照してください。

モードレス ダイアログ ボックスはモーダル ダイアログ ボックスのようにアプリケーションに値を返すことはできませんが、 ダイアログ ボックス プロシージャは、 SendMessage関数を使ってオーナー ウィンドウに情報を送ることができます。

アプリケーションは、 終了する前にモードレス ダイアログ ボックスをすべて破棄しなければなりません。モードレス ダイアログ ボックスを破棄するには、 DestroyWindow関数を使います。ほとんどの場合、 ダイアログ ボックスプロシージャは、 [キャンセル]ボタンのクリックなどのユーザー入力に対して、 DestroyWindowを呼び出します。ユーザーがこのようにしてダイアログ ボックスをクローズしなかったときは、 必ずDestroyWindowを呼び出さなければなりません。

DestroyWindow関数は、 ダイアログ ボックスのウィンドウ ハンドルを無効化して、 それ以降のそのハンドルによる関数呼び出しがエラー値を返すようにします。エラーが発生しないようにするには、 ダイアログ ボックス プロシージャは、 ダイアログ ボックスが破棄されたことをオーナーに通知しなければなりません。通常、 アプリケーションは、 ダイアログ ボックスのハンドルをグローバル変数で管理します。ダイアログ ボックス プロシージャは、 ダイアログ ボックスを破棄するときにこのグローバル変数にNULLを設定して、 ダイアログ ボックスが無効になったことを示します。

ダイアログ ボックス プロシージャは、 EndDialog関数を呼び出してモードレス ダイアログ ボックスを破棄してはいけません。

 

 

ダイアログ ボックス テンプレート

ダイアログ ボックス テンプレートとは、 ダイアログ ボックスを記述するバイナリ データで、 ダイアログ ボックスの高さ、 幅、 スタイル、 含まれるコントロールを定義します。ダイアログ ボックスを作成するとき、 Windowsは、 ダイアログ ボックス テンプレートをアプリケーションの実行可能ファイルのリソースからロードするか、 アプリケーションがグローバル メモリ内に格納しているテンプレートを使います。どちらの場合も、 アプリケーションは、 ダイアログ ボックスを作成するときにテンプレートを供給しなければなりません。

テンプレート リソースを作成するには、 リソース コンパイラからダイアログ ボックス エディタを使います。リソース コンパイラは、 テキスト記述をバイナリ リソースに変換します。ダイアログ ボックス エディタは、 対話的に構築されたダイアログ ボックスをバイナリ リソースとして保存します。

注: テンプレート リソースを作成してアプリケーションの実行可能ファイルに追加する方法は、 このドキュメントの範囲を超えています。テンプレート リソースを作成し、 実行可能ファイルに追加する方法について、 詳しくは、 アプリケーション開発ツールのドキュメントを参照してください。

テンプレート リソースを使わずにダイアログ ボックスを作成するときは、 メモリ内にテンプレートを作成して、 DialogBoxIndirect関数かCreateDialogIndirect関数に渡します。メモリ テンプレートを作成するには、 グローバル メモリ オブジェクトを割り当てて、 そのオブジェクトにDLGTEMPLATE構造体と1つ以上のDLGITEMTEMPLATE構造体を設定します。メモリ テンプレートの形式と内容は、 テンプレート リソースと同じです。通常、 メモリ テンプレートを使う場合、 まずLoadResource関数を使ってテンプレート リソースをメモリにロードしてから、 そのリソースを修正して新しいメモリ テンプレートを作成します。

ダイアログ ボックス テンプレートで使われるスタイルや寸法などの値については、 次に示すトピックで説明されています。

 

スタイル

寸法

コントロール

コントロール メニュー

フォント

メモリ内のテンプレート

 

スタイル

どのダイアログ ボックス テンプレートでも、 ダイアログ ボックスの外観と機能を定義するスタイル値の組み合わせを指定します。スタイル値には、 WS_POPUPWS_SYSMENUなどのウィンドウ スタイルと、 DS_MODALFRAMEなどのダイアログ ボックス スタイルがあります。テンプレートのスタイルの個数や種類は、 ダイアログ ボックスの種類や目的によって異なります。

Windowsは、 ダイアログ ボックスを作成するとき、 テンプレートで指定されているウィンドウ スタイルをすべてCreateWindowEx関数に渡します。たとえば、 テンプレートでDS_MODALFRAMEスタイルが指定されていれば、 Windowsは、 ダイアログ ボックスを作成するときにWS_EX_DLGMODALFRAMEスタイルを使います。テンプレートでDS_SYSMODALスタイルが指定されていれば、 WindowsはWS_EX_TOPMOSTスタイルを使います。そのほかのダイアログ ボックス スタイルは、 Windowsがダイアログ ボックスを管理する方法に影響します。

ほとんどのダイアログ ボックスは、 コントロール メニューとタイトル バーを持つポップアップ ウィンドウです。このため、 通常のテンプレートでは、 WS_POPUPスタイル、 WS_SYSMENUスタイル、 WS_CAPTIONスタイルを指定します。また、 境界線スタイルとして、 モーダル ダイアログ ボックスの場合はDS_MODALFRAMEスタイル、 モードレス ダイアログ ボックスの場合はWS_BORDERスタイルを指定します。ダイアログ ボックスの代わりにカスタマイズしたウィンドウを作成するときは、 ポップアップ以外の種類のウィンドウ (WS_OVERLAPPEDなど) を指定します。

モーダル ダイアログ ボックスの場合、 WS_VISIBLEスタイルが指定されているかどうかにかかわらず、 Windowsは、 ダイアログ ボックスを表示します。モードレスダイアログ ボックスの場合、 テンプレートでWS_VISIBLEスタイルが指定されていれば、 Windowsはダイアログ ボックスを作成すると自動的に表示します。そうでないときは、 アプリケーションはShowWindow関数を使ってダイアログ ボックスを表示しなければなりません。

Windowsがダイアログ ボックスを前面に表示させるには、 テンプレートでDS_SETFOREGROUNDスタイルを指定します。これは、 オーナー ウィンドウが前面ウィンドウかどうかにかかわらずユーザーの注意をひかなければならないモーダル ダイアログ ボックスで特に役立ちます。このスタイルは、 Windows NTだけで利用可能です。

DS_ABSALIGNスタイルを指定すると、 Windowsは、 ダイアログ ボックスの寸法をスクリーン座標として解釈します。DS_SETFONTスタイルを指定すると、 Windowsは、 システム フォントではなく指定されたフォントを使って、 ダイアログ ボックスのクライアント領域やコントロールのテキストを描画します。DS_NOIDLEMSGを指定すると、 モーダル ダイアログ ボックスがWM_ENTERIDLEメッセージをオーナー ウィンドウに送らなくなります。これらのスタイルについては、 このトピックの後半で詳しく説明します。

DS_LOCALEDITスタイルは、 16ビットのWindowsアプリケーションにのみ適用されます。DS_SYSMODALスタイルは、 Windows NTとWindowsのほかのバージョンとでは解釈が異なります。Windows NTでは、 DS_SYSMODALスタイル付きのダイアログ ボックスがWS_EX_TOPMOSTウィンドウ スタイルを受け取りますが、 ユーザーはデスクトップ上のほかのウィンドウをアクセスできます。

移植上の問題: Windows NTは、 システム モーダル ダイアログ ボックスをサポートしていません。モーダル ダイアログ ボックスを作成するとき、 Windows NTは、 DS_SYSMODALスタイルがダイアログ ボックス テンプレートで指定されていても無視します。アプリケーションは、 システム モーダル ダイアログ ボックスの動作を利用しないでください。

 

ダイアログ ボックスの寸法

どのダイアログ ボックス テンプレートにも、 ダイアログ ボックスとそれに含まれるコントロールの位置、 幅、 高さを示す寸法が含まれています。これらの寸法はデバイスに依存しないため、 1つのテンプレートを使って、 さまざまなディスプレイ デバイスで同じダイアログ ボックスを作成できます。これによって、 画面の解像度やアスペクト比が違っても、 ダイアログ ボックスの比率と外観は同じになります。

ダイアログ ボックスの寸法は、 ダイアログ基本単位で指定します。水平方向の1単位は、 システム フォントの平均文字幅の4分の1です。垂直方向の1単位は、 システム フォントの平均文字幅の8分の1です。現在のディスプレイにおける基本単位当たりのピクセル数を取得するには、 GetDialogBaseUnits関数を使います。ダイアログ基本単位の寸法をピクセル数に変換するには、 MapDialogRect関数を使います。

テンプレートには、 ダイアログ ボックスの左上隅の初期座標を指定しなければなりません。通常、 座標は、 オーナー ウィンドウのクライアント領域の左上隅に相対です。テンプレートでDS_ABSALIGNスタイルが指定されているときや、 オーナーがないときは、 位置は画面の左上隅に相対になります。Windowsはダイアログ ボックスを作成するときにこの初期位置を設定しますが、 アプリケーションは、 ダイアログ ボックスが表示される前に位置を調整できます。たとえば、 オーナー ウィンドウの寸法を取得し、 オーナー ウィンドウの中心にダイアログ ボックスを置くための位置を計算して、 SetWindowPos関数を使って位置を設定します。

テンプレートには、 画面の幅と高さを超えず、 すべてのコントロールがダイアログ ボックスのクライアント領域内に収まるような幅と高さを指定してください。ダイアログ ボックスのサイズは任意に設定できますが、 小さすぎるダイアログ ボックスや大きすぎるダイアログ ボックスを作成すると、 ユーザーが入力できなくなり、 ダイアログ ボックスの役割が失われます。コントロールがたくさんあるときは、 複数のダイアログ ボックスを使ってください。そのような場合、 最初のダイアログ ボックスには、 次のダイアログ ボックスを表示するためのプッシュ ボタンを含めます。

 

コントロール

テンプレートには、 ダイアログ ボックスの各コントロールの位置、 幅、 高さ、 スタイル、 識別子、 ウィンドウ クラスを指定します。Windowsは、 このデータをCreateWindowEx関数に渡して各コントロールを作成します。ダイアログ ボックスに対応するコマンドを完了するのに必要な情報をユーザーが入力できるようにするため、 テンプレートには、 適切なコントロールの個数、 種類、 順序を指定してください。

テンプレートでは、 各コントロールに対して、 コントロールの外観と動作を定義するスタイル値を指定します。コントロールは子ウィンドウであるため、 WS_CHILDスタイルは必ず指定しなければなりません。ダイアログ ボックスが表示されるときにコントロールも表示されるようにするには、 WS_VISIBLEスタイルも指定しなければなりません。そのほかに、 オプションの境界線を持つコントロールの場合はWS_BORDER、 ダイアログ ボックスを作成したときは使用不能になっているコントロールの場合はWS_DISABLED、 キーボードを使ってアクセス可能なコントロールの場合はWS_TABSTOPWS_GROUPを指定します。WS_TABSTOPスタイルとWS_GROUPスタイルは、 このトピックの後半で説明するダイアログ キーボード インターフェイスで使われます。

また、 テンプレートには、 コントロールのウィンドウ クラスに固有のコントロール スタイルも指定できます。たとえば、 ボタン コントロールを指定するテンプレートには、 BS_PUSHBUTTONBS_CHECKBOXなどのコントロール スタイルを指定しなければなりません。Windowsは、 WM_CREATEメッセージを使ってコントロール スタイルをコントロール ウィンドウ プロシージャに渡して、 コントロール ウィンドウ プロシージャがコントロールの外観と動作を変更できるようにします。

Windowsは、 CreateWindowEx関数を呼び出す前に、 位置の座標や幅と高さの寸法をダイアログ基本単位からピクセル単位に変換します。Windowsは、 コントロールを作成するとき、 ダイアログ ボックスを親ウィンドウとして指定します。つまり、 Windowsは、 ダイアログ ボックスのクライアント領域の左上隅に相対的なクライアント座標系でコントロールの位置座標を解釈します。

テンプレートには、 各コントロールのウィンドウ クラスを指定します。通常、 ダイアログ ボックスには、 ボタンやエディット コントロールなどの定義済みコントロール ウィンドウ クラスに属するコントロールがあります。この場合、 テンプレートでは、 クラスに対応する定義済みアトム値でウィンドウ クラスを指定します。カスタム コントロール ウィンドウ クラスの属するコントロールの場合は、 登録されているウィンドウ クラスの名前か、 その名前に現在関連付けられているアトム値をテンプレートに指定します。

コントロールどうしを区別するため、 ダイアログ ボックスの各コントロールには一意な識別子を指定しなければなりません。コントロールはWM_COMMANDメッセージを使ってダイアログ ボックス プロシージャに情報を送るため、 コントロール識別子がなければ、 ダイアログ ボックス プロシージャはどのコントロールがメッセージを送ったかを判断できません。この規則の唯一の例外は、 スタティック コントロールのコントロール識別子です。スタティック コントロールはWM_COMMANDメッセージを送らないため、 一意な識別子は不要です。

ユーザーがダイアログ ボックスをクローズできるようにするには、 コントロール識別子としてIDCANCELを持つプッシュ ボタンをテンプレートに指定します。ダイアログ ボックスによるコマンドを完了するか取り消すかを選択できるようにするには、 [OK][キャンセル]の2つのプッシュ ボタンをテンプレートに指定します。この場合、 [OK]ボタンと[キャンセル]ボタンの識別子はそれぞれIDOKとIDCANCELでなければなりません。

また、 テンプレートには、 オプションのテキストと作成データも指定できます。通常、 このテキストには、 ボタン コントロールのラベルや、 スタティック テキスト コントロールの初期の内容を指定します。作成データとは、 Windowsがコントロールを作成するときにコントロール ウィンドウ プロシージャに渡すデータです。作成データは、 ほかのデータで指定した初期の内容やスタイルに関する詳細な情報が必要なコントロールで役立ちます。たとえば、 作成データを使って、 スクロール バー コントロールの初期設定と範囲を設定できます。

 

コントロール メニュー

テンプレートでWS_SYSMENUスタイルを指定すると、 Windowsは、 ダイアログ ボックスにコントロール メニューを付加します。不適切なコマンド入力を防ぐため、 Windowsは、 [移動]コマンドと[閉じる]コマンド以外のメニュー コマンドを自動的にすべて使用不能にします。ユーザーは、 [移動]コマンドを使ってダイアログ ボックスを移動できます。ユーザーが[閉じる]コマンドを選択すると、 Windowsは、 wParamパラメータにIDCANCELを設定したWM_COMMANDメッセージをダイアログ ボックス プロシージャに送ります。このメッセージは、 ユーザーが[キャンセル]ボタンを選択したときにボタンが送るメッセージと同じです。このメッセージを受け取ったら、 ダイアログ ボックスをクローズし、 要求されたコマンドや処理を取り消してください。

ダイアログ ボックスにこれ以外のメニューを付加するのはよくありませんが、 ダイアログ ボックス テンプレートでは、 メニュー リソースの識別子または名前を供給してメニューを指定できます。この場合、 Windowsは、 そのメニュー リソースをロードして、 ダイアログ ボックスのメニューを作成します。通常、 テンプレートを使ってダイアログ ボックスではなくカスタム ウィンドウを作成するときに、 テンプレート内でメニュー識別子またはメニュー名を使います。

 

フォント

デフォルトでは、 Windowsは、 ダイアログ ボックス内のすべてのテキストをシステム フォントを使って描画します。Windowsがほかのフォントを使うようにするには、 ダイアログ ボックスにDS_SETFONTスタイルを設定し、 ポイント サイズと書体名を指定します。ダイアログ ボックスでフォントを指定することもできますが、 Windowsは、 ダイアログ ボックスのタイトルとメニューには必ずシステム フォントを使います。DS_SETFONTスタイルでもこの設定は変更できません。

DS_SETFONTスタイルを指定すると、 システムは、 コントロールを作成するときに、 ダイアログ ボックスとその各コントロールにWM_SETFONTメッセージを送ります。ダイアログ ボックス プロシージャは、 WM_SETFONTメッセージで渡されたフォント ハンドルを保存し、 ウィンドウにテキストを描画するときはディスプレイ デバイス コンテキストでそのハンドルを選択しなければなりません。定義済みコントロールは、 デフォルトでこの処理を行います。

DS_SETFONTスタイルを指定すると、 Windowsは、 指定されたフォントの平均文字幅を使ってダイアログ ボックスの位置と寸法を計算します。このスタイルを指定しなければ、 システム フォントの平均文字幅を使います。

 

メモリ内のテンプレート

メモリ内のテンプレートは、 DLGTEMPLATE構造体とそれに続く1つ以上のDLGITEMTEMPLATE構造体、 関連するデータで構成されます。ダイアログ ボックス内の各コントロールについてDLGITEMTEMPLATE構造体が1つずつあります。

DLGTEMPLATE構造体は、 ダイアログ ボックス内のコントロールの位置、 幅、 高さ、 スタイル、 個数を示します。構造体の後の追加データは、 ダイアログ ボックスのオプションのメニュー、 クラス、 タイトル、 フォントを示します。DLGTEMPLATE構造体の形式を次に示します。

 

typedef struct { /* dltt */
DWORD style;
DWORD dwExtendedStyle;
WORD cdit;
WORD x;
WORD y;
WORD cx;
WORD cy;
} DLGTEMPLATE;

styleメンバは、 ダイアログ ボックスのウィンドウ スタイルやダイアログ ボックス スタイルを示します。Windowsは、 ダイアログ ボックスを作成するときにはdwExtendedStyleメンバは使いません。テンプレートを使ってほかの種類のウィンドウを作成する場合は、 このメンバを使ってウィンドウの拡張ウィンドウ スタイルを指定できます。xメンバとyメンバは、 ダイアログ ボックスの位置を示します。cxcyは、 幅と高さを示します。cditメンバはダイアログ ボックス内のコントロールの個数を示します。テンプレート内には、 cditと同じ個数のDLGITEMTEMPLATE構造体があります。

DLGTEMPLATE構造体の直後には、 ダイアログ ボックスにメニューがあるかどうかを示す16ビット値があります。この値が0x0000ならば、 ダイアログ ボックスにはメニューはありません。0xFFFFならば、 次の16ビット値がダイアログ ボックスのメニューを記述するメニュー リソースの識別子を示します。初期値が0x0000でも0xFFFFでもなければ、 Windowsは、 ダイアログ ボックスのメニューを記述するメニュー リソースの名前を示すNULLで終わる文字列の開始位置と解釈します。

メニュー識別子またはメニュー名の次の16ビット値は、 ダイアログ ボックスが属するウィンドウ クラスを示します。この値が0x0000ならば、 Windowsは、 ダイアログ ボックスに定義済みのダイアログ ボックス クラスを使います。この値が0xFFFFならば、 次の16ビット値は、 登録されているウィンドウ クラスを識別するアトム値です。初期値が0x0000でも0xFFFFでもなければ、 Windowsは、 登録されているウィンドウ クラスを記述するNULLで終わる文字列の開始位置と解釈します。

クラス アトムまたはクラス名の直後には、 ダイアログ ボックスのタイトルがあります。タイトルは、 NULLで終わる文字列です。文字列が空ならば、 Windowsは、 ダイアログ ボックスのタイトルを空白にします。ダイアログ ボックスにWS_CAPTIONスタイルが設定されていなければ、 Windowsは、 指定された文字列をタイトルに設定しますが、 表示はしません。

ダイアログ ボックスにDS_SETFONTスタイルが設定されているときは、 ダイアログ ボックス タイトルの直後に、 ポイント サイズを示す16ビット値と、 フォントの書体名を示すNULLで終わる文字列があります。Windowsは、 このデータを使って、 ダイアログ ボックスのクライアント領域やコントロールのテキストを描画するときに使われるフォントを作成します。ダイアログ ボックスにDS_SETFONTスタイルが設定されていなければ、 テンプレートにはこの16ビット値と文字列は含まれません。

テンプレート内の各DLGITEMTEMPLATE構造体は、 コントロールの位置、 幅、 高さ、 スタイル、 識別子を示すデータを含みます。各構造体の後には、 コントロールが属するウィンドウクラスとコントロールの初期テキストや、 コントロールの作成に必要な作成データを示す追加情報があります。DLGITEMTEMPLATE構造体の形式を次に示します。

 

typedef struct { /* dlit */
DWORD style;
DWORD dwExtendedStyle;
WORD x;
WORD y;
WORD cx;
WORD cy;
WORD id;
} DLGITEMTEMPLATE;

styleメンバは、 コントロール スタイルを示します。このメンバは、 BS_PUSHBUTTONWS_VISIBLEなどのウィンドウ スタイル フラグの組み合わせです。Windowsは、 ダイアログ ボックスのコントロールを作成するときはdwExtendedStyleメンバは使いません。テンプレートを使ってそのほかの種類のウィンドウを作成するときは、 このメンバを使ってコントロールの拡張ウィンドウ スタイルを指定できます。xメンバとyメンバは、 コントロールの左上隅の座標を示します。cxcyは、 コントロールの幅と高さを示します。idメンバはコントロール識別子です。

コントロールのウィンドウ クラスは、 DLGITEMTEMPLATE構造体の直後のアトムまたは名前で指定します。構造体の次の16ビットが0xFFFFならば、 その次の16ビット値は、 登録されているウィンドウ クラスを識別するアトム値です。そうでないときは、 構造体の直後には、 登録されているウィンドウ クラスを示すNULLで終わる文字列があります。

コントロール テキストは、 クラス アトムまたはクラス名の後の最初の16ビット境界から始まります。このテキストは、 リソース識別子を示す2つの16ビット値か、 コントロールの初期テキストを示すNULLで終わる文字列です。このメンバがリソース識別子ならば、 最初の16ビット値は0xFFFFで、 次の16ビット値が識別子です。通常、 リソース識別子は、 テキストを表示せずにアイコンなどのリソースをロードして表示するスタティック アイコン コントロールなどで使われます。

コントロール テキストの後には、 コントロールに必要な追加作成データがあります。Windowsは、 CreateWindowEx関数を呼び出すときに、 このデータを作成パラメータとしてコントロールに渡します。

 

 

 

ダイアログ ボックス プロシージャ

ダイアログ ボックス プロシージャは、 実行すべき動作があるときにWindowsがメッセージを送るという点ではウィンドウ プロシージャに似ています。しかし、 ダイアログ ボックス プロシージャは、 DefWindowProc関数を呼び出しません。その代わりに、 メッセージを処理するときはTRUEを、 処理しないときはFALSEを返します。

ダイアログ ボックス プロシージャの形式を次に示します。

 

BOOL APIENTRY DlgProc(hwndDlg, message, wParam, lParam)
HWND hwndDlg;
UINT message;
WPARAM wParam;
LPARAM lParam;
{
switch (message) {

/* Place message cases here. */

default:
return FALSE;
}
}

プロシージャのパラメータの意味は、 ウィンドウ プロシージャと同じです。たとえば、 hwndDlgパラメータには、 ダイアログ ボックスのウィンドウ ハンドルが渡されます。

通常、 ダイアログ ボックス プロシージャでは、 コントロールが送ったWM_INITDIALOGメッセージとWM_COMMANDメッセージを処理しますが、 それ以外のメッセージは処理しません。ダイアログ ボックス プロシージャは、 メッセージを処理しないときは、 FALSEを返してWindowsにメッセージを処理させます。この規則の例外はWM_INITDIALOGメッセージです。ダイアログ ボックス プロシージャは、 TRUEを返して、 WindowsにもWM_INITDIALOGメッセージを処理させなければなりません。どのような場合でも、 ダイアログ ボックス プロシージャはDefWindowProcを呼び出してはいけません。

 

WM_INITDIALOGメッセージ

Windowsは、 ダイアログ ボックス プロシージャにはWM_CREATEメッセージを送りません。その代わり、 ダイアログ ボックスとそのコントロールを作成するときにWM_INITDIALOGメッセージを送り、 その後でダイアログ ボックスを表示します。プロシージャは、 コマンドや処理に関する現在の設定をダイアログ ボックスに表示するのに必要な初期化を行わなければなりません。たとえば、 現在のドライブとディレクトリを表示するコントロールがダイアログ ボックスにあるときは、 プロシージャは、 現在のドライブとディレクトリを判断して、 コントロールにその値を設定しなければなりません。

プロシージャがコントロールを初期化するには、 SetDlgItemTextCheckDlgButtonなどの関数を使います。コントロールはウィンドウであるため、 プロシージャは、 EnableWindowSetFocusなどのウィンドウ管理関数を使ってコントロールを操作することもできます。コントロールのウィンドウ ハンドルを取得するには、 GetDlgItem関数を使います。

ダイアログ ボックス プロシージャは、 必要に応じて、 コントロールの内容、 状態、 位置を変更できます。たとえば、 ファイル名のリスト ボックスと[開く]ボタンがあるダイアログ ボックスの場合、 プロシージャは、 ユーザーがリストからファイルを選択するまで[開く]ボタンを使用不能にします。この場合、 ダイアログ ボックステンプレートで[開く]ボタンにWS_DISABLEDスタイルを指定しておくと、 Windowsは、 ボタンを作成するときに自動的に使用不能にします。ダイアログ ボックス プロシージャは、 ユーザーがファイルを選択したことを示す通知メッセージをリスト ボックスから受け取ったら、 EnableWindow関数を呼び出して[開く]ボタンを使用可能にします。

DialogBoxParam DialogBoxIndirectParamCreateDialogParam CreateDialogIndirectParamなどの関数を使ってダイアログ ボックスを作成する場合、 WM_INITDIALOGメッセージのlParamパラメータには、 関数に渡された追加パラメータが設定されています。通常、 この追加パラメータは、 追加初期化情報のアドレスをダイアログ ボックス プロシージャに渡すために使われますが、 パラメータの意味はダイアログ ボックス プロシージャが自由に解釈できます。これ以外の関数を使ってダイアログ ボックスを作成すると、 WindowsはlParamパラメータにNULLを設定します。

プロシージャは、 WM_INITDIALOGメッセージから戻る前に、 特定のコントロールに入力フォーカスを設定するかどうかを決定しなければなりません。ダイアログ ボックス プロシージャがTRUEを返すと、 Windowsは、 wParamパラメータのウィンドウ ハンドルのコントロールに入力フォーカスを設定します。デフォルト フォーカスを受け取るコントロールが不適切ならば、 SetFocus関数を使って適切なコントロールにフォーカスを設定できます。入力フォーカスを設定したときは、 FALSEを返してWindowsがデフォルト フォーカスを設定しないようにしなければなりません。デフォルトの入力フォーカスを受け取るコントロールは、 表示されていて使用不能ではなく、 WS_TABSTOPスタイルを持つ、 テンプレートで最初に指定されているコントロールです。そのようなコントロールがなければ、 Windowsは、 テンプレートの最初のコントロールにデフォルトの入力フォーカスを設定します。

 

WM_COMMANDメッセージ

コントロール内でユーザーが何らかの動作を実行したとき、 コントロールは、 ダイアログ ボックス プロシージャにWM_COMMANDメッセージを送ります。このようなメッセージは通知メッセージと呼ばれ、 ユーザー入力をプロシージャに通知し、 プロシージャが適切な応答を実行できるようにします。

スタティック コントロール以外のすべての定義済みコントロールは、 特定のユーザー動作に対して、 通知メッセージを送ります。たとえば、 ユーザーがプッシュ ボタンを選択すると、 ボタンは、 BN_CLICKED通知メッセージを送ります。どの場合でも、 wParamパラメータの下位ワードにはコントロール識別子、 wParamの上位ワードには通知コード、 lParamパラメータにはコントロール ウィンドウのハンドルが設定されています。

移植上の問題: Windows NTでは、 通知コードはlParamパラメータではなくwParamパラメータに設定されます。Windows 3.xアプリケーションをWindows NTに移植するときは、 通知メッセージを処理するコードを修正してください。

ダイアログ ボックス プロシージャは、 通知メッセージを監視して処理しなければなりません。とくに、 IDOK識別子やIDCANCEL識別子を持つメッセージは必ず処理してください。これらのメッセージは、 ユーザーによるダイアログ ボックス クローズ要求を示しています。モーダル ダイアログ ボックスの場合はEndDialog関数、 モードレス ダイアログ ボックスの場合はDestroyWindow関数を使って、 ダイアログ ボックスをクローズしてください。

また、 コントロール メニューなどのメニューを持つダイアログ ボックスでユーザーがコマンドを選択すると、 Windowsは、 ダイアログ ボックス プロシージャにWM_COMMANDメッセージを送ります。とくに、 ユーザーがダイアログ ボックスのコントロール メニューから[閉じる]コマンドを選択した場合、 Windowsは、 wParamパラメータにIDCANCELを設定したWM_COMMANDメッセージを送ります。このメッセージは[キャンセル]ボタンが送る通知メッセージとほとんど同じであり、 まったく同様に処理しなければなりません。

 

WM_NOTIFYPARENTメッセージ

ユーザーがコントロール内でマウス ボタンを押すと、 コントロールは、 WM_PARENTNOTIFYメッセージを送ります。一部のアプリケーションでは、 このメッセージを、 コントロールの使用目的を説明するテキストの表示などのコントロールに関連する動作を実行するためのシグナルとして解釈します。

通常、 Windowsは、 ウィンドウを作成したり破棄するときにWM_PARENTNOTIFYメッセージも送ります。ダイアログ ボックス テンプレートから作成したコントロールにはこのメッセージは送られません。Windowsは、 コントロールを作成するときにWS_EX_NOPARENTNOTIFYスタイルを指定して、 このメッセージが送られないようにします。ダイアログ ボックスに自分でコントロールを作成しない限り、 アプリケーションがこの動作を変更することはできません。

 

コントロールのカラー メッセージ

コントロールやWindowsは、 特定のブラシと色を使ってコントロールなどのウィンドウの背景をダイアログ ボックス プロシージャに描画させたいときに、 コントロールのカラー メッセージを送ります。このメッセージは、 ダイアログ ボックスやそのコントロールで使われるデフォルトの色をアプリケーションが変更するときに役立ちます。コントロールのカラー メッセージを次に示します。

WM_CTLCOLORBTN

WM_CTLCOLORDLG

WM_CTLCOLOREDIT

WM_CTLCOLORLISTBOX

WM_CTLCOLORSCROLLBAR

WM_CTLCOLORSTATIC

コントロールは、 自分自身の背景を描画する直前にコントロールのカラー メッセージをダイアログ ボックス プロシージャに送ります。ダイアログ ボックス プロシージャは、 このメッセージによって、 使用するブラシを設定し、 前景色と背景色を設定できます。ダイアログ ボックス プロシージャは、 ブラシ ハンドルを返すことによってブラシを指定します。また、 背景色と前景色を設定するには、 コントロールのディスプレイ デバイス コンテキストに対してSetBkColor関数とSetTextColor関数を使います。プロシージャには、 wParamパラメータにディスプレイ デバイス コンテキストのハンドルを設定したコントロールのカラー メッセージが送られます。

ダイアログ プロシージャがWM_ERASEBKGNDメッセージを処理しなければ、 Windowsは、 ダイアログ ボックス プロシージャにWM_CTLCOLORDLGメッセージを送ります。定義済みのダイアログ ボックス クラスにはクラス背景ブラシはないため、 プロシージャは、 このメッセージを使って、 特別な処理を行わずに自分自身の背景を定義できます。

どの場合でも、 ダイアログ ボックス プロシージャがコントロールのカラー メッセージを処理しなければ、 Windowsは、 デフォルトのウィンドウの色のブラシを使ってスクロール バー以外のすべてのコントロールとウィンドウの背景を描画します。デフォルトのウィンドウの色を取得するには、 COLOR_WINDOWを指定してGetSysColor関数を呼び出します。背景を描画するとき、 ディスプレイ デバイス コンテキストの前景色はデフォルトのテキストの色 (COLOR_WINDOWTEXT) に設定されます。スクロール バーの場合、 Windowsは、 デフォルトのスクロール バーの色 (COLOR_SCROLLBAR) のブラシを使います。この場合、 ディスプレイ デバイス コンテキストの背景色と前景色はそれぞれ白と黒に設定されます。

移植上の問題: Windows NTでは、 WM_CTLCOLORメッセージはコントロールのカラー メッセージのセットで置き換えられています。Windows 3.xのアプリケーションをWindows NTするときは、 この変更に合わせてコードを修正してください。

 

デフォルトのメッセージ処理

定義済みダイアログ ボックス クラスのウィンドウ プロシージャは、 ダイアログ ボックス プロシージャが処理しないメッセージすべてに対してデフォルトのメッセージ処理を実行します。ダイアログ ボックス プロシージャがメッセージに対してFALSEを返すと、 定義済みウィンドウ プロシージャはそのメッセージをチェックし、 次に示すデフォルト動作を実行します。

 

メッセージ デフォルト動作

DM_GETDEFID デフォルト プッシュ ボタンがあればそのコントロール識別子を返します。そうでないときは、 0を返します。

DM_SETDEFID wParamパラメータのコントロール識別子で指定されたコントロールをデフォルト プッシュ ボタンにします。

WM_ACTIVATE ダイアログ ボックスをアクティブ化するときは、 以前に保存しておいたハンドルが識別するコントロールに入力フォーカスを設定します。そうでないときは、 入力フォーカスを持つコントロールのハンドルを保管します。

WM_CHARTOITEM 0を返します。

WM_CLOSE IDCANCELをコントロール識別子に指定したBN_CLICKED通知メッセージをダイアログ ボックスにポストします。ダイアログ ボックスにIDCANCELコントロール識別子を持つコントロールがあり、 そのコントロールが現在使用不能になっているときは、 プロシージャは警告音を鳴らし、 メッセージをポストしません。

WM_COMPAREITEM 0を返します。

WM_ERASEBKGND WM_CTLCOLORDLGメッセージが返したブラシかデフォルトのウィンドウの色を使って、 ダイアログ ボックスのクライアント領域を塗りつぶします。

WM_GETFONT アプリケーション定義のダイアログ ボックス フォントのハンドルを返します。

WM_INITDIALOG 0を返します。

WM_LBUTTONDOWN 入力フォーカスを持つコンボ ボックスにCB_SHOWDROPDOWNメッセージを送って、 コントロールにドロップダウン リスト ボックスを非表示にさせます。プロシージャは、 DefWindowProc関数を呼び出して動作を完了します。

WM_NCDESTROY (Windows 3.xアプリケーションでDS_LOCALEDITスタイルを指定しているときは) ダイアログ ボックス内のエディット コントロール用に割り当てられているグローバル メモリを解放し、 (ダイアログ ボックスにDS_SETFONTスタイルを指定しているときは) アプリケーション定義のフォントを解放します。プロシージャは、 DefWindowProc関数を呼び出してデフォルトの動作を完了します。

WM_NCLBUTTONDOWN 入力フォーカスを持つコンボ ボックスにCB_SHOWDROPDOWNメッセージを送って、 コントロールにドロップダウン リストを非表示にさせます。プロシージャは、 DefWindowProc関数を呼び出してデフォルトの動作を完了します。

WM_NEXTDLGCTL ダイアログ ボックス内の次または前のコントロールに入力フォーカスを設定するか、 wParamパラメータのハンドルが識別するコントロールにフォーカスを設定します。または、 表示されていて使用不能ではなく、 WS_TABSTOPスタイルを持つ、 ダイアログ ボックス内の最初のコントロールにフォーカスを設定します。現在入力フォーカスを持つウィンドウがコントロールではないときは、 プロシージャはこのメッセージを無視します。

WM_SETFOCUS 以前に保存しておいたコントロール ウィンドウ ハンドルが識別するコントロールに入力フォーカスを設定します。そのようなハンドルがなければ、 プロシージャは、 テンプレート内の最初のコントロールに入力フォーカスを設定します。

WM_SHOWWINDOW ダイアログ ボックスが非表示になるときは、 入力フォーカスを持つコントロールのハンドルを保存します。それから、 DefWindowProc関数を呼び出してデフォルトの動作を完了します。

WM_SYSCOMMAND ダイアログ ボックスがアイコン化されるときは、 入力フォーカスを持つコントロールのハンドルを保存します。それから、 DefWindowProc関数を呼び出してデフォルトの動作を完了します。

WM_VKEYTOITEM 0を返します。

 

 

定義済みのウィンドウ プロシージャは、 上記以外のメッセージはすべてDefWindowProc関数に渡してデフォルトの処理を実行させます。

 

 

ダイアログ ボックスのキーボード インターフェイス

Windowsでは、 一部のキーに対して特別な処理を行うダイアログ ボックスのために特別なキーボード インターフェイスを用意しています。このインターフェイスは、 ダイアログ ボックス内の特定のボタンに対応するメッセージを生成したり、 コントロール間でフォーカスを変更します。このインターフェイスで使われるキーとその動作を次に示します。

 

キー 動作

Alt+「ニーモニック」 指定されたニーモニックを含むスタティック コントロールの後の最初の (WS_TABSTOPスタイルを持つ) コントロールに入力フォーカスを移動します。

グループ内の次のコントロールに入力フォーカスを移動します。

Enter ダイアログ ボックス プロシージャにWM_COMMANDメッセージを送ります。wParamパラメータには、 IDOKか、 デフォルト プッシュ ボタンのコントロール識別子が設定されます。

Esc ダイアログ ボックス プロシージャにWM_COMMANDメッセージを送ります。wParamパラメータには、 IDCANCELが設定されます。

グループ内の1つ前のコントロールに入力フォーカスを移動します。

「ニーモニック」 指定されたニーモニックを含むスタティック コントロールの後の (WS_TABSTOPスタイルを持つ) 最初のコントロールに入力フォーカスを移動します。

グループ内の次のコントロールに入力フォーカスを移動します。

Shift+Tab WS_TABSTOPスタイルを持つ前のコントロールに入力フォーカスを移動します。

Tab WS_TABSTOPスタイルを持つ次のコントロールに入力フォーカスを移動します。

グループ内の1つ前のコントロールに入力フォーカスを移動します。

 

 

Win32アプリケーション プログラミング インターフェイス (API) は、 すべてのモーダル ダイアログ ボックスに対してキーボード インターフェイスを自動的に提供します。アプリケーションがメイン メッセージ ループでIsDialogMessage関数を呼び出してメッセージをフィルタしなければ、 モードレス ダイアログ ボックスに対してはキーボード インターフェイスは提供されません。つまり、 アプリケーションは、 メッセージ キューからメッセージを取得したら、 すぐにそのメッセージをIsDialogMessageに渡さなければなりません。この関数は、 メッセージがダイアログ ボックスに対するものならばメッセージを処理して、 メッセージを処理したことを示す0以外の値を返します。その場合、 メッセージをTranslateMessage関数やDispatchMessage関数に渡さないでください。

ダイアログ ボックスのキーボード インターフェイスでは方向キーを使ってダイアログ ボックス内のコントロール間を移動するため、 モーダル ダイアログ ボックスやIsDialogMessage関数が呼び出されたモードレス ダイアログ ボックスの内容を方向キーを使ってスクロールすることはできません。ダイアログ ボックスにスクロール バーがあるときは、 スクロール バー用のキーボード インターフェイスを別に用意しなければなりません。システムでマウスが利用可能ならば、 マウス インターフェイスを使ってスクロールできます。

 

WS_TABSTOPスタイル

ダイアログ ボックスのコントロールにWS_TABSTOPが指定されていなければ、 TabキーとShift+Tabキーの効果はありません。Windowsは、 次に入力フォーカスを受け取るコントロールをダイアログ ボックス内で探すとき、 これらのスタイルを調べます。

ユーザーがTabキーやShift+Tabキーを押すと、 Windowsは、 まず、 入力フォーカスを持つコントロールがそのキーを処理するかどうかを判断します。Windowsは、 コントロールにWM_GETDLGCODEメッセージを送り、 コントロールがDLGC_WANTTABを返したら、 コントロールにそのキーを送ります。そうでないときは、 Windowsは、 GetNextDlgTabItem関数を使って、 表示されていて使用不能ではなく、 WS_TABSTOPスタイルを持つ次のコントロールを探します。コントロールの検索は現在入力フォーカスを持つコントロールから始まり、 コントロールが作成された順番 (ダイアログ ボックス テンプレートで定義されている順番) に検索されます。Windowsは、 必要な特性を持つコントロールを見つけたら、 そのコントロールに入力フォーカスを移動します。

また、 アプリケーションは、 GetNextDlgTabItemを使って、 WS_TABSTOPスタイルを持つコントロールを見つけることもできます。この関数は、 入力フォーカスを移動せずに、 WS_TABSTOPスタイルを持つ次または前のコントロールのウィンドウ ハンドルを取得します。

 

WS_GROUPスタイル

ユーザーが方向キーを押すと、 デフォルトでは、 Windowsは次または前のコントロールにフォーカスを移動します。入力フォーカスを持つ現在のコントロールが方向キーを処理せず、 次または前のコントロールがスタティック コントロールでなければ、 Windowsは、 ユーザーが方向キーを押している限り、 ダイアログ ボックス内のすべてのコントロール間で入力フォーカスを移動します。

このデフォルト動作を変更するには、 WS_GROUPスタイルを使います。このスタイルは、 コントロールのグループの先頭をマークします。ユーザーが方向キーを押し始めたときにグループ内のコントロールに入力フォーカスがあれば、 フォーカスはそのグループ外には出ません。一般に、 グループ内の最初のコントロールにWS_GROUPスタイルを設定し、 グループ内のそのほかのコントロールにはこのスタイルを設定しません。グループ内のコントロールは連続していなければなりません。つまり、 コントロールは、 間にほかのコントロールをはさまずに連続して作成しなければなりません。

ユーザーが方向キーを押すと、 Windowsは、 まず、 現在入力フォーカスを持つコントロールが方向キーを処理するかどうかを判断します。Windowsは、 コントロールにWM_GETDLGCODEメッセージを送り、 コントロールがDLGC_WANTARROWSを返したら、 そのキーをコントロールに渡します。そうでないときは、 WindowsはGetNextDlgGroupItem関数を使ってグループ内の次のコントロールを判断します。

GetNextDlgGroupItem関数は、 コントロールを作成したときの順番 (またはその反対の順番) でコントロールを検索します。ユーザーがキーかキーを押したとき、 コントロールにWS_GROUPスタイルが設定されていなければ、 GetNextDlgGroupItemは次のコントロールを返します。そうでないときは、 この関数は、 検索の順番を反対にして、 WS_GROUPスタイルを持つ最初のコントロールを返します。ユーザーがキーかキーを押したとき、 現在のコントロールにすでにWS_GROUPスタイルが設定されていなければ、 GetNextDlgGroupItemは前のコントロールを返します。現在のコントロールにWS_GROUPスタイルが設定されていれば、 この関数は、 検索の順番を反対にして、 WS_GROUPスタイルを持つ最初のコントロールを探し、 見つかったコントロールのすぐ前にあるコントロールを返します。

Windowsは、 次または前のコントロールを見つけると、 そのコントロールにWM_GETDLGCODEメッセージを送ってコントロールの種類を判断します。コントロールがスタティック コントロールでなければ、 その後、 Windowsは、 コントロールに入力フォーカスを移動します。コントロールが自動ラジオボタンならば、 Windowsは、 コントロールにBM_CLICKメッセージを送ります。また、 アプリケーションは、 GetNextDlgGroupItem関数を使ってグループ内でコントロールを探すこともできます。

ユーザーがTabキーを使ってグループ間を移動できるようにするため、 通常、 グループ内の最初のコントロールには、 WS_GROUPスタイルとWS_TABSTOPスタイルを組み合わせて設定します。グループにオプション ボタンが含まれているときは、 グループ内の最初のコントロールだけにWS_TABSTOPスタイルを設定してください。ユーザーがグループ内のコントロールを移動すると、 Windowsは、 スタイルを自動的に移動させます。これによって、 ユーザーがTabキーを使ってグループに移動したとき、 最後に選択されていたコントロールに入力フォーカスが設定されるようになります。

 

ニーモニック

ニーモニックとは、 ボタンのラベルやスタティック コントロールのテキストに含まれる特定の文字または数字です。ニーモニックに対応するキーをユーザーが押したり、 そのキーとAltキーを組み合わせて押すと、 Windowsは、 そのニーモニックに関連付けられているコントロールに入力フォーカスを移動します。ユーザーは、 ニーモニックによって、 キーボードを使って特定のコントロールにすばやく移動できます。

コントロールのニーモニックを作成するには、 コントロールのラベルやテキストの特定の文字や数字の前にアンパサンド記号 (&) を挿入します。ダイアログ ボックス テンプレート内のコントロールに指定されているNULLで終わる文字列にはアンパサンドが含まれています。しかし、 アプリケーションは、 SetDlgItemText関数を使ってコントロールの既存のラベルやテキストを置き換えることによって、 いつでもニーモニックを作成できます。 各コントロールに指定できるニーモニックは1つだけです。ダイアログ ボックス内のニーモニックは一意である必要はありません (しかし、 一意にした方がよいでしょう)。

ユーザーが文字キーや数字キーを押すと、 Windowsは、 まず、 現在入力フォーカスを持つコントロールがそのキーを処理するかどうかを判断します。Windowsは、 WM_GETDLGCODEメッセージをコントロールに送り、 コントロールがDLGC_WANTALLKEYSまたはDLG_WANTMESSAGEを返したら、 コントロールにそのキーを渡します。そうでないときは、 指定された文字または数字に一致するニーモニックを持つコントロールを探します。一致するコントロールを見つけるか、 すべてのコントロールを調べるまで、 検索は続きます。検索時は、 SS_NOPREFIXスタイルを持つスタティック コントロールは飛ばされます。

スタティック コントロールを見つけたときにそのコントロールが使用不能になっていなければ、 Windowsは、 そのスタティック コントロールの後の、 表示されていて使用不能ではなく、 WS_TABSTOPスタイルを持つ最初のコントロールにフォーカスを移動します。Windowsは、 一致するニーモニックを持つそれ以外のコントロールを見つけると、 入力フォーカスをそのコントロールに移動します。そのコントロールがデフォルト プッシュ ボタンならば、 Windowsは、 ダイアログ ボックス プロシージャにBN_CLICKED通知メッセージを送ります。コントロールがそれ以外のスタイルのボタンで、 同じニーモニックを持つコントロールがダイアログ ボックス内にほかになければ、 WindowsはBM_CLICKメッセージをそのコントロールに送ります。

 

 

ダイアログ ボックスの設定

ダイアログ ボックスの設定とは、 ダイアログ ボックス内のコントロールの現在の選択と値です。ダイアログ ボックス プロシージャは、 ダイアログ ボックスが作成されるときにこの設定をコントロールに対して行い、 初期化しなければなりません。また、 ダイアログ ボックス プロシージャは、 ダイアログ ボックスが破棄される前にコントロールから現在の設定を取得しなければなりません。設定の初期化と取得に使われる方法は、 コントロールの種類によって異なります。

 

オプション ボタンとチェック ボックス

ダイアログ ボックスでは、 オプションのリストからユーザーにオプションを選択させるためにオプション ボタン (ラジオ ボタンともいう) やチェック ボックスを使います。オプション ボタンの場合は、 相互に排他的なオプションを選択します。チェック ボックスの場合は、 オプションの組み合わせを選択します。

ダイアログ ボックス プロシージャは、 CheckDlgButton関数を使って、 チェック ボックスの初期状態を設定できます。この関数は、 チェック ボックスをセットまたはクリアします。相互に排他的なオプション ボタンのグループのなかのオプション ボタンに対しては、 CheckRadioButton関数を使って適切なオプション ボタンをセットできます。そのほかのオプション ボタンは自動的にクリアされます。

ダイアログ ボックス プロシージャは、 ダイアログ ボックスが終了する前に、 IsDlgButtonChecked関数を使って、 各オプション ボタンやチェック ボックスの状態を調べることができます。この関数は、 ボタンの現在の状態を返します。通常、 ダイアログ ボックスは、 この情報を保存しておいて、 次にダイアログ ボックスが作成されたときの初期化に使います。

 

エディット コントロール

ダイアログ ボックスには、 ユーザーが入力としてテキストを供給するためのエディット コントロールを持つものが多くあります。通常、 ダイアログ ボックス プロシージャは、 ダイアログ ボックスが最初に起動するときにエディット コントロールを初期化します。たとえば、 ダイアログ ボックス プロシージャは、 ファイル名の候補をコントロールに設定し、 ユーザーがそのファイル名を選択、 修正、 置換できるようにします。エディット コントロールにテキストを設定するには、 SetDlgItemText関数を使います。この関数は、 指定されたバッファからエディット コントロールにテキストをコピーします。エディット コントロールは、 入力フォーカスを受け取ると、 テキスト全体を編集用に自動的に選択します。

エディット コントロールはテキストをダイアログ ボックスに自動的には返さないため、 ダイアログ ボックス プロシージャは、 終了する前にテキストを取得しなければなりません。テキストを取得するには、 GetDlgItemText関数を使います。この関数は、 エディット コントロールのテキストをバッファにコピーします。通常、 ダイアログ ボックス プロシージャは、 このテキストを保存しておいて、 後でエディット コントロールを初期化するときに使ったり、 親ウィンドウに渡して処理させます。

ダイアログ ボックスには、 エディット コントロールを使ってユーザーに数値を入力させるものもあります。エディット コントロールから数値を取得するには、 GetDlgItemInt関数を使います。この関数は、 エディット コントロールからテキストを取得し、 そのテキストを10進値に変換します。ユーザーは、 数値を10進数で入力します。符号はあってもなくてもかまいません。整数を表示するには、 SetDlgItemInt関数を使います。SetDlgItemIntは、 符号付きまたは符号なしの整数を10進数文字列に変換します。

 

リスト ボックス、 コンボ ボックス、 ディレクトリ リスト

ダイアログ ボックスには、 ユーザーが名前を選択するためのリストを表示するものがあります。たとえば、 ファイル名のリストを表示するには、 リスト ボックスとDlgDirList関数やDlgDirSelect関数を使います。DlgDirList関数は、 現在のディレクトリのファイル名を自動的にリスト ボックスに設定します。DlgDirSelect関数は、 リスト ボックスで選択されているファイル名を取得します。この2つの関数を使うことによって、 ダイアログ ボックスにディレクトリのリストを簡単に表示でき、 ユーザーはファイルの位置と名前を入力せずにファイルを選択できるようになります。

また、 ダイアログ ボックスでは、 コンボ ボックスを使ってファイル名のリストを表示することもできます。DlgDirListComboBox関数は、 現在のディレクトリのファイル名をコンボ ボックスのリスト ボックス部分に自動的に設定します。DlgDirSelectComboBox関数は、 リスト ボックス部分で選択されているファイル名を取得します。

 

コントロール メッセージ

通常、 コントロールは、 何らかの動作を指示する定義済みメッセージを認識します。たとえば、 BM_SETCHECKメッセージはチェック ボックスにチェックを設定し、 EM_GETSELメッセージはコントロールで現在選択されているテキストの部分を取得します。ダイアログ ボックス プロシージャはコントロール メッセージを利用して標準関数では実現できない処理を行うことができるため、 コントロール メッセージは、 ユーザーとの複雑な対話が必要なダイアログ ボックスでよく使われます。

コントロールにメッセージを送るには、 コントロール識別子を指定してSendDlgItemMessage関数を呼び出します。この関数は、 メッセージを受け取るコントロールをウィンドウ ハンドルではなくコントロール識別子を使って識別することを除いて、 SendMessage関数と同じです。指定するメッセージによっては、 パラメータの指定が必要な場合もあります。また、 対応する戻り値がある場合もあります。各コントロール メッセージの処理と必要条件は、 メッセージの目的とそのメッセージを処理するコントロールによって異なります。

コントロール メッセージについて詳しくは、 コントロールの概要を参照してください。

 

 

カスタム ダイアログ ボックス

カスタム ダイアログ ボックスを作成するには、 定義済みダイアログ ボックス クラスではなくアプリケーション定義のウィンドウ クラスを使います。通常、 この方法は、 ダイアログ ボックスがアプリケーションのメイン ウィンドウであるときに使われますが、 標準のオーバーラップ ウィンドウを持つウィンドウでモーダルやモードレスのダイアログ ボックスを作成するときにも役立ちます。

アプリケーションは、 アプリケーション定義のウィンドウ クラスによって、 ダイアログ ボックスのウィンドウ プロシージャを定義し、 メッセージがダイアログ ボックス プロシージャに送られる前にメッセージを処理できます。また、 ダイアログ ボックスのクラス アイコンやクラス背景ブラシ、 クラス メニューをアプリケーションが定義できます。ウィンドウ クラスはダイアログ ボックスを作成する前に登録しなければならず、 そのウィンドウ クラスのアトム値または名前をダイアログ ボックス テンプレートに指定しなければなりません。

通常、 新しいダイアログ ボックス クラスを作成するには、 まず、 GetClassInfo関数に定義済みダイアログ ボックス クラスのクラス名を渡して、 クラス情報を取得します。この関数は、 WNDCLASS構造体に情報を設定します。アプリケーションは、 クラス名、 ブラシ、 アイコンなどの構造体の各メンバを修正し、 RegisterClass関数を使って新しいクラスを登録します。アプリケーションは、 自分自身のWNDCLASS構造体を設定するとき、 cbWndExtraメンバにDLGWINDOWEXTRAを設定しなければなりません。この値は、 Windowsが各ダイアログ ボックスについて必要とする拡張バイト数です。各ダイアログ ボックスについて拡張バイトを使用するアプリケーションは、 Windowsが必要とするバイト数に自分が必要とするバイト数を加えたバイト数を設定しなければなりません。

カスタム ダイアログ ボックスのウィンドウ プロシージャのパラメータと必要条件は、 ほかのウィンドウ プロシージャと同じです。しかし、 ほかのウィンドウ プロシージャとは異なり、 カスタム ダイアログ ボックスのウィンドウ プロシージャは、 処理しないメッセージに対してはDefWindowProc関数ではなくDefDlgProc関数を呼び出さなければなりません。DefDlgProcは、 ダイアログ ボックス プロシージャの呼び出しなど、 定義済みダイアログ ボックスのウィンドウ プロシージャによるデフォルト メッセージ処理と同じ処理を行います。

また、 定義済みのダイアログ ボックスのウィンドウ プロシージャをサブクラス化してカスタム ダイアログ ボックスを作成することもできます。SetWindowLong関数によって、 特定のウィンドウのウィンドウ プロシージャのアドレスを設定できます。SetClassLong関数を使ってサブクラス化することもできますが、 この関数は、 アプリケーションに属するダイアログ ボックスだけではなく、 システム中のすべてのダイアログ ボックスに影響を与えます。

カスタム ダイアログ ボックスを作成する場合は、 ダイアログ ボックスの代替キーボード インターフェイスを用意することがあります。モードレス ダイアログ ボックスの場合、 IsDialogMessage関数を呼び出さずに、 カスタム ウィンドウ プロシージャでキーボード入力をすべて処理します。そのような場合、 WM_NEXTDLGCTLメッセージを使って、 コントロール間で入力フォーカスを移動するのに必要なコードを最小限にすることができます。DefDlgProc関数は、 このメッセージを受け取ると、 指定されたコントロールに入力フォーカスを移動し、 デフォルト プッシュ ボタン境界線の移動や自動オプション ボタンの設定などのコントロールの外観の更新を行います。

 

 

ダイアログ ボックスの使用

ダイアログ ボックスは、 情報を表示したり、 ユーザーに入力を要求するときに使います。ダイアログ ボックスを使うには、 ダイアログ ボックスをロードして初期化し、 ユーザーの入力を処理します。ユーザーが作業を終えたら、 ダイアログ ボックスを破棄します。ダイアログ ボックスの処理は、 モーダルかモードレスかによって異なります。モーダル ダイアログ ボックスの場合、 ユーザーがダイアログ ボックスをクローズしなければ、 アプリケーションのほかのウィンドウをアクティブ化することはできません。しかし、 ユーザーは、 ほかのアプリケーションのウィンドウをアクティブ化することはできます。モードレス ダイアログ ボックスの場合は、 ユーザーはその場で応答する必要はありません。モードレス ダイアログ ボックスは、 コントロールを持つメイン ウィンドウのようなものです。

次に示すトピックでは、 この両方のダイアログ ボックスの使い方を説明します。各トピックをクリックすると、 そのトピックの内容を表示できます。

 

メッセージ ボックスの表示

モーダル ダイアログ ボックスの作成

モードレス ダイアログ ボックスの作成

ダイアログ ボックスの初期化

メモリ内のテンプレートの作成

 

 

メッセージ ボックスの表示

モーダル ダイアログ ボックスの最も簡単な形がメッセージ ボックスです。通常、 メッセージ ボックスは、 ユーザーにエラーを知らせたり、 エラーの後の処理に関する指示を受けるために使われます。メッセージ ボックスを作成するには、 メッセージと表示するボタンの個数と種類を指定してMessageBox関数またはMessageBoxEx関数を呼び出します。Windowsは、 専用のダイアログ ボックス テンプレートとダイアログ ボックス プロシージャを使ってモーダル ダイアログ ボックスを作成します。ユーザーがメッセージ ボックスをクローズすると、 MessageBoxまたはMessageBoxExは、 ユーザーがメッセージ ボックスをクローズするのに使ったボタンを識別する値を返します。

次の例は、 fError変数がTRUEならばメッセージ ボックスを表示します。メッセージ ボックスには、 エラーを記述するメッセージが表示されます。MB_OKCANCELスタイルによって、 処理方法をユーザーが選択するための2つのボタンを用意するようにMessageBoxに指示しています。

 

if (fError) {
if (MessageBox(hwndDlg, SZNOTFOUND, SZDELETEITEM,
MB_OKCANCEL)==IDOK)

.
. /* Prompt for a new item name and repeat the command. */
.

else

.
. /* Cancel the command. */
.

}

上記の例で、 SZNOTFOUNDとSZDELETEITEMは、 アプリケーション定義のNULLで終わる文字列で、 メッセージ テキストとメッセージ ボックスのタイトルを示します。

 

 

モーダル ダイアログ ボックスの作成

モーダル ダイアログ ボックスを作成するには、 DialogBox関数を使います。この関数には、 ダイアログ ボックス テンプレート リソースの識別子または名前と、 ダイアログ ボックス プロシージャのアドレスを指定します。DialogBox関数は、 テンプレートをロードしてダイアログ ボックスを表示し、 ユーザーがダイアログ ボックスをクローズするまでユーザー入力をすべて処理します。

次の例は、 ユーザーがメニューから[Delete Item]コマンドを選択するとモーダル ダイアログ ボックスを表示します。ダイアログ ボックスには、 (項目の名前を入力するための) エディット コントロール、 [OK]ボタン、 [キャンセル]ボタンがあります。これらのコントロールのコントロール識別子は、 それぞれ、 ID_ITEMNAME、 IDOKIDCANCELです。

この例の最初の部分では、 モーダル ダイアログ ボックスを作成しています。アプリケーションのメイン ウィンドウのウィンドウ プロシージャでは、 IDM_DELETEITEMコマンド識別子が設定されたWM_COMMANDメッセージを受け取るとダイアログ ボックスを作成します。この例の後の部分はダイアログ ボックス プロシージャです。ダイアログ ボックス プロシージャは、 WM_COMMANDメッセージを受け取ると、 エディット コントロールの内容を取得し、 ダイアログ ボックスをクローズします。

次の文はモーダル ダイアログ ボックスを作成します。ダイアログ ボックス テンプレートはアプリケーションの実行可能ファイル内にあるリソースで、 リソース識別子はDLG_DELETEITEMです。

 

case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDM_DELETEITEM:
if (DialogBox(hinst, MAKEINTRESOURCE(DLG_DELETEITEM),
hwnd, (DLGPROC)DeleteItemProc)==IDOK)

.
. /*
. * Complete the command; szItemName contains
. * the name of the item to delete.
. */
.

else
.
. /* Cancel the command. */
.

break;
}
return 0L;

上記の例では、 ダイアログ ボックスのオーナー ウィンドウとしてアプリケーションのメイン ウィンドウを指定しています。Windowsがダイアログ ボックスを最初に表示するとき、 ダイアログ ボックスの位置はオーナー ウィンドウのクライアント領域の左上隅に相対になります。DialogBoxの戻り値は、 コマンドを続行するか取り消すかを判断するために使われます。次の文は、 ダイアログ ボックス プロシージャを定義しています。

 

char szItemName[80]; /* receives name of item to delete. */


BOOL CALLBACK DeleteItemProc(hwndDlg, message, wParam, lParam)
HWND hwndDlg;
UINT message;
WPARAM wParam;
LPARAM lParam;
{
switch (message) {
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
if (!GetDlgItemText(hwndDlg, ID_ITEMNAME,
szItemName, 80))
*szItemName=0;

/* Fall through. */

case IDCANCEL:
EndDialog(hwndDlg, wParam);
return TRUE;
}
}
return FALSE;
}

上記の例では、 ダイアログ ボックス プロシージャは、 GetDlgItemText関数を使って、 ID_ITEMNAMEで識別されるエディット コントロールから現在のテキストを取得しています。それから、 EndDialog関数を呼び出して、 受け取ったメッセージに応じてダイアログ ボックスの戻り値をIDOKまたはIDCANCELに設定し、 ダイアログ ボックスのクローズ処理を開始します。IDOK識別子とIDCANCEL識別子は、 [OK]ボタンと[キャンセル]ボタンに対応します。ダイアログ ボックス プロシージャがEndDialogを呼び出すと、 Windowsは、 プロシージャにさらにメッセージを送ってダイアログ ボックスを破棄し、 ダイアログ ボックスを作成した関数にダイアログ ボックスの戻り値を返します。

 

 

モードレス ダイアログ ボックスの作成

モードレス ダイアログ ボックスを作成するには、 ダイアログ ボックス テンプレートの識別子または名前とダイアログ ボックス プロシージャのアドレスを指定してCreateDialog関数を呼び出します。CreateDialogは、 テンプレートをロードしてダイアログ ボックスを作成し、 オプションでダイアログ ボックスを表示します。ダイアログ ボックス プロシージャに対するユーザー入力メッセージの取得とディスパッチは、 アプリケーションが行わなければなりません。

次の例は、 ユーザーがメニューから[Go To]コマンドを選択したときに、 モードレス ダイアログ ボックスがまだ表示されていなければ表示します。ダイアログ ボックスには、 エディット コントロール、 チェック ボックス、 [OK]ボタン、 [キャンセル]ボタンがあります。ダイアログ ボックス テンプレートはアプリケーションの実行可能ファイル内のリソースで、 リソース識別子はDLG_GOTOです。ユーザーは、 エディット コントロールに行番号を入力したり、 行番号が現在の行からの値であることを示すチェック ボックスをチェックできます。コントロール識別子は、 ID_LINE、 ID_ABSREL、 IDOK IDCANCELです。

例の最初の部分は、 モードレス ダイアログ ボックスを作成します。アプリケーションのメイン ウィンドウのウィンドウ プロシージャでは、 IDM_GOTOコマンド識別子が設定されたWM_COMMANDメッセージを受け取ると、 グローバル変数hwndGotoに有効なハンドルがまだ設定されていなければ、 ダイアログ ボックスを作成します。例のその次のの部分は、 アプリケーションのメイン メッセージ ループです。ループ内では、 IsDialogMessage関数を使って、 モードレス ダイアログ ボックス内でもユーザーがダイアログ ボックス キーボード インターフェイスを使えるようにしています。例の最後の部分は、 ダイアログ ボックス プロシージャです。ユーザーが[OK]ボタンを選択すると、 ダイアログ ボックス プロシージャは、 エディット コントロールとチェック ボックスの内容を取得します。ユーザーが[キャンセル]ボタンを選択すると、 ダイアログ ボックス プロシージャはダイアログ ボックスを破棄します。

 

HWND hwndGoto = NULL; /* window handle of dialog box */

.
.
.

case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDM_GOTO:
if (!IsWindow(hwndGoto)) {
hwndGoto = CreateDialog(hinst,
MAKEINTRESOURCE(DLG_GOTO),
hwnd, (DLGPROC) GoToProc);
ShowWindow(hwndGoto, SW_SHOW);
}
break;
}
return 0L;

上記の例では、 hwndGoto変数に有効なウィンドウ ハンドルが設定されていないときだけCreateDialog関数を呼び出します。これによって、 同時に2つのダイアログ ボックスが表示されないようにしています。このチェック方法を使うには、 ダイアログ ボックスを破棄するときにhwndGoto変数にNULLを設定しなければなりません。

アプリケーションのメッセージ ループは、 次に示す文で構成されます。

 

while (GetMessage(&msg, NULL, NULL, NULL)) {
if (!IsWindow(hwndGoto) || !IsDialogMessage(hwndGoto, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

}

このループは、 ダイアログ ボックスのハンドルが有効かどうかチェックして、 ハンドルが有効ならばIsDialogMessage関数を呼び出します。IsDialogMessageは、 ダイアログ ボックスに対するメッセージだけを処理します。メッセージがダイアログ ボックスに対するものでなければ、 この関数はFALSEを返し、 ループはメッセージを適切なウィンドウにディスパッチします。

次の例は、 ダイアログ ボックス プロシージャを定義しています。

 

int iLine; /* receives line number */
BOOL fRelative; /* receives check box status */

.
.
.

BOOL CALLBACK GoToProc(hwndDlg, message, wParam, lParam)
HWND hwndDlg;
UINT message;
WPARAM wParam;
LPARAM lParam;
{
BOOL fError;

switch (message) {
case WM_INITDIALOG:
CheckDlgButton(hwndDlg, ID_ABSREL, fRelative);
return TRUE;

case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
fRelative = IsDlgButtonChecked(hwndDlg, ID_ABSREL);
iLine = GetDlgItemInt(hwndDlg, ID_LINE, &fError,
fRelative);
if (fError) {
MessageBox(hwndDlg, SZINVALIDNUMBER,
SZGOTOERR, MB_OK);
SendDlgItemMessage(hwndDlg, ID_LINE,
EM_SETSEL, 0, -1L);
} else

.
. /*
. * Notify the owner window to carry out the
. * command.
. */
.


return TRUE;

case IDCANCEL:
DestroyWindow(hwndDlg);
hwndGoto = NULL;
return TRUE;
}
}
return FALSE;
}

上記の例では、 WM_INITDIALOGメッセージとWM_COMMANDメッセージを処理しています。WM_INITDIALOGを処理するときは、 ローカル変数fRelativeの現在の値をCheckDlgButton関数に渡して、 チェック ボックスを初期化します。それから、 TRUEを返して、 Windowsにデフォルトの入力フォーカスを設定させます。

WM_COMMANDを処理するときは、 ユーザーが[キャンセル]ボタン (IDCANCEL識別子を持つボタン) を選択したときだけダイアログ ボックスをクローズします。モードレス ダイアログ ボックスをクローズするには、 DestroyWindow関数を呼び出さなければなりません。また、 hwndGoto変数を利用するほかのコードが正しく動作するようにするため、 hwndGotoにNULLを設定しています。

ユーザーが[OK]ボタンを選択すると、 チェック ボックスの現在の状態を取得してfRelative変数に設定します。それから、 その変数を使って、 エディット コントロールから行番号を取得します。GetDlgItemInt関数は、 エディット コントロールのテキストを整数値に変換します。この関数は、 fRelativeの値に応じて、 数値を符号付きまたは符号なしとして解釈します。エディット コントロールのテキストが有効な数値でないときは、 GetDlgItemIntfError変数に0以外の値を設定します。プロシージャは、 この値を調べて、 エラー メッセージを表示するかコマンドを実行するかを判断します。エラーの場合は、 ダイアログ ボックス プロシージャはエディット コントロールにメッセージを送って、 ユーザーがテキストを置き換えやすいようにコントロールのテキストを選択させます。GetDlgItemInt関数がエラーを返さなければ、 ダイアログ ボックス プロシージャは、 要求されたコマンドを自分自身で実行するか、 オーナー ウィンドウにメッセージを送ってコマンドを実行させます。

 

 

ダイアログ ボックスの初期化

WM_INITDIALOGメッセージを処理するときは、 ダイアログ ボックスとその内容を初期化します。最もよく行われる作業は、 現在のダイアログ ボックスの設定を反映するようにコントロールを初期化することです。もう1つの一般的な作業は、 ダイアログ ボックスを画面またはオーナー ウィンドウの中心に置くことです。最後に、 デフォルトの入力フォーカスを使わずに特定のコントロールに入力フォーカスを設定することがあります。

次の例のダイアログ ボックス プロシージャは、 WM_INITDIALOGメッセージの処理で、 ダイアログ ボックスを中心に置き、 入力フォーカスを設定しています。ダイアログ ボックスを中心に置くには、 ダイアログ ボックスとオーナー ウィンドウのウィンドウ長方形を取得し、 ダイアログ ボックスの新しい位置を計算します。入力フォーカスを設定するには、 wParamパラメータを調べて、 デフォルトの入力フォーカスの識別子を判断します。

 

HWND hwndOwner;
RECT rc, rcDlg, rcOwner;

case WM_INITDIALOG:
/* Get the owner window and dialog box rectangles. */

if ((hwndOwner = GetParent(hwndDlg)) == NULL)
hwndOwner = GetDesktopWindow();
GetWindowRect(hwndOwner, &rcOwner);
GetWindowRect(hwndDlg, &rcDlg);
CopyRect(&rc, &rcOwner);

/*
* Offset the owner and dialog box rectangles so that
* right and bottom values represent the width and
* height, and then offset the owner again to discard
* space taken up by the dialog box.
*/

OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top);
OffsetRect(&rc, -rc.left, -rc.top);
OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);

/*
* The new position is the sum of half the remaining
* space and the owner's original position.
*/

SetWindowPos(hwndDlg,
HWND_TOP,
rcOwner.left + (rc.right / 2),
rcOwner.top + (rc.bottom / 2),
0, 0, /* ignores size arguments */
SWP_NOSIZE);

if (GetDlgCtrlID((HWND) wParam) != ID_ITEMNAME) {
SetFocus(GetDlgItem(hwndDlg, ID_ITEMNAME));
return FALSE;
}
return TRUE;

上記の例では、 GetParent関数を使ってダイアログ ボックスのオーナー ウィンドウのハンドルを取得しています。この関数は、 ダイアログ ボックスの場合はオーナー ウィンドウのハンドル、 子ウィンドウの場合は親ウィンドウのハンドルを返します。オーナーを持たないダイアログ ボックスを作成することもできるため、 ダイアログ ボックス プロシージャでは、 返されたハンドルを調べて、 必要ならばGetDesktopWindow関数を使ってデスクトップ ウィンドウのハンドルを取得しています。新しい位置を計算したら、 ダイアログ ボックスをオーナー ウィンドウよりも前に表示するためのHWND_TOPを指定してSetWindowPos関数を呼び出し、 ダイアログ ボックスを移動します。

入力フォーカスを設定する前に、 デフォルトの入力フォーカスのコントロール識別子を調べます。Windowsは、 デフォルトの入力フォーカスのウィンドウ ハンドルをwParamパラメータで渡します。GetDlgCtrlID関数は、 ウィンドウ ハンドルが識別するコントロールのコントロール識別子を返します。識別子が正しい識別子と一致しなければ、 SetFocus関数を使って入力フォーカスを設定します。特定のコントロールのウィンドウ ハンドルを取得するには、 GetDlgItem関数が必要です。

 

 

 

メモリ内のテンプレートの作成

処理中のデータの状態に応じて、 ダイアログ ボックスの内容を変更する場合があります。そのような場合、 考えられる場合すべてについてダイアログ ボックス テンプレートをアプリケーションの実行可能ファイルのリソースとして用意するのは現実的ではありません。しかし、 テンプレートをメモリ内で作成することによって、 アプリケーションはさまざまな状況により柔軟に対応できます。

次の例は、 メッセージと[OK]ボタン、 [Help]ボタンを含むモーダル ダイアログ ボックスのテンプレートをメモリ内に作成します。

 

LRESULT DisplayMyMessage(HINSTANCE hinst, HWND hwndOwner, LPSTR lpszMessage)
{

HGLOBAL hgbl;
LPDLGTEMPLATE lpdt;
LPDLGITEMTEMPLATE lpdit;
LPWORD lpw;
LPWSTR lpwsz;
LRESULT ret;

hgbl = GlobalAlloc(GMEM_ZEROINIT, 1024);
if (!hgbl)
return -1;

lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);

/* Define a dialog box. */

lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
| DS_MODALFRAME | WS_CAPTION;
lpdt->cdit = 3; /* number of controls */
lpdt->cdit = 1;
lpdt->x = 10; lpdt->y = 10;
lpdt->cx = 100; lpdt->cy = 100;

lpw = (LPWORD) (lpdt + 1);
*lpw++ = 0; /* no menu */
*lpw++ = 0; /* predefined dialog box class (by default) */

lpwsz = (LPWSTR) lpw;
lstrcpyW(lpwsz, L"My Message"); /* dialog box title (Unicode) */
lpw = (LPWORD) (lpwsz + lstrlenW(lpwsz) + 1);

/* Define an OK button. */

lpdit = (LPDLGITEMTEMPLATE) lpw;
lpdit->x = 10; lpdit->y = 10;
lpdit->cx = 40; lpdit->cy = 20;
lpdit->id = IDOK; /* OK button identifier */
lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON;

lpw = (LPWORD) (lpdit + 1);
*lpw++ = 0xFFFF;
*lpw++ = 0x0080; /* button class */

lpwsz = (LPWSTR) lpw;
lstrcpyW(lpwsz, L"OK"); /* button label (Unicode) */
lpw = (LPWORD) (lpwsz + lstrlenW(lpwsz) + 1);
*lpw++ = 0; /* no creation data */

/* Define a Help button. */

lpdit = (LPDLGITEMTEMPLATE) lpw;
lpdit->x = 55; lpdit->y = 10;
lpdit->cx = 40; lpdit->cy = 20;
lpdit->id = ID_HELP; /* help button identifier */
lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON;

lpw = (LPWORD) (lpdit + 1);
*lpw++ = 0xFFFF;
*lpw++ = 0x0080; /* button class atom */
lpwsz = (LPWSTR) lpw;
lstrcpyW(lpwsz, L"Help"); /* button label (Unicode) */
lpw = (LPWORD) (lpwsz + lstrlenW(lpwsz) + 1);
*lpw++ = 0; /* no creation data */

/* Define a static text control. */

lpdit = (LPDLGITEMTEMPLATE) lpw;
lpdit->x = 55; lpdit->y = 10;
lpdit->cx = 40; lpdit->cy = 20;
lpdit->id = ID_TEXT; /* text identifier */
lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;

lpw = (LPWORD) (lpdit + 1);
*lpw++ = 0xFFFF;
*lpw++ = 0x0082; /* static class */
for (lpwsz = (LPWSTR) lpw;
*lpwsz++ = (WCHAR) *lpszMessage++; /* message (Unicode) */
);
lpw = (LPWORD) lpwsz;
*lpw++ = 0; /* no creation data */

GlobalUnlock(hgbl);

ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,
hwndOwner, (DLGPROC) DialogProc);

GlobalFree(hgbl);

return ret;

}

 

 

ダイアログ ボックス関数とメッセージ

ダイアログ ボックスやダイアログ ボックス内のコントロールの作成と管理に使われる関数とメッセージを次に示します。

CreateDialog

CreateDialogIndirect

CreateDialogIndirectParam

CreateDialogParam

DefDlgProc

DialogBox

DialogBoxIndirect

DialogBoxIndirectParam

DialogBoxParam

DialogProc

EndDialog

GetDialogBaseUnits

GetDlgCtrlID

GetDlgItem

GetDlgItemInt

GetDlgItemText

GetNextDlgGroupItem

GetNextDlgTabItem

IsDialogMessage

MapDialogRect

MessageBox

MessageBoxEx

SendDlgItemMessage

SetDlgItemInt

SetDlgItemText

WM_CTLCOLORMSGBOX

WM_ENTERIDLE

WM_GETDLGCODE

WM_INITDIALOG

WM_NEXTDLGCTL

 

 

 

ダイアログ ボックス構造体

ダイアログ ボックスやダイアログ ボックス内のコントロールの作成と管理に使われる構造体を次に示します。

 

DLGITEMTEMPLATE

DLGTEMPLATE

 

▲ページトップに戻る

【本を読んでもよくらからない】 … 個別指導でわかりやすくお教えします