一、消息映射表
AFX_MSGMAP_ENTRY结构表示消息映射表中的一个消息映射项,将消息与处理该消息的成员关联起来。
struct AFX_MSGMAP_ENTRY { UINT nMessage; //消息标志 UINT nCode; //控制代码或WM_NOTIFY通知码 UINT nID; //控件ID,如果是窗口消息,其值为0 UINT nLastID; //一定范围命令的最后一个命令或控件ID,用于支持组消息映射 UINT_PTR nSig; //消息处理成员函数的签名代码 AFX_PMSG pfn; //消息处理函数 };
AFX_MSGMAP表示一个消息映射表,包括两个成员,一个指向基类的消息映射表,一个指向一组消息映射项的指针。
struct AFX_MSGMAP { //指向基类消息映射表的指针 #ifdef _AFXDLL const AFX_MSGMAP * (PASCAL * pfnGetBaseMap)(); #else const AFX_MSGMAP * pBaseMap; #endif //消息映射表的表项,将消息与成员函数关联起来 const AFX_MSGMAP_ENTRY * lpEntries };
由此可见,每个类的消息映射表中均包含了父类的消息映射表的信息,因此消息映射表提供了基类成员处理子类消息的能力。
二、在CCmdTarget派生类中添加消息映射表
(1)在声明类的头文件中加入DECLARE_MESSAGE_MAP()宏。
#ifdef _AFXDLL #define DECLARE_MESSAGE_MAP() \ private:\ static const AFX_MSGMAP_ENTRY _messageEntries[]; //容纳消息映射项的静态数组 protected:\ static const AFX_MSGMAP messageMap;\ //消息映射表 static const AFX_MSGMAP * PASCAL GetThisMessageMap();\ virtual const AFX_MSGMAP * GetMessageMap() const;\ //获取消息映射表的指针 #else #define DECLARE_MESSAGE_MAP() \ private:\ static const AFX_MSGMAP_ENTRY _messageEntries;\ //容纳消息映射项的静态数组 protected:\ static const AFX_MSGMAP messageMap;\ //消息映射表 virtual const AFX_MSGMAP * GetMessageMap() const;\ //获取消息映射表的指针 #endif
(2)在声明类的实现文件中加入BEGIN_MESSAGE_MAP(theClass,baseClass)宏和END_MESSAGE_MAP宏。
BEGIN_MESSAGE_MAP宏完成三件事:
a.返回当前类的消息映射表的虚成员。
b.初始化静态消息映射表成员。
c.开始初始化消息映射表项数组
#ifdef _AFXDLL #define BEGIN_MESSAGE_MAP(theClass,baseClass)\ const AFX_MSGMAP * PASCAL theClass::GetThisMessageMap()\ {return &theCalss::messageMap;}\ const AFX_MSGMAP * theClass::GetMessageMap() const\ //返回当前类的消息映射表的虚成员 {return &theClass::messageMap;}\ AFX_COMDAT const AFX_MSGMAP theClass::messageMap = \ //设置基类的消息映射表入口,设置消息映射表的消息映射项数组的入口 {&baseClass::GetThisMessageMap,&theClass::_messageEntries[0]}; AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = \ //开始初始化类的静态消息映射表项数组 {\ #else #define BEGIN_MESSAGE_MAP(theClass,baseClass)\ const AFX_MSGMAP * theClass::GetMessageMap() const\ //返回当前类的消息映射表的虚成员 {return &theClass::messageMap;}\ AFX_COMDOT const AFX_MSGMAP theClass::messageMap = \ //设置基类的消息映射表入口,设置消息映射表的消息映射项数组的入口 {&baseClass::messageMap,&theClass::_messageEntries[0]};\ AFX_COMDOT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = \ //开始初始化类的静态消息映射表项数组 {\ #endif
END_MESSAGE_MAP宏在类的消息映射数组中添加最后一项,以作为数组结束标记。
#define END_MESSAGE_MAP()\ {0,0,0,0,AfxSig_end,(AFX_PMSG)0}\ };\
For example:
BEGIN_MESSAGE_MAP(CMyView,CView) //...忽略了消息映射宏 END_MESSAGE_MAP
三、在BEGIN_MESSAGE_MAP宏和END_MESSAGE_MAP宏之间加入相应的消息映射宏
MFC中的消息主要分为四种:窗口消息、通知信息、命令消息和反射消息。
(1)CWnd类将窗口消息和其成员函数挂钩起来,窗口消息又称标准消息。
#define ON_WM_DESTROY()\ {WM_DESTROY,0,0,0,AfxSig_vv,\ (AFX_PMSG)(AFX_PMSGW)(static_cast<void (AFX_MSG_CALL CWnd::*)>(OnDestroy))},
(2)命令消息的消息映射宏如下:(包含两个参数,一个是表示要处理的命令ID,另一个是处理该命令的成员函数)
ON_COMMAND宏和ON_COMMAND_RANGE宏:不会将命令传递给处理链的下一个对象。
#define ON_COMMAND(id,memberFxn)\ {WM_COMMAND,CN_COMMAND,(WORD)id,AfxSigCmd_v,\ static_cast<AFX_PMSG>(memberFxn)},
#define ON_COMMAND_RANGE(id,idLast,memberFxn)\ {WM_COMMAND,CN_COMMAND,(WORD)id,(WORD)idLast,AfxSigCmd_RANGE,\ (AFX_PMSG)(static_cast<void (AFX_MSG_CALL CCmdTarget::*)(UINT)>(memberFxn))},
ON_COMMAND_EX宏和ON_COMMAND_EX_RANGE宏:返回FALSE允许命令沿着命令处理链继续处理。
#define ON_COMMAND_EX(id,idLast,memberFxn)\ {WM_COMMAND,CN_COMMAND,(WORD)id,(WORD)idLast,AfxSigCmd_EX,\ (AFX_PMSG)(static_cast<BOOL (AFX_MSG_CALL CCmdTarget::*)(UINT)>(memberFxn))},
ON_UPDATE_COMMAND_UI宏和ON_UPDATE_COMMAND_UI_RANGE宏:用于更新菜单、控制条命令按钮的外观。
#define ON_UPDATE_COMMAND_UI(id,memberFxn)\ {WM_COMMAND,CN_UPDATE_COMMAND_UI,(WORD)id,(WORD)id,AfxSigCmdUI,\ (AFX_MSG)(static_cast<void (AFX_MSG_CALL CCmdTarget::*)(CCmdUI*)>(memberFxn))},
(3)通知消息
控件通知消息是控件窗口发送到其父窗口的消息,父窗口的消息映射表通过添加控件通知消息映射宏来处理子控件窗口发来的通知消息。控件通知消息映射宏有ON_CONTROL和ON_CONTROL_RANGE。
#define ON_CONTROL(wNotifyCode,id,memberFxn)\ {WM_COMMAND,(WORD)wNotifyCode,(WORD)id,(WORD)id,AfxSigCmd_v,\ (static_cast<AFX_PMSG>(memberFxn))},
#define ON_CONTROL_RANGE(wNotifyCode,id,idLast,memberFxn)\ {WM_COMMAND,(WORD)wNotifyCode,(WORD)id,(WORD)idLast,AfxSigCmd_RANGE,\ (AFX_PMSG)(static_cast<void (AFX_MSG_CALL CCmdTarget::*)(UINT)>(memberFxn))},
通知消息即WM_NOTIFY消息,相应的宏为ON_NOTIFY和ON_NOTIFY_RANGE。
#define ON_NOTIFY(wNotifyCode,id,memberFxn)\ {WM_NOTIFY,(WORD)(int)wNotifyCode,(WORD)id,(WORD)id,AfxSigNotify_v,\ (AF_PMSG)(static_cast<void (AFX_MSG_CALL CCmdTarget::*)(NMHDR*,LRESULT*)>(memberFxn))},
(4)反射消息
对子窗口向父窗口发送的通知消息或控件通知,父窗体会将该消息转化为对应的反射消息发送给子窗体,以优先让子窗体处理。
反射的通知消息的映射宏ON_NOTIFY_REFLECT,及增强版的ON_NOTIFY_REFLECT_EX宏。
#define ON_NOTIFY_REFLECT(wNotifyCode,memberFxn)\ {WM_NOTIFY+WM_REFLECT_BASE,(WORD)(int)wNotifyCode,0,0,AfxSigNotify_v,\ (AFX_PMSG)(static_cast<void (AFX_MSG_CALL CCmdTarget::*(NMHDR*,LRESULT*))>(memberFxn))},
反射的控件通知消息的映射宏ON_CONTROL_REFLECT,及增强版的ON_CONTROL_REFLECT_EX宏。
#define ON_CONTROL_REFLECT\ {WM_COMMAND+WM_REFLECT_BASE,(WORD)wNotifyCode,0,0,AfxSigCmd_v,\ (AFX_PMSG)(static_cast<BOOL (AFX_MSG_CALL CCmdTarget::*)(void)>(memberFxn))},
其他反射消息映射宏
ON_WM_CTLCOLOR_REFLECT
ON_WM_DRAWITEM_REFLECT
ON_WM_MEASUREITEM_REFLECT
ON_WM_DELETEITEM_REFLECT
ON_WM_CHARTOITEM_REFLECT
ON_WM_VKEYTOITEM_REFLECT
ON_WM_COMPAREITEM_REFLECT
ON_WM_HSCROLL_REFLECT
ON_WM_VSCROLL_REFLECT
ON_WM_PARENTNOTIFY_REFLECT
不同类别的消息,其消息映射宏是不同的,也具有不同的参数。