標準 Windows メッセージ (WM_) の既定のハンドラーは、CWnd クラスで定義されています。 クラス ライブラリでは、これらのハンドラーの名前をメッセージ名に基づいて決めています。 たとえば、WM_PAINT メッセージのハンドラー名は、CWnd で次のように宣言されています。
afx_msg void OnPaint();
キーワード afx_msg は、これらのハンドラーをほかの CWnd のメンバー関数と区別する点で、C++ キーワード virtual と同じ効果があります。 ただし、CWnd のメンバー関数は実際には仮想関数にはならず、メッセージ マップによって実装されます。 メッセージ マップには、プリプロセッサの標準マクロだけが使われ、C++ 言語の拡張機能は使われません。 キーワード afx_msg は、プリプロセスが終了すると、空白文字に置換されます。
基本クラスで定義されているハンドラーをオーバーライドするには、派生クラスで同じプロトタイプを使って関数を定義し、対応するメッセージ マップ エントリを作成します。 作成したハンドラーは、そのクラスのすべての基本クラスにある同名のハンドラーをオーバーライドします。
場合によっては、作成したハンドラーから、オーバーライドした基本クラスのハンドラーを呼び出して、基本クラスと Windows でメッセージを処理させる必要があります。 オーバーライド関数から基本クラスのハンドラーを呼び出すタイミングは、状況によって異なります。 基本クラスのハンドラーを最初に呼び出す場合も、最後に呼び出す場合もあります。 自分でメッセージを処理しない場合は、条件に応じて基本クラスのハンドラーを呼び出すこともできます。 また、最初に基本クラスのハンドラーを呼び出し、その戻り値またはステータスに応じて自分のハンドラー コードを実行することもあります。
ヒント
引数を基本クラスのハンドラーに渡す場合は、引数を変更するのは危険です。 たとえば、OnChar ハンドラーの引数 nChar を変更すると (大文字への変換など)、 操作結果が不安定になります。このようなときは、CWnd のメンバー関数 SendMessage を代わりに使います。
メッセージを正しくオーバーライドする方法を調べることもできます。 [プロパティ] ウィンドウで、メッセージに対するハンドラー関数 (たとえば WM_CREATE に対する OnCreate ハンドラー) のスケルトンを生成すると、メンバー関数のオーバーライド方法が提案されます。 次の例では、まず基本クラスのハンドラーを呼び出して、その戻り値が -1 以外のときだけ処理を継続するという処理が提案されています。
int CMyView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFormView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
return 0;
}
規約上、ハンドラー名の先頭には "On" を付けることになっています。引数を取るハンドラーも、取らないハンドラーもあります。 void 以外の戻り値を持つハンドラーもあります。 WM_ メッセージの既定のハンドラーは、名前が "On" で始まる CWnd クラスのメンバー関数として分類されています (『MFC リファレンス』参照)。CWnd クラスのメンバー関数の宣言では、先頭に afx_msg が付きます。