ホーム ATL/WTL
チェーン
ドキュメント種別 ATL/WTL に関する文書
最終更新日 2003/12/17
PR
 ATLにはチェーンという仕組みがあります。これは、メッセージマップを別のメッセージマップと繋ぐ仕組みです。 なぜこのような仕組みが必要なのかを以下のプログラム片を例に説明します。

// 基底クラス
class CBaseWindow : public CWindowImpl<CBaseWindow>
{
    BEGIN_MSG_MAP(CBaseWindow)
        MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
    END_MSG_MAP()

    LRESULT OnDestroy(UINT, WPARAM, LPARAM, BOOL&)
    {
        PostQuitMessage(0);
        return 0;
    }
};

// 派生クラス
class CMessageWindow : public CBaseWindow
{
    BEGIN_MSG_MAP(CMessageWindow)
        MESSAGE_HANDLER(WM_LBUTTONDOWN, OnButtonDown)
    END_MSG_MAP()

    LRESULT OnButtonDown(UINT, WPARAM, LPARAM, BOOL&)
    {
        MessageBox(_T("Hello!"));
        return 0;
    }
};
			

 上記のプログラム片は、ウィンドウを終了するハンドラだけを持った基底クラス(CBaseWindow) と、そのクラスから派生したクラス(CMessageWindow)の定義です。 派生クラスでは、左マウスボタンを押した時に "Hello!" というメッセージボックスを 表示するようにしています。

 ここで、派生クラスであるCMessageWindowクラスからウィンドウを作成し表示したとしても、 このウィンドウは終了できません。 つまり、このウィンドウへWM_DESTROYメッセージが送られても、 自動的に基底クラスへは送られず、基底クラスのOnDestroy()は呼び出されないのです。

 この問題を解決するのがチェーンという仕組みです。つまり、派生クラスのメッセージマップと 基底クラスのメッセージマップを繋ぎ、派生クラスでメッセージハンドラが見つからない場合は 基底クラスのメッセージマップを検索するように変更するのです。これは、基本クラスへのチェーンと 呼ばれます。基本クラスへのチェーンを実現するためには、派生クラスのメッセージマップ内で CHAIN_MSG_MAPマクロを使用します。

BEGIN_MSG_MAP(CMessageWindow)
    MESSAGE_HANDLER(WM_LBUTTONDOWN, OnButtonDown)
    CHAIN_MSG_MAP(CBaseWindow)  // チェーン先の基底クラスを指定
END_MSG_MAP()
			

 このように、ATLでは、派生クラスに該当するメッセージハンドラが無いとき、 メッセージが自動的に基底クラスへ送られることはありません。 これは、ATLのアーキテクチャが多重継承を基盤にしているからです。 多重継承では基底クラスが複数存在するため、どの基底クラスのメッセージマップに メッセージを送るかを、チェーンによって明示的に指定しなければならないのです。

ATLはCHAIN_MSG_MAP()を含め、次のようなチェーンマクロを用意しています。

  • CHAIN_MSG_MAP(クラス名)
    指定されたクラスのメッセージマップにチェーンします。

  • CHAIN_MSG_MAP_MEMBER(インスタンス名)
    指定されたインスタンスのメッセージマップにチェーンします。