ホーム ATL/WTL
代替メッセージマップ
ドキュメント種別 ATL/WTL に関する文書
最終更新日 2003/12/17
PR
 前回説明したチェーンにより、基底クラスのメッセージマップは複数の派生クラスからのメッセージを処理できるようになります。 以下に示すのは、派生クラスのウィンドウ上でクリックすると、 WM_LBUTTONDOWNメッセージがチェーン先の基底クラスへ送られ、 メッセージボックスが表示されるという例です。

// 基底クラス
class CBaseMsgWindow : public CWindowImpl<CBaseMsgWindow>
{
    BEGIN_MSG_MAP(CBaseMsgWindow)
        MESSAGE_HANDLER(WM_LBUTTONDOWN, OnButtonDown)
    END_MSG_MAP()

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

// 派生クラス1
class CHelloWindow : public CBaseMsgWindow
{
    BEGIN_MSG_MAP(CHelloWindow)
        ...
        CHAIN_MSG_MAP(CBaseMsgWindow)  // チェーン先の基底クラスを指定
    END_MSG_MAP()
};

// 派生クラス2
class CHelloWindow2 : public CBaseMsgWindow
{
    BEGIN_MSG_MAP(CHelloWindow2)
        ...
        CHAIN_MSG_MAP(CBaseMsgWindow)  // チェーン先の基底クラスを指定
    END_MSG_MAP()
};
			

この例では、二つの派生クラスとも、結果的に同じOnButtonDown()という メッセージハンドラを呼び出します。

 ところで、上記の方法では、派生クラスによって別のメッセージハンドラを呼び出したいと思っていても、 当然ですがいつも同じOnButtonDown()しか呼び出されません。 しかし、ATLの「代替メッセージマップ」を使えば、 派生クラスによって別のメッセージハンドラを呼び出すことが可能です。

次に示すのは、基底クラスのメッセージマップを三つの部分に分割して代替メッセージマップを作成し、 派生クラスから基底クラスの代替メッセージマップへチェーンするという例です。 メッセージマップを分割するには、ALT_MSG_MAPマクロを使用します。

// 基底クラス
class CBaseMsgWindow : public CWindowImpl<CBaseMsgWindow>
{
    // メッセージマップを三つの部分に分割
    BEGIN_MSG_MAP(CBaseMsgWindow)
        MESSAGE_HANDLER(WM_LBUTTONDOWN, OnButtonDown)
    ALT_MSG_MAP(1)
        MESSAGE_HANDLER(WM_LBUTTONDOWN, OnButtonDown2)
    ALT_MSG_MAP(2)
        MESSAGE_HANDLER(WM_LBUTTONDOWN, OnButtonDown3)
    END_MSG_MAP()

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

// 派生クラス1
class CHelloWindow : public CBaseMsgWindow
{
    BEGIN_MSG_MAP(CHelloWindow)
        ...
        CHAIN_MSG_MAP(CBaseMsgWindow)         // 通常のチェーン
    END_MSG_MAP()
};

// 派生クラス2
class CHelloWindow2 : public CBaseMsgWindow
{
    BEGIN_MSG_MAP(CHelloWindow2)
        ...
        CHAIN_MSG_MAP_ALT(CBaseMsgWindow, 1)  // 代替メッセージマップへチェーン
    END_MSG_MAP()
};
			

 ALT_MSG_MAPマクロには代替メッセージマップを識別する番号を指定します。 上記の例では、前述のとおり基底クラスのメッセージマップを ALT_MSG_MAPマクロによって三つの部分に分割しています。 一つ目はデフォルトのメッセージマップで、二つ目は番号 1 で識別される代替メッセージマップ、 三つ目は番号 2 で識別される代替メッセージマップです。 なお、デフォルトのメッセージマップには暗黙のうちに 0 という番号が割り当てられます。

// メッセージマップを三つの部分に分割
BEGIN_MSG_MAP(CBaseMsgWindow)
// 一つ目
    MESSAGE_HANDLER(WM_LBUTTONDOWN, OnButtonDown)
ALT_MSG_MAP(1)
// 二つ目
    MESSAGE_HANDLER(WM_LBUTTONDOWN, OnButtonDown2)
ALT_MSG_MAP(2)
// 三つ目
    MESSAGE_HANDLER(WM_LBUTTONDOWN, OnButtonDown3)
END_MSG_MAP()
			

 これで基底クラスに代替メッセージマップが用意できたので、次に、 派生クラスから代替メッセージマップにチェーンする方法ですが、 そのためにはCHAIN_MSG_MAP_ALTマクロを使用します。 CHAIN_MSG_MAP_ALTマクロには、チェーン先のクラス名と、 そのクラスにある代替メッセージマップの番号を指定します。

上記の例では、CHelloWindowクラスではCBaseMsgWindowクラスに 通常のチェーンをしているだけなので、CBaseMsgWindowクラスのデフォルトのメッセージマップにある OnButtonDown()が呼び出されます。 CHelloWindow2クラスでは、CBaseMsgWindowクラスの 代替メッセージマップ番号 1 にチェーンしてるので、 OnButtonDown2()が呼び出されます。

ATLはCHAIN_MSG_MAP_ALT()を含め、次のような代替メッセージマップ用チェーンマクロを用意しています。

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

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