zoukankan      html  css  js  c++  java
  • MFC消息映射与命令传递

    DECLARE_MESSAGE_MAP宏

    在 MFC 几乎每个头文件下(类的最后一行声明),都会有这么几行代码:

    // 生成的消息映射函数

    protected:

    DECLARE_MESSAGE_MAP()

     

    我们看一看 DECLARE_MESSAGE_MAP到底为何物,查看 DECLARE_MESSAGE_MAP源码(c:Program FilesMicrosoft Visual Studio 9.0VCatlmfcincludeafxwin.h):

    #define DECLARE_MESSAGE_MAP() 

    protected: 

    static const AFX_MSGMAP* PASCAL GetThisMessageMap(); 

    virtual const AFX_MSGMAP* GetMessageMap() const; 

     

    我们看到了一个陌生的类型 AFX_MSGMAP ,查看其定义: 

    struct AFX_MSGMAP

    {

    const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();

    const AFX_MSGMAP_ENTRY* lpEntries;

    };

     

    这个结构体第一个成员是一个函数指针,第二个成员类型为 AFX_MSGMAP_ENTRY* ,查看AFX_MSGMAP_ENTRY 定义:

    struct AFX_MSGMAP_ENTRY

    {

    UINT nMessage;   // windows message

    UINT nCode;      // control code or WM_NOTIFY code

    UINT nID;        // control ID (or 0 for windows messages)

    UINT nLastID;    // used for entries specifying a range of control id's

    UINT_PTR nSig;       // signature type (action) or pointer to message #

    AFX_PMSG pfn;    // routine to call (or special value)

    };

    AFX_MSGMAP_ENTRY 定义一些消息的相关信息,AFX_PSG 定义为:

    typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);

    是一个函数指针。是不是将每个消息与其处理方法绑定起来呢?真有可能。

    BEGIN_MESSAGE_MAP/ON.../END_MESSAGEBOX 

    MFC 几乎每个(类定义的)源文件下都会出现下面几行代码(或者类似):

    BEGIN_MESSAGE_MAP(CXXX, C***)

    ON_……

    END_MESSAGE_MAP()

    我们继续一探究竟,查看这几个宏的源码:

    #define BEGIN_MESSAGE_MAP(theClass, baseClass) 

    PTM_WARNING_DISABLE 

    const AFX_MSGMAP* theClass::GetMessageMap() const 

    { return GetThisMessageMap(); } 

    const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() 

    typedef theClass ThisClass;    

    typedef baseClass TheBaseClass;    

    static const AFX_MSGMAP_ENTRY _messageEntries[] =  

    {

     

     

    #define END_MESSAGE_MAP() 

    {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } 

    }; 

    static const AFX_MSGMAP messageMap = 

    { &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; 

    return &messageMap; 

    }   

    PTM_WARNING_RESTORE

    关于 ON_...类型的宏就多了,下面我摘了(C:Program FilesMicrosoft Visual Studio 9.0VCatlmfcincludeafxmsg_.h)下面一些我们很熟悉的代码:

    #define ON_COMMAND(id, memberFxn) 

    { WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSigCmd_v, 

    static_cast<AFX_PMSG> (memberFxn) },

    // ON_COMMAND(id, OnBar) is the same as

    //   ON_CONTROL(0, id, OnBar) or ON_BN_CLICKED(0, id, OnBar)

    #define ON_NOTIFY(wNotifyCode, id, memberFxn) 

    { WM_NOTIFY, (WORD)(int)wNotifyCode, (WORD)id, (WORD)id, AfxSigNotify_v, 

    (AFX_PMSG) 

    (static_cast< void (AFX_MSG_CALL CCmdTarget::*)(NMHDR*, LRESULT*) > 

    (memberFxn)) },

    // for general controls

    #define ON_CONTROL(wNotifyCode, id, memberFxn) 

    { WM_COMMAND, (WORD)wNotifyCode, (WORD)id, (WORD)id, AfxSigCmd_v, 

    (static_cast< AFX_PMSG > (memberFxn)) },

    #define ON_WM_DESTROY() 

    { WM_DESTROY, 0, 0, 0, AfxSig_vv, 

    (AFX_PMSG)(AFX_PMSGW) 

    (static_cast< void (AFX_MSG_CALL CWnd::*)(void) > ( &ThisClass :: OnDestroy)) },

    #define ON_WM_SIZE() 

    { WM_SIZE, 0, 0, 0, AfxSig_vwii, 

    (AFX_PMSG)(AFX_PMSGW) 

    (static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, int, int) > ( &ThisClass :: OnSize)) },

     

    又加了一些宏,一步一步的看吧,PTM_WARNING_DISABLE与PTM_WARNING_RESTORE:

    #define PTM_WARNING_DISABLE 

    __pragma(warning( push )) 

    __pragma(warning( disable : 4867 ))

    #define PTM_WARNING_RESTORE 

    __pragma(warning( pop ))

    是处理警告的,貌似和我们的话题不符,就先不看了。

    查看 AfxSig_end 定义:

    enum AfxSig

    {

    AfxSig_end = 0,     // [marks end of message map]

     

    AfxSig_b_D_v, // BOOL (CDC*)

    AfxSig_b_b_v, // BOOL (BOOL)

    AfxSig_b_u_v, // BOOL (UINT)

    AfxSig_b_h_v, // BOOL (HANDLE)

    AfxSig_b_W_uu, // BOOL (CWnd*, UINT, UINT)

    AfxSig_b_W_COPYDATASTRUCT, // BOOL (CWnd*, COPYDATASTRUCT*)

    AfxSig_b_v_HELPINFO, // BOOL (LPHELPINFO);

    AfxSig_CTLCOLOR, // HBRUSH (CDC*, CWnd*, UINT)

    AfxSig_CTLCOLOR_REFLECT, // HBRUSH (CDC*, UINT)

    AfxSig_i_u_W_u, // int (UINT, CWnd*, UINT)  // ?TOITEM

    AfxSig_i_uu_v, // int (UINT, UINT)

    AfxSig_i_W_uu, // int (CWnd*, UINT, UINT)

    AfxSig_i_v_s, // int (LPTSTR)

    AfxSig_l_w_l, // LRESULT (WPARAM, LPARAM)

    AfxSig_l_uu_M, // LRESULT (UINT, UINT, CMenu*)

    AfxSig_v_b_h, // void (BOOL, HANDLE)

    AfxSig_v_h_v, // void (HANDLE)

    AfxSig_v_h_h, // void (HANDLE, HANDLE)

    AfxSig_v_v_v, // void ()

    AfxSig_v_u_v, // void (UINT)

    AfxSig_v_u_u, // void (UINT, UINT)

    AfxSig_v_uu_v, // void (UINT, UINT)

    AfxSig_v_v_ii, // void (int, int)

    AfxSig_v_u_uu, // void (UINT, UINT, UINT)

    AfxSig_v_u_ii, // void (UINT, int, int)

    AfxSig_v_u_W, // void (UINT, CWnd*)

    AfxSig_i_u_v, // int (UINT)

    AfxSig_u_u_v, // UINT (UINT)

    AfxSig_b_v_v, // BOOL ()

    AfxSig_v_w_l, // void (WPARAM, LPARAM)

    AfxSig_MDIACTIVATE, // void (BOOL, CWnd*, CWnd*)

    AfxSig_v_D_v, // void (CDC*)

    AfxSig_v_M_v, // void (CMenu*)

    AfxSig_v_M_ub, // void (CMenu*, UINT, BOOL)

    AfxSig_v_W_v, // void (CWnd*)

    AfxSig_v_v_W, // void (CWnd*)

    AfxSig_v_W_uu, // void (CWnd*, UINT, UINT)

    AfxSig_v_W_p, // void (CWnd*, CPoint)

    AfxSig_v_W_h, // void (CWnd*, HANDLE)

    AfxSig_C_v_v, // HCURSOR ()

    AfxSig_ACTIVATE, // void (UINT, CWnd*, BOOL)

    AfxSig_SCROLL, // void (UINT, UINT, CWnd*)

    AfxSig_SCROLL_REFLECT, // void (UINT, UINT)

    AfxSig_v_v_s, // void (LPTSTR)

    AfxSig_v_u_cs, // void (UINT, LPCTSTR)

    AfxSig_OWNERDRAW, // void (int, LPTSTR) force return TRUE

    AfxSig_i_i_s, // int (int, LPTSTR)

    AfxSig_u_v_p, // UINT (CPoint)

    AfxSig_u_v_v, // UINT ()

    AfxSig_v_b_NCCALCSIZEPARAMS, // void (BOOL, NCCALCSIZE_PARAMS*)

    AfxSig_v_v_WINDOWPOS, // void (WINDOWPOS*)

    AfxSig_v_uu_M, // void (UINT, UINT, HMENU)

    AfxSig_v_u_p, // void (UINT, CPoint)

    AfxSig_SIZING, // void (UINT, LPRECT)

    AfxSig_MOUSEWHEEL, // BOOL (UINT, short, CPoint)

    AfxSig_MOUSEHWHEEL, // void (UINT, short, CPoint)

    AfxSigCmd_v, // void ()

    AfxSigCmd_b, // BOOL ()

    AfxSigCmd_RANGE, // void (UINT)

    AfxSigCmd_EX, // BOOL (UINT)

    AfxSigNotify_v, // void (NMHDR*, LRESULT*)

    AfxSigNotify_b, // BOOL (NMHDR*, LRESULT*)

    AfxSigNotify_RANGE, // void (UINT, NMHDR*, LRESULT*)

    AfxSigNotify_EX, // BOOL (UINT, NMHDR*, LRESULT*)

    AfxSigCmdUI, // void (CCmdUI*)

    AfxSigCmdUI_RANGE, // void (CCmdUI*, UINT)

    AfxSigCmd_v_pv, // void (void*)

    AfxSigCmd_b_pv, // BOOL (void*)

    AfxSig_l, // LRESULT ()

    AfxSig_l_p, // LRESULT (CPOINT)

    AfxSig_u_W_u, // UINT (CWnd*, UINT)

    AfxSig_v_u_M, // void (UINT, CMenu* )

    AfxSig_u_u_M, // UINT (UINT, CMenu* )

    AfxSig_u_v_MENUGETOBJECTINFO, // UINT (MENUGETOBJECTINFO*)

    AfxSig_v_M_u, // void (CMenu*, UINT)

    AfxSig_v_u_LPMDINEXTMENU, // void (UINT, LPMDINEXTMENU)

    AfxSig_APPCOMMAND, // void (CWnd*, UINT, UINT, UINT)

    AfxSig_RAWINPUT, // void (UINT, HRAWINPUT)

    AfxSig_u_u_u, // UINT (UINT, UINT)

    AfxSig_MOUSE_XBUTTON, // void (UINT, UINT, CPoint)

    AfxSig_MOUSE_NCXBUTTON, // void (short, UINT, CPoint)

    AfxSig_INPUTLANGCHANGE, // void (BYTE, UINT)

    AfxSig_v_u_hkl, // void (UINT, HKL)

    AfxSig_INPUTDEVICECHANGE, // void (unsigned short)

    // Old

    AfxSig_bD = AfxSig_b_D_v,      // BOOL (CDC*)

    AfxSig_bb = AfxSig_b_b_v,      // BOOL (BOOL)

    AfxSig_bWww = AfxSig_b_W_uu,    // BOOL (CWnd*, UINT, UINT)

    AfxSig_hDWw = AfxSig_CTLCOLOR,    // HBRUSH (CDC*, CWnd*, UINT)

    AfxSig_hDw = AfxSig_CTLCOLOR_REFLECT,     // HBRUSH (CDC*, UINT)

    AfxSig_iwWw = AfxSig_i_u_W_u,    // int (UINT, CWnd*, UINT)

    AfxSig_iww = AfxSig_i_uu_v,     // int (UINT, UINT)

    AfxSig_iWww = AfxSig_i_W_uu,    // int (CWnd*, UINT, UINT)

    AfxSig_is = AfxSig_i_v_s,      // int (LPTSTR)

    AfxSig_lwl = AfxSig_l_w_l,     // LRESULT (WPARAM, LPARAM)

    AfxSig_lwwM = AfxSig_l_uu_M,    // LRESULT (UINT, UINT, CMenu*)

    AfxSig_vv = AfxSig_v_v_v,      // void (void)

     

    AfxSig_vw = AfxSig_v_u_v,      // void (UINT)

    AfxSig_vww = AfxSig_v_u_u,     // void (UINT, UINT)

    AfxSig_vww2 = AfxSig_v_uu_v,    // void (UINT, UINT) // both come from wParam

    AfxSig_vvii = AfxSig_v_v_ii,    // void (int, int) // wParam is ignored

    AfxSig_vwww = AfxSig_v_u_uu,    // void (UINT, UINT, UINT)

    AfxSig_vwii = AfxSig_v_u_ii,    // void (UINT, int, int)

    AfxSig_vwl = AfxSig_v_w_l,     // void (UINT, LPARAM)

    AfxSig_vbWW = AfxSig_MDIACTIVATE,    // void (BOOL, CWnd*, CWnd*)

    AfxSig_vD = AfxSig_v_D_v,      // void (CDC*)

    AfxSig_vM = AfxSig_v_M_v,      // void (CMenu*)

    AfxSig_vMwb = AfxSig_v_M_ub,    // void (CMenu*, UINT, BOOL)

     

    AfxSig_vW = AfxSig_v_W_v,      // void (CWnd*)

    AfxSig_vWww = AfxSig_v_W_uu,    // void (CWnd*, UINT, UINT)

    AfxSig_vWp = AfxSig_v_W_p,     // void (CWnd*, CPoint)

    AfxSig_vWh = AfxSig_v_W_h,     // void (CWnd*, HANDLE)

    AfxSig_vwW = AfxSig_v_u_W,     // void (UINT, CWnd*)

    AfxSig_vwWb = AfxSig_ACTIVATE,    // void (UINT, CWnd*, BOOL)

    AfxSig_vwwW = AfxSig_SCROLL,    // void (UINT, UINT, CWnd*)

    AfxSig_vwwx = AfxSig_SCROLL_REFLECT,    // void (UINT, UINT)

    AfxSig_vs = AfxSig_v_v_s,      // void (LPTSTR)

    AfxSig_vOWNER = AfxSig_OWNERDRAW,  // void (int, LPTSTR), force return TRUE

    AfxSig_iis = AfxSig_i_i_s,     // int (int, LPTSTR)

    AfxSig_wp = AfxSig_u_v_p,      // UINT (CPoint)

    AfxSig_wv = AfxSig_u_v_v,      // UINT (void)

    AfxSig_vPOS = AfxSig_v_v_WINDOWPOS,    // void (WINDOWPOS*)

    AfxSig_vCALC = AfxSig_v_b_NCCALCSIZEPARAMS,   // void (BOOL, NCCALCSIZE_PARAMS*)

    AfxSig_vNMHDRpl = AfxSigNotify_v,    // void (NMHDR*, LRESULT*)

    AfxSig_bNMHDRpl = AfxSigNotify_b,    // BOOL (NMHDR*, LRESULT*)

    AfxSig_vwNMHDRpl = AfxSigNotify_RANGE,   // void (UINT, NMHDR*, LRESULT*)

    AfxSig_bwNMHDRpl = AfxSigNotify_EX,   // BOOL (UINT, NMHDR*, LRESULT*)

    AfxSig_bHELPINFO = AfxSig_b_v_HELPINFO,   // BOOL (HELPINFO*)

    AfxSig_vwSIZING = AfxSig_SIZING,    // void (UINT, LPRECT) -- return TRUE

     

    // signatures specific to CCmdTarget

    AfxSig_cmdui = AfxSigCmdUI,   // void (CCmdUI*)

    AfxSig_cmduiw = AfxSigCmdUI_RANGE,  // void (CCmdUI*, UINT)

    AfxSig_vpv = AfxSigCmd_v_pv,     // void (void*)

    AfxSig_bpv = AfxSigCmd_b_pv,     // BOOL (void*)

     

    // Other aliases (based on implementation)

    AfxSig_vwwh = AfxSig_v_uu_M,                // void (UINT, UINT, HMENU)

    AfxSig_vwp = AfxSig_v_u_p,                 // void (UINT, CPoint)

    AfxSig_bw = AfxSig_b_u_v,      // BOOL (UINT)

    AfxSig_bh = AfxSig_b_h_v,      // BOOL (HANDLE)

    AfxSig_iw = AfxSig_i_u_v,      // int (UINT)

    AfxSig_ww = AfxSig_u_u_v,      // UINT (UINT)

    AfxSig_bv = AfxSig_b_v_v,      // BOOL (void)

    AfxSig_hv = AfxSig_C_v_v,      // HANDLE (void)

    AfxSig_vb = AfxSig_vw,      // void (BOOL)

    AfxSig_vbh = AfxSig_v_b_h,    // void (BOOL, HANDLE)

    AfxSig_vbw = AfxSig_vww,    // void (BOOL, UINT)

    AfxSig_vhh = AfxSig_v_h_h,    // void (HANDLE, HANDLE)

    AfxSig_vh = AfxSig_v_h_v,      // void (HANDLE)

    AfxSig_viSS = AfxSig_vwl,   // void (int, STYLESTRUCT*)

    AfxSig_bwl = AfxSig_lwl,

    AfxSig_vwMOVING = AfxSig_vwSIZING,  // void (UINT, LPRECT) -- return TRUE

     

    AfxSig_vW2 = AfxSig_v_v_W,                 // void (CWnd*) (CWnd* comes from lParam)

    AfxSig_bWCDS = AfxSig_b_W_COPYDATASTRUCT,               // BOOL (CWnd*, COPYDATASTRUCT*)

    AfxSig_bwsp = AfxSig_MOUSEWHEEL,                // BOOL (UINT, short, CPoint)

    AfxSig_vws = AfxSig_v_u_cs,

    };

    AfxSig 的含义暂时不讲,稍后再说。

    把几个宏分散开来,没有整体效果。还是举个例子吧:

    DECLARE_MESSAGE_MAP()

    EGIN_MESSAGE_MAP(CFirstMFCDemoApp, CWinApp)

    ON_COMMAND(ID_FILE_NEW, &CWinApp::OnFileNew)

    ON_COMMAND(ID_FILE_OPEN, &CWinApp::OnFileOpen)

    END_MESSAGE_MAP()

     

    展开以后为:

    protected: 

    static const AFX_MSGMAP* PASCAL GetThisMessageMap(); 

    virtual const AFX_MSGMAP* GetMessageMap() const; 

     

    const AFX_MSGMAP* CFirstMFCDemoApp::GetMessageMap() const 

    return GetThisMessageMap(); 

    const AFX_MSGMAP* PASCAL 

    CFirstMFCDemoApp::GetThisMessageMap() 

    typedef CFirstMFCDemoApp ThisClass;    

    typedef CWinApp TheBaseClass;    

    static const AFX_MSGMAP_ENTRY _messageEntries[] =  

    {

    {  

    WM_COMMAND, CN_COMMAND, (WORD)ID_FILE_NEW, 

       (WORD)ID_FILE_NEW, AfxSigCmd_v, 

       static_cast<AFX_PMSG> (&CWinApp::OnFileNew) 

    },

        {  

    WM_COMMAND, CN_COMMAND, (WORD)ID_FILE_OPEN, 

       (WORD)ID_FILE_OPEN, AfxSigCmd_v, 

       static_cast<AFX_PMSG> (&CWinApp::OnFileOpen)

    },

    {  

    0, 0, 0, 0,

        AfxSig_end, (AFX_PMSG)0 

    };

    static const AFX_MSGMAP messageMap = 

    { &TheBaseClass::GetThisMessageMap, 

          &_messageEntries[0] }; 

    return &messageMap; 

    }

    仔细看上述代码,会发现这和 RTTI 一样,还是一个链表。将子类的消息映射表和父类的消息映射表联系起来。

    下图为 MFC 消息映射表:

    消息泵的开始

    这里用到 window高级编程中的 hook 技术,而我对 hook 技术很不了解,所以无法讲述(与其讲错,不如不讲)。想了解更多,自己查资料去吧,O(_)O~

    消息传递方式

    (1)直线上溯(一般 windows 消息)

    CWnd::WindowProc 调用 OnWndMsg 用来分辨并处理消息;如果是命令消息,交给 OnCommand 处理,如果是通知消息(Notification),交给 OnNotify 处理。而一般的 Windows 消息,就直接在消息映射表中上溯,寻找其归宿(消息处理程序)。

    下图是WM_PAINT 消息发生于 View 时,消息传递路径:

     

    (2)拐弯上溯(WM_COMMAND命令消息)

    如果消息是 WM_COMMAND ,CWnd::OnWndMsg 另辟蹊径,交流 OnCommand 来处理。这并不一定是 CWnd::OnCommand ,得视 this 指针指向哪一种对象而定。在 MFC 之中,以下类都改写了 OnCommand 函数;

    Class CWnd : public CCmdTarget

    Class CFrameWnd : public CFrameWnd

    Class CMDIFrameWnd : public CWnd

    Class CSplitterWnd : public CWnd

    Class CPropertySheet : public CWnd

    Class COlePropertyPage : public CDialog 

    下图示出了 FrameWnd 窗口收到命令消息后的四个尝试路径:

     

     

    消息映射和命令传递,大体上应该有了一个了解。一些细节如“AfxSig_XX 的奥秘以及具体到程序的代码,这是一个极其复杂的过程,需要深厚的 Windows 编程功底。而我觉得作为 MFC 普通用户而言,了解到这里就已经够了。

  • 相关阅读:
    自动化测试框架相关资料下载
    C++白盒测试最佳实践课程,3个免费名额火热申请中,31号前截止申请...
    亿能测试培训中心 下周进入完整自动化测试项目实训阶段
    亿能测试大讲堂
    自动化测试调查问卷送《QTP自动化测试最佳实践》
    8月白盒测试课程
    广州亿能自动化测试沙龙
    8月自动化测试课程
    广州亿能自动化测试沙龙
    史上最强的自动化测试课程7月开设
  • 原文地址:https://www.cnblogs.com/jiangzhaowei/p/5099176.html
Copyright © 2011-2022 走看看