ホーム WTL Mobile
チェイン
ドキュメント種別 ATL/WTL に関する文書
最終更新日 2009/04/22
PR
 ATLにはチェインという仕組みがあります。これは、メッセージマップを別のメッセージマップへ繋ぐ仕組みです。 なぜこのような仕組みが必要なのかを次のコードを例に説明します。

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

    LRESULT OnActivate(UINT, WPARAM, LPARAM, BOOL&){
        SHFullScreen(m_hWnd, SHFS_HIDESIPBUTTON);
        return 0;
    }

    LRESULT OnSettingChange(UINT, WPARAM, LPARAM, BOOL&){
        SHFullScreen(m_hWnd, SHFS_HIDESIPBUTTON);
        return 0;
    }

    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;
    }
};
			

 上記のコードは、WM_ACTIVATEメッセージ、WM_SETTINGCHANGEメッセージ、 WM_DESTROYメッセージのハンドラ関数を持つ基底クラス(CBaseWindow)と、 その派生クラス(CMessageWindow)の定義です。 派生クラスでは、ウィンドウをタップした時に "Hello!" というメッセージボックスを表示します。

 ここで、派生クラスであるCMessageWindowクラスからウィンドウを作成し表示したとしても、 このウィンドウはSIPボタンを非表示にせず、終了もできません。 つまり、このウィンドウへWM_ACTIVATEメッセージ、WM_SETTINGCHANGEメッセージ、 WM_DESTROYメッセージが送られても、 自動的に基底クラスへは送られず、基底クラスのOnActivate()OnSettingChange()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(メンバ変数名)
    指定されたメンバ変数のメッセージマップにチェインします。