WindowsのMFCに入門してみる
ちょっと忙しくてブログを投稿する気が起きなかったが、それもいかんなと思い、少し前に調べたMFCの調査メモを適当に整理したものを投稿する。
はじめに
Windowsでデスクトップアプリを作成するとしたら、MFCやWindows Form、WPF、UWPなどが挙げられたりするが、訳あって今回はMFCにを触ってみる。
なお、今回は入門的な位置づけだが、主にダイアログアプリケーションの作成の本当に基本的な部分のみを触る。そのため、以下のような高度(?)な機能などは触らない。
分割ウィンドウ
プロパティシート
(リソースファイルを使わない)ダイアログの動的生成
画面遷移
動作はWindows 10におけるVisual Studio 2022で確認している。また、今回作成分のコードは以下にzipで圧縮したものを置いてある。
環境構築
まずは、MFCのプロジェクトを立ち上げることができるようにするための具体的手順を示す。
Visual Studio Installerを起動
Visual Studio 2022の変更に関する項目を選択
「C++によるデスクトップ開発」を選択
右のチェックリストにあるC++ MFCに関する項目にチェックを入れる
インストールを実施
これで、MFCのプロジェクトが作成可能になる。次に、MFCによるダイアログアプリケーションのプロジェクトを立ち上げる手順を示す。
MFCで検索をかけることにより「MFC アプリ」という項目が見つかるため、それを選択
他のプロジェクトと同じようにプロジェクトの設定を行う
プロジェクトの設定を行う過程でMFCアプリケーションの構成を尋ねられるため、「アプリケーションの種類」をダイアログベースを選択し、「完了」ボタンを押下
これでプロジェクトの作成が完了する。後は、F5でも押してビルドをすると、初期状態のダイアログとボタンが表示されるだけのプログラムが起動する。
なお、今回はMFCTest
という名前のプロジェクトを作成した。
簡単なGUIとイベントの設置
基本的には、以下の画像の左にあるようなツールボックス(ツールボックスの配置はVisual Studioの利用者の環境依存)からドラッグ&ドロップによりGUIを直接設置していくことができる。
ボタン
まずは、ボタンを設置してみる。ボタンに表示されるテキストについては「プロパティ」の「キャプション」(下画像の左のリストのハイライトされている項目)から設定をすることができる。
そして、設置したボタンをダブルクリックすると、C++のソースにジャンプし、ボタンクリックについてのイベントハンドラが生成される。そのイベントとして、メッセージボックスを設置してみる。
これを実行して「ボタン」ボタンを押下すると以下のようなメッセージボックスが表示され、「はい」を押さない限りずっと表示される。
チェックボックス
チェックボックスについてもボタンと同じ要領で設置をし、イベントを定義することができるため、適当に機能を作ってみる。機能の概要についてはコメントの通りである。
これを実行して適当なチェックボックスにチェックを入れると、隣接するチェックボックスの中身が反転する。
ラジオボタン
ラジオボタンの設置についてはラジオボタンの生成順序が重要である。まず、以下のような2つのラジオボタンのグループを生成することを考える。「Radio1」のような各文字列はラジオボタンのIDである。
「Radio1」、「Radio2」、「Radio3」
「Radio4」、「Radio5」、「Radio6」
そして、「Radio1」から連番で「Radio6」までのラジオボタンを順番に生成する。そして、「Radio1」と「Radio6」について、「プロパティ」の「グループ」をTrueに設定する。
これにより2つのラジオボタンのグループが生成される。
これでラジオボタンの操作ができるようになる。プログラム上からラジオボタンを操作するサンプルとして、チェックボックスをクリックすることで、ラジオボタンのチェックを移動させるという処理を追加してみる。
これを実行して適当なラジオボタンを選択すると、ラジオボタンのグループが2つ存在することが確認できる。また、「Check3」のチェックボックスをクリックすることにより、ラジオボタンの選択要素が次に移動する事が確認できる。
MFCは単なるWindows APIのラッパーであるため、配置をしたダイアログの要素についてはリソースエディタから編集をすることができる。リソースエディタについてはソリューションエクスプローラの「リソースファイル」を展開し、リソースファイルを右クリックして「コードの表示」をクリックすることにより確認をすることができる。
その中の現段階におけるダイアログの構成は以下の部分である。これを見ればわかる通り、要素を定義した順番に列挙されていることが分かる。
もちろん、これを直接触ることにより調整も可能である。ここで着目するのは、IDC_RADIO1
からIDC_RADIO6
の部分である。この要素が作成したラジオボタンのハンドラであり、IDC_RADIO1
とIDC_RADIO4
についてはWS_GROUP
というフラグがついている。Windows APIにおけるグループとはWS_GROUPが指定された要素をから次のWS_GROUPが指定された要素(存在しないならば終端要素)までを1つのグループとして扱うため、定義の順番が重要であるということである。
エディットコントロール・スタティックテキスト
エディットコントロールとはいわゆるテキストボックスであり、スタティックテキストはただのテキストを表示するものである。エディットコントロールに関連して、リッチエディット2.0コントロール(以後単にリッチエディットコントロールとする)というものががあるが、これはエディットコントロールをリッチにしたものであり、書式の利用ができる。これら3つの要素を設置してみる。作成内容としては以下の内容とする。
エディットコントロールとリッチエディットコントロールの変更を検知したとき、入力したテキストをスタティックテキストへ反映させる。
リッチエディットコントロールでは
<
と>
で囲まれた文字列をURLと判断してハイパーリンクを設置する。
エディットコントロールとリッチエディットコントロールには「複数行」と「戻り値が必要」、「自動 VScroll」、「水平スクロール」「垂直スクロール」をTrueに設定する。注意点としては 「戻り値が必要」をTrueにすることが改行を入力するための指定である。
また、 テキストの変更を要するスタティックテキストにはIDを自分で付ける必要がある(今回はIDC_STATIC2
とした)。
というわけで、実際に実装をしてみる。まず、リッチエディットコントロールの利用には共有ライブラリの読み込みが必要であるため、C[プロジェクト名]App::InitInstance()
で共有ライブラリの読み込みと開放を行う。今回作成したプロジェクトの名前はMFCTest
であるためCMFCTestApp::InitInstance()
で行えばいい。
また、リッチエディットコントロールは初期状態ではイベントを発火してくれないため、イベントマスクを設定する必要がある。そのため、C[プロジェクト名]Dlg::OnInitDialog()
でイベントマスクの設定を行う。今回作成したプロジェクトの名前はMFCTest
であるためCMFCTestDlg::OnInitDialog()
で行えばいい(メインのウィンドウのGUIの初期化の記述はCMFCTestDlg::OnInitDialog()
で記述する必要がある)。
次にイベントを設置していく。まずは、エディットコントロールとリッチエディットコントロールの変更内容をスタティックテキストへ反映し、リッチエディットコントロールでハイパーリンクを生成するイベントを設置する。イベントの設置方法はこれまでと同様にして、設置したGUIをダブルクリックするだけである。 イベントの実施内容のプログラムについては以下の通りである。特に、FindText()
のフラグの指定には要注意である。
次に、リッチエディットコントロールでのハイパーリンククリック時のイベントを定義する。エディタ上で対象となるリッチエディットコントロールを右クリックすると、「イベントハンドラーの追加」というものがあるため、これを選択する。
これによりダイアログが出現し、以下の設定をして「OK」を押下するとイベントが定義される。このイベントの定義方法はダブルクリックによりイベントを生成するよりも一般的な定義方法であり、ダブルクリックにより自動的に生成されるイベントは、この方法では「メッセージの種類」でEN_CHANGE
を選択することで、同様のイベントが生成される。
リンクの起動に関するイベントの実装は以下のとおりである。
メニューバー・ツールバー
ダイアログの領域が圧迫されてきたので、先にメニューバーを作っておく。まずは、リソースビューのソリューションの配下にあるMF[プロジェクト名].rc
を右クリックし、リソースの追加を選択する。
すると、作成可能なリソースの種類が表示されるので「Menu」を選択肢、「新規作成」を押下する。
あとは直観的にメニューバーを構築することができる(ちなみに下画像で表示されている項目以外は作成していない)。Altキーによるショートカットを指定するときは、項目名に「Menu1(&A)」と入力する。この場合はAlt+Aで「Menu1」が開くことを意味する。メニューの「プロパティ」で「区切り」をTrueにすると区切り線が表示される。
作成したメニューバーをダイアログにドッキングするには、ダイアログのプロパティの「メニューバー」の部分に作成したメニューバーのIDを指定すればいい(下画像でハイライトされている部分)。
ツールバーの作成についてはメニューバーの作成ほど簡単にはいかない。第一の方法としてリソースの追加からツールバーを選択して作成することが考えられるが、これはダイアログにはドッキングすることは(おそらく)できない。また、仮にできたとしてもWindows標準のビットマップ(アイコン)については外部から直接インポートしてこない限り利用することはできない。そのため、プログラム上で作成をする必要がある。
早速ツールバーを作成してみる。今回はWindows標準のビットマップを利用する。CMFCTestDlg
のメンバ変数としてツールバーのハンドルを定義し、その後、実装を行う。ツールバーの構築を行う箇所についてはリッチエディットコントロールでマスクの設定をした場所と同様のCMFCTestDlg::OnInitDialog()
で行う。
STD_FILENEW
といったマクロはWindows標準で与えられているビットマップのインデックスが与えられており、ID_FILE_NEW
のようなIDについてのマクロはWindows標準で定義されているコマンドを割り当てている。また、読み込むビットマップについてはHINST_COMMCTRL
でWindows標準のものを用いることを宣言し、IDB_STD_SMALL_COLOR
に対応する画像を読み込んでいる。これらのようなWindows標準のものに対する詳細は以下を参照せよ。
これを実行すると以下のようなダイアログが表示され、メニューバーとツールバーが作成されていることが確認できる。
次に、設置したメニューバーとツールバーにイベントを設置する。それぞれにおけるイベントはこれまでのような 「ダブルクリックによる追加」や「イベントハンドラーの追加」からは行うことはできない。この場合については 手動で設定をするか、クラスウィザードを介して自動で行う(推奨) という手段ある。
まず、メニューバーのイベントを 手動で 設置してみる。設置対象はSubMenu1
に対してである。まずは、イベントのプロトタイプとその実装を記述し、適当にメッセージボックスを出力するイベントを定義する。
後はイベントを作成したイベントをマッピングするだけである。
この段階のプログラムを実行し、メニューバーのSubMenu1
を選択することにより、以下のようなメッセージボックスの出現が確認できる。
次に、ツールバーのイベントをクラスウィザードを介して自動で 設置してみる。クラスウィザードについては、Visual Studioのメニューバーの「プロジェクト」から起動することができる。そして、以下の画像のように適切なクラス名を指定して、コマンドに対応するIDを指定をすることにより、イベントハンドラを生成することができる。
ツールバーのイベントの中身については、ファイルのアイコンがあるのだから、ファイルに関するダイアログのイベントを起動し、その対象となるファイルパスをメッセージボックスで表示させてみる。今回はファイルを開くイベントとファイルを保存する2つのイベントを設置する。そのイベントのプログラムは以下のとおりである。
分割ボタン
分割ボタンの配置については、チェックボックスやラジオボタンと同様に設置することができる。他と異なるのは、ドロップダウンする項目部をメニューバーの要領で作成する必要があることである。メニューバーについては以下のように構築する。「Title」とある部分についてはドロップダウンの項目にならない事に注意する必要がある。
あとは、適当に分割ボタンとメニューを関連付けることが考えられるが、以下の方法ではOnInitDialog()
終了時に例外が生じてしまう。
例外が発生してしまう要因は、
指定したコントロールまたは子ウィンドウへのポインター。 パラメーターによって指定された nID 整数 ID を持つコントロールが存在しない場合、値は NULL.
返されるポインターは一時的な場合があり、後で使用するために格納しないでください。
とあるように、あくまでもGetDlgItem()
で得られるポインタが一時的なものであることが原因であると考えられる(実際のところはわからない)。
これを解決するには、明示的にIDとメンバ変数を関連付ける操作をすればいい。その手順を示す。分割ボタンに対して右クリックをすると「変数の追加」とあるため、それを選択する。
そうすると、以下のような画面が出現するため、適当に設定を入力し「完了」ボタンを押下する。これにより、ダイアログのクラスにメンバ変数が生成され、DoDataExchange()
にデータ交換処理が追記される。
後は、分割ボタンとメニューの関連部を以下のように修正するだけである。
そもそもデータ交換の必要があるGUIの要素については変数を作っておいた方がいいというのもある。あまり何度もGetDlgItem()
でやるのはよくないだろう(変更の際のリファクタリングが面倒になる)。
イベントの設置については分割ボタンのボタン部はボタンのイベントと、メニュー部はメニューバーのものと同様に作成が可能であるため、今回は特には作成しない。
コンボボックス
次は、分割ボタンと見た目がよく似ているコンボボックスを設置してみる。コンボボックスは分割ボタンとは異なり、リストの項目をメニューで管理しないことが特徴である。
まずは、コンボボックスとスタティックテキストを設置する。今回は、コンボボックスの選択要素が変更されたらその情報をスタティックテキストへ反映するといった処理を実装する。そのため、スタティックテキストにはIDC_STATIC3
といったIDを割り振っておく。
コンボボックスの項目の追加については、
のようにコンボボックスの「プロパティ」の「データ」からセミコロン区切りで項目を追加をしたり、
のようにダイアログの初期化において実施してもよい。
イベントの追加については設置したコンボボックスをダブルクリックすることによりイベントハンドラが自動生成されるため、そこに実施内容を記述する。
かなり素直にイベントを記述できるため簡単である。適当にitem 4
を選択した場合の実行結果以下のとおりである。
タブコントロール
順番的には他の要素の説明をした方がいいと思うが、ダイアログの領域が狭くなってきたのでタブを作成する。まずは、初期状態で存在している邪魔なスタティックテキストをようやく削除する。
タブコントロールの作成方法は以下の通りである。
タブを設置するダイアログにタブコントロールを設置
タブの中身となる子ダイアログを作成
タブに子ダイアログを登録
まずは、ダイアログにタブコントロールを設置する。
次に、タブの中身となる子ダイアログを作成する。ダイアログのプロパティとしては、「タイトルバー」をFalse、「スタイル」を子、「境界線」をなし、「静的エッジ」をTrueのように設定する。このようなダイアログを3つ作成する。
次に、ダイアログを示すクラスを作成する。ダイアログを右クリックすると、「クラスの追加」があるため、それをクリックする。
そうしたら以下のようなダイアログが出現するため、適当に項目を設定し、「OK」を押下する。この操作は作成した全てのダイアログについて行う。
後は、作成したタブコントトールに対してタブを与え、そのタブにダイアログを割り当てればいい。まずは、各タブに割り当てるダイアログのハンドルを示すメンバ変数をダイアログのクラスに割り当てる。
次に、ダイアログの初期化部で前述したとおりの操作を記述する。
後は、タブの切り替えのイベントの記述である。イベントの追加については他と同様に設置したタブコントロールをダブルクリックすることによりイベントハンドラが自動生成されるため、そこに実施内容を記述する。
プログラムを起動し、適当にタブ2を選択すると、以下のようにタブが切り替わりタブコントロールが機能していることが確認できる。
ポップアップメニュー
ここでのポップアップメニューとは、右クリックで表示させるメニューのことを指す。ポップアップメニューの作成方法は分割ボタンと同様にして、リソースでメニューを作成する。
最も安直な方法としては、ダイアログのクラスのメンバ関数であるOnContextMenu()
をオーバーライドするという方法である。クラスウィザードからメッセージON_WM_CONTEXTMENU
のハンドラを追加する処理を行うことで、OnContextMenu()
を自動生成してくれる。
イベントの中身のプログラムについては以下の通り。
これを実行して適当な場所で右クリックをすると、実装をしたポップアップメニューが表示される。
また、要素が重なっている際のポップアップメニューの表示の優先順位は標準では子のダイアログの方が高く、例えば、タブに埋め込んだダイアログに対してOnContextMenu()
を実装すると、子のダイアログのOnContextMenu()
が呼び出される。より端的に表現すると、要素の親子関係においてダイアログは自動的に親子関係をもとに子のOnContextMenu()
を呼び出すが、ボタンなどに関しては勝手には呼び出されない。そのため、親が明示的にOnContextMenu()
の引数の情報をもとに呼び出す必要がある。
これの実装例については、ツリーコントロールの作成にて行っている。
リストボックス
リストボックスはコンボボックスをシリアライズしたようなものである。なので設置も非常に容易である。機能的な違いとしては複数の要素を選択できることである。また、リソースエディタから要素の設定をすることはできない。
今回はリストボックスをタブ1に設置することにする。
中央にあるボタンと右にあるエディットコントロールについては、リストボックスで何かしら選択されている状態でボタンをクリックするとエディットコントロールに反映するというものを実装するために用いる。
次に、初期値を設定する。これについては少し注意が必要で、タブ1についてのダイアログ、すなわちCTab1Page1Dlg::OnInitDialog()
で行う必要がある。デフォルトの生成ではこれが定義されないため適宜オーバーライド(クラスウィザードから作成可能)して、以下のような実装を記述する。
最後にイベントを設置する。今まで通り、ボタンのクリックイベントハンドラを生成し、イベントの中身を実装をする。その中身は以下のとおりである。
プログラムを実行し、リストボックスの要素を選択して矢印ボタンを押下すると、リストボックスの選択された要素のテキストがエディットコントロールへ反映されることが確認できる。
リストコントロール
リストコントロールはリストボックスを高度にしたものであり、プロパティの「ビュー」で様々な形式で表示を指定することができる。今回はテーブル形式のデータの表示に優れる「レポート」を選択した。また、リストコントロールはタブ3に設置する。スタティックテキストについては現在の選択状況をリアルタイムで反映するための要素である。
データの追加については、リストボックスと同様に個別のタブ(今回の場合ならCTab1Page3Dlg::OnInitDialog()
)に記述をする。
リストコントロールの定義の冒頭で行っている拡張スタイルの詳細については以下を参照せよ。
イベントの追加については他と同様に設置したリストコントロールをダブルクリックすることによりイベントハンドラが自動生成されるため、そこに実施内容を記述する。
また、ヘッダをクリックした際のイベントも定義してみる。ヘッダのクリックについては「イベントハンドラーの追加」からLVN_COLUMNCLICK
を指定してイベントを定義する。
今回実装する動作としては、ヘッダをクリックした際は行の選択を全て解除して、スタティックテキストに選択した列の内容を反映する。
プログラムを実行して行を選択すると、その情報がスタティックテキストへ反映されることがわかる。また、その状態から列を選択すると行の選択状態がクリアされ、列の選択に関する情報が表示されることが確認できる。
ツリーコントロール
ツリーコントロールはリストボックスに階層構造を持たせる方向で高度にしたものである。プロパティについては、ツリーコントロールの階層構造を開閉ボタンの設置のために「ボタンあり」をTrue、階層構造に関する罫線を表示するために「行あり」をTrueに設定する。
ツリーコントロールを右クリックによるポップアップメニューを用いて制御を行いたいため、出現させるメニューを定義する。今回はツリーに対して要素の挿入と削除を行うために、それに関する項目を定義する。また、「削除」に関するIDはID_MYTREE_DELETE
、「次に挿入」に関するIDはID_MYTREE_INSERT_NEXT
、「子に挿入」に関するIDはID_MYTREE_INSERT_CHILD
のようにした。
ツリーコントロールを設置するダイアログにWM_CONTEXTMENU
に関するハンドラを生成する。その中身は以下のように定義する。TrackPopupMenu()
の第4引数にはtreeCtrl
を指定したいところではあるが、今回はポップアップメニューのイベントのキャッチをツリーコントロールではなくダイアログCTab1Page3Dlg
で行うためthis
を指定している。
これにより、ツリーコントロール上で右クリックをすると専用のポップアップメニューが出現する。
次に設置したポップアップメニューのイベントを設置する。イベントの設置方法についてはメニューバーと同様にクラスウィザードから作成することができる。
後は、具体的にツリーに要素を挿入するロジックを定義する。
以上でツリーを構築する機能の構築が完了したため、自由にツリーを構築することができる。
ダイアログの制御
これまででは1つのウィンドウ(ダイアログ)を扱ってきたが、複数のウィンドウを扱う方法について扱う。
モーダルダイアログ
まずは、もっとも単純なウィンドウであるモーダルダイアログを表示させてみる。初めに、モーダルダイアログ専用のダイアログおよびクラスを作成する。
どのイベントによりモーダルダイアログを表示するかであるが、今回は分割ボタンの要素1(DropDown1)を選択したときにモーダルダイアログを表示させるようにする。イベントハンドラの実装についてはこれまで通り、クラスウィザードからイベントハンドラを生成し、その中身を記述する。
後は、プログラムを実行し、分割ボタンの要素1(DropDown1)を選択すればモーダルダイアログを表示されることが確認できる。
また、モーダルダイアログのキャンセルボタンやバツボタンを押下すれば、キャンセルに関する終了コードが取得されていることが確認できる。
モードレスダイアログ
次はモードレスダイアログを作成してみる。モーダルダイアログの場合と同様にして専用のダイアログおよびクラスを作成する。
モードレスダイアログの表示についてはモードレスダイアログと同様にして、分割ボタンの要素2(DropDown2)を選択したときにモードレスダイアログを表示させるようにする。
イベントハンドラについてはモーダルダイアログとは異なる部分が多い。なぜならば、モードレスダイアログを管理は親クラスなどがする必要があるためである(モーダルダイアログのダイアログのハンドラはスタックで管理される)ことや、モーダルダイアログとは異なり同期的ではないためである。
まずは、モードレスダイアログを管理する変数を与える。
ダイアログの表示のためのコードは以下のようになる。
これにより、分割ボタンの要素2(DropDown2)を選択したときにモードレスダイアログが表示され、削除も機能しているかのように見える。しかし、コメントにもあるように、モードれすダイアログはメインのウィンドウではないため、例えばキャンセルボタンを押下しても、単にモーダルダイアログが非表示になるだけである。
モードレスダイアログを削除する際には、親で管理しているダイアログのハンドルのリソースも適切に開放するべきである。CWnd::DestroyWindow()のドキュメントによれば、削除の通知はWM_PARENTNOTIFY
メッセージが親で受信できるとあるが、今回の場合は受信することはできない。なぜならば、厳密にはダイアログのプロパティの「スタイル」に子を指定した場合に送信される(と思われる)ものであるためである。
今回は安直に親に対して専用の通知を送信することにより、リソースの開放を行うことにする。まずは、専用のコマンドIDを定義したいところであるが、以下のようにResource.h
を直接書き換えると、Visual Studioが勝手に書き換えた内容をなかったことにするため、ダミーのメニューバーなどを作成し、IDを生成する。
以下がそのダミーを作成する様子。
イベントハンドラの定義についてもこれまでと同様にしてクラスウィザードから定義をし、中身についてはダイアログのインスタンスを削除する処理を記述する。
後は、モードレスダイアログの「OK」ボタンを押下したタイミングでコマンドを送信すればいい。
以上により、モードレスダイアログの削除を機能させることができる(そもそもダイアログ生成時に親を指定しないでおいてドキュメントに従ってdelete this
をするという手段もあるにはある)。
しかし、モードレスダイアログ起動時にモーダルダイアログを立ち上げるとモードレスダイアログが操作できてしまうという問題が残っている。それに関しては、モーダルダイアログの生成・削除の前後でモードレスダイアログを無効化する処理を挿入することで解決をすることができる。
ショートカットキー
ショートカットキーの実装はアクセラレータを利用することで達成することができる。まずはリソースの追加からアクセラレータを選択し、「新規作成」を押下する。
あとはエディタから直観的にショートカットキーの設定をすることができる。IDについてはこれまで作成したコマンドについてのIDを指定する。タイプについては仮想キー(VIRTKEY)か物理キー(ASCII)のどちらのキー配列を用いるかの指定をする。
次に、ダイアログの初期化部においてアクセラレータのハンドルを取得する処理を記述する。
後は、アクセラレータをハンドルするためにPreTranslateMessage()
をオーバーライドして、その中身を記述する。
プログラムを立ち上げ、「Ctrl+Alt+F1」と入力するとモーダルダイアログが立ち上がるし、「Ctrl+Q」と入力するとメインのウィンドウの「ボタン」ボタンを押下した際のイベントが発火する。
イベントの発火
イベントを発火させることについてはモードレスダイアログの方で若干触れたが、改めてその方法について述べておく(もちろん、イベントの定義された関数を直接呼び出してもよいが、今回はWindows APIにおけるイベント管理方式であるメッセージキューを介して何とかする事について述べる)。
モードレスダイアログの削除の際に親に送信したように、送信先となるターゲットとなるウィンドウのメンバ関数として、SendMessage()
を呼び出すことによりメッセージを送信することができる。
SendMessage()
の第1引数(message
)にはメッセージの種類(ボタンのクリックなど)、第2引数(wParam
)と第3引数(lParam
)にはメッセージ固有の詳細情報を記述する。wParam
とlParam
の違いとしては、wParam
にはハンドラを示すIDをが指定され、lParam
にはメッセージとして渡されるデータ(構造体へのポインタ等)が指定されるという点で異なる。
具体的に指定するlParam
については、以下のドキュメントから個別のメッセージを定義を読むといいだろう。WM_
でタイトルにフィルターをかけるとメッセージの種類一覧が表示されるため、そこから検索をかけるとよい。
おわりに
とりあえずダイアログアプリケーションを作成する際のMFCの基礎的な部分についてはおおよそ触ることができたと思われる。感想としては、隠しきれないWindows API感がけっこうアレというのと、C++はC++でもC++03以前の古いBetter Cだなと思った。
あとは、SDIやMDIといったViewを用いたアプリケーション作成といったところではあるが、基本的なGUI等の操作は変わらなかったり、パーツとしてダイアログを用いたりするため、どうしてもダイアログの扱いが初めに必要になってしまう。これらを扱おうとするだけで非常に記事が長くなってしまうため、今回はなしとした。