• MFC 消息映射、分派和传递


    几个重要的结构体:

    struct AFX_MSGMAP
    {
          AFX_MSGMAP* pBaseMessageMap;
          AFX_MSGMAP_ENTRY* lpEntries;
    }
    

     

    struct AFX_MSGMAP_ENTRY
    {
        UINT nMessage;// Windows消息
        UINT nCode;// 控制消息的通知码
        UINT nID;// 其控制组件的ID
        UINT nLastID;// 如果是一定范围的消息映射,此值表示区间的最大值
        UINT nSig;  // 消息的动作标识
        AFX_MSG pfn;// 消息响应函数
    }
    

    此结构体的数据由任何一个ON_宏都会把这六个数据初始化,例如 此处的ON_WM_CREATE 和 下面提到的ON_COMMAND:

    #define ON_WM_CREATE() 
    { WM_CREATE, 0, 0, 0, AfxSig_is, (AFX_MSG)(AFX_PMSGW)(int (AFX_MSG_CALL CWnd::*)(LPCREATESTRUCT)OnCreate) },
    

      

    AFX_PMSG 是一个函数指针:

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

    定义一个DECLARE_MESSAGE_MAP()宏

    #define DECLARE_MESSAGE_MAP() 
       static AFX_MSGMAP_ENTRY _messageEntries[] ;
       static AFX_MSGMAP messageMap; 
       virtual AFX_MSGMAP* GetMessageMap() const;
    

    于是DECLARE_MESSAGE_MAP宏就相当于声明了下面的数据结构:

      

      

     这个数据结构的内容填充工作由下面三个宏完成:

    #define BEGIN_MESSAGE_MAP (theClass,baseClass) 
       AFX_MSGMAP* theClass::GetMessageMap() const 
                               { return &theClass::messageMap; }
       AFX_MSGMAP theClass::messageMap = 
       {
            &(baseClass::messageMap), 
            (AFX_MSGMAP_ENTRY*) &(theClass::_messageEntries) ; 
       } 
       AFX_MSGMAP_ENTRY  theClass::_messageEntries[] = 
       {
         
    
    #define ON_COMMAND(id,memberFxn)  
    { WM_COMMAND, 0, (WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)memberFxn },
    
    #define END_MESSAGE_MAP() 
      { 0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0} 
    };

    这个AfxSig枚举的具体作用是什么呢?

    上面的宏ON_WM_CREATE和ON_COMMAND也有出现类似的AfxSig_,那么到底作何用处?

    从上面两个宏的最后一个参数可以看出,表示的是具体的执行函数,且都进行了类型转换,最终转换为AFX_PMSG.

    可是AFX_PMSG的定义呢?我们再写一遍。

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

    这是一个什么鬼?无参,无返回值,不可能所有的函数都如此吧?

    这正是AfxSig_的作用所在,当需要调用AFX_MSGMAP_ENTRY中的消息响应函数pfn的时候,具体的动作是这样的(出现在wincore.cpp CWnd::OnWndMsg 和 DispatchCmdMsg中):

    union MessageMapFunctions mmf;
    mmf.pfn = lpEntry->pfn; // lpEntry 是AFX_MSGMAP_ENTRY的对象
    switch(lpEntry->nSig)
    {
        case AfxSig_is:
                 lResult = (this->*mmf.pfn_is)((LPTSTR)lParam);
                 break;
        case AfxSig_lwl:
                 lResult = (this->*mmf.pfn_lwl)(wParam, lParam);
                 break;
        case AfxSig_vv:
                 lResult = (this->*mmf.pfn_vv)();
                 break;
        .....
    }
    

    重点注意: MessageMapFunctions 和AfxSig_. AfxSig_ 定义位于AFXMSG_.H档。

    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*)
    	....  // 后面很多不列举
    };
    

    MessageMapFunctions 定义于WINCORE.cpp 中:

    union MessageMapFunctions
    {
    	AFX_PMSG pfn;   // generic member function pointer
    
    	BOOL (AFX_MSG_CALL CCmdTarget::*pfn_b_D)(CDC*);
    	BOOL (AFX_MSG_CALL CCmdTarget::*pfn_b_b)(BOOL);
    	BOOL (AFX_MSG_CALL CCmdTarget::*pfn_b_u)(UINT);
    	BOOL (AFX_MSG_CALL CCmdTarget::*pfn_b_h)(HANDLE);
    	BOOL (AFX_MSG_CALL CCmdTarget::*pfn_b_W_u_u)(CWnd*, UINT, UINT);
    	BOOL (AFX_MSG_CALL CCmdTarget::*pfn_b_W_COPYDATASTRUCT)(CWnd*, COPYDATASTRUCT*);
    	BOOL (AFX_MSG_CALL CCmdTarget::*pfn_b_HELPINFO)(LPHELPINFO);
    	HBRUSH (AFX_MSG_CALL CCmdTarget::*pfn_B_D_W_u)(CDC*, CWnd*, UINT);
    	HBRUSH (AFX_MSG_CALL CCmdTarget::*pfn_B_D_u)(CDC*, UINT);
    	int (AFX_MSG_CALL CCmdTarget::*pfn_i_u_W_u)(UINT, CWnd*, UINT);
    	int (AFX_MSG_CALL CCmdTarget::*pfn_i_u_u)(UINT, UINT);
    	int (AFX_MSG_CALL CCmdTarget::*pfn_i_W_u_u)(CWnd*, UINT, UINT);
    	int (AFX_MSG_CALL CWnd::*pfn_i_s)(LPTSTR);
    	int (AFX_MSG_CALL CWnd::*pfn_i_S)(LPCTSTR);
    	LRESULT (AFX_MSG_CALL CWnd::*pfn_l_w_l)(WPARAM, LPARAM);
    	LRESULT (AFX_MSG_CALL CWnd::*pfn_l_u_u_M)(UINT, UINT, CMenu*);
    	....  // 后面很多不列举
    };

    其实真正的函数只有pfn一个,但通过union后,它就有了许多类型不同的形象。这里可以看出union自动转型的作用。  

    //***********************************************************************************************

    上面讲基本内容解释完毕,下面以实例来演示宏展开后的结果:

    //in header file
    class CView : public CWnd
    {
    public:
       //...
    	DECLARE_MESSAGE_MAP()
    };
    
    //in implementation file
    #define CViewid 122
    //...
    BEGIN_MESSAGE_MAP(CView, CWnd)
    	ON_COMMAND(CViewid, 0)
    END_MESSAGE_MAP
    
    //被展开之后为
    
    //in header file
    class CView : public CWnd
    {
    public:
    	//...
    	static AFX_MSGMAP_ENTRY _messageEntries[];
    	static AFX_MSGMAP messageMap;
    	virtual AFX_MSGMAP* GetMessageMap() const;
    };
    
    //in implementation file
    AFX_MSGMAP* CView::GetMessageMap() const
    {
    	return &CView::messageMap;
    }
    
    AFX_MSGMAP CView::messageMap = { &(CWnd::messageMap), (AFX_MSGMAP_ENTRY*)&(CView::_messageEntries) };
    
    AFX_MSGMAP_ENTRY CView::_messageEntries[] = { 
         {WM_COMMAND, 0, (WORD)122, (WORD)122, 1, (AFX_MSGMAP)0},
         {0, 0, 0, 0, 0, (AFX_MSGMAP)0}
    };
    

    以图表示则为:

      

    MFC中定义了各种类似ON_COMMAND这样的宏,把各式各样的消息与特定的消息处理函数关联起来。

    下面的代码中每一个CCmdTarget的衍生类都产生类似上图的消息映射表:

    //in head file
    class CObject
    {
    	//....
    	//注意:CObject并不属于消息流动网的一份子
    };
    
    class CCmdTarget :public CObject
    {
    	//...
    	DECLARE_MESSAGE_MAP()
    };
    
    class CWinThread :public CCmdTarget
    {
    	//...
    	//注意:CWinThread并不属于消息流动网的一份子
    };
    
    class CWinApp :public CWinThread
    {
    	//...
    	DECLARE_MESSAGE_MAP()
    };
    
    class CDocument :public CCmdTarget
    {
    	//...
    	DECLARE_MESSAGE_MAP()
    };
    
    class CWnd :public CCmdTarget
    {
    	//...
    	DECLARE_MESSAGE_MAP()
    };
    
    class CFrameWnd :public CWnd
    {
    	//...
    	DECLARE_MESSAGE_MAP()
    };
    
    class CView :public CWnd
    {
    	//...
    	DECLARE_MESSAGE_MAP()
    };
    
    class CView :public CWnd
    {
    	//...
    	DECLARE_MESSAGE_MAP()
    };
    
    class CMyWinApp :public CWinApp
    {
    	//...
    	DECLARE_MESSAGE_MAP()
    };
    
    class CMyFrameWnd :public CFrameWnd
    {
    	//...
    	DECLARE_MESSAGE_MAP()
    };
    
    class CMyDoc :public CDocument
    {
    	//...
    	DECLARE_MESSAGE_MAP()
    };
    
    class CMyView :public CView
    {
    	//...
    	DECLARE_MESSAGE_MAP()
    };
    
    //in implementation file
    BEGIN_MESSAGE_MAP(CWnd, CCmdTarget)
    	ON_COMMAND(CWndid, 0)
    END_MESSAGE_MAP
    
    BEGIN_MESSAGE_MAP(CFrameWnd, CWnd)
    	ON_COMMAND(CFrameWndid, 0)
    END_MESSAGE_MAP()
    
    BEGIN_MESSAGE_MAP(CDocument, CCmdTarget)
    	ON_COMMAND(CDocumentid, 0)
    END_MESSAGE_MAP()
    
    BEGIN_MESSAGE_MAP(CView, CWnd)
    	ON_COMMAND(CViewid, 0)
    END_MESSAGE_MAP()
    
    BEGIN_MESSAGE_MAP(CWinApp, CCmdTarget)
    	ON_COMMAND(CWinAppid, 0)
    END_MESSAGE_MAP()
    
    BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp)
    	ON_COMMAND(CMyWinAppid, 0)
    END_MESSAGE_MAP()
    
    BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
    	ON_COMMAND(CMyFrameWndid, 0)
    END_MESSAGE_MAP()
    
    BEGIN_MESSAGE_MAP(CMyDoc, CDocument)
    	ON_COMMAND(CMyDocid, 0)
    END_MESSAGE_MAP()
    
    BEGIN_MESSAGE_MAP(CMyView, CView)
    	ON_COMMAND(CMyViewid, 0)
    END_MESSAGE_MAP()
    
    //同时也设定了消息的终极标靶CCmdTarget的映射表内容:
    AFX_MSGMAP CCmdTarget::messageMap =
    {
    	NULL,
    	&CCmdTarget::_messageEntries[0]
    };
    
    AFX_MSGMAP_ENTRY CCmdTarget::_messageEntries =
    {
    	{0, 0, CCmdTargetid, 0, AfxSig_end, 0 }
    }
    

    以上构成了完整的消息流动网,如下图:

     

  • 相关阅读:
    前台js的复制与粘贴
    idea
    前台 js easyUI datagrid 杂记 验证(disable)
    《命运赋》
    前台
    js 、 java去除字符串中的数字
    【 协议 】 freemodbus的分层结构分析
    王爽 汇编11.10(2)编程用串传送指令,将F000H段中最后的16个字节复制到data段中
    王爽 汇编11.10(1)编程用串传送指令,将data段中的第一个字符串赋值到它后面的空间中
    汇编语搜索言中32位CPU多出的两个FS、GS段寄存器,全称是什么啊?
  • 原文地址:https://www.cnblogs.com/zhehan54/p/5173874.html
Copyright © 2020-2023  润新知