按惯例,这一篇文章主要还是作者读《深入浅出MFC》整理的一些笔记。
Message Mapping
消息映射表其实是一张类库地图,一个子类的消息需要一级一级传达到父类,再父类,直至CCmd类或者CObject类。
数据结构AFX_MSGMAP、AFX_MSGMAP_ENTRY
struct AFX_MSGMAP
{
AFX_MSGMAP* pBaseMessageMap;
AFX_MSGMAP_ENTRY* lpEntries;
};
struct AFX_MSGMAP_ENTRY // MFC 4.0 format
{
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 nSig; // signature type (action) or pointer to message #
AFX_PMSG pfn; // routine to call (or special value)
};
其中AFX_PMSG 为函数指针:
typedef void (CCmdTarget::*AFX_PMSG)(void);
实际的CWnd类中出现的DECLARE_MESSAGE_MAP、END_MESSAGE_MAP()、ON_COMMAND等等的宏:
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; \
__pragma(warning(push)) \
__pragma(warning(disable: 4640)) /* message maps can only be called by single threaded message pump */ \
static const AFX_MSGMAP_ENTRY _messageEntries[] = \
{
#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 END_MESSAGE_MAP() \
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \
}; \
__pragma(warning(pop)) \
static const AFX_MSGMAP messageMap = \
{ &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; \
return &messageMap; \
} \
PTM_WARNING_RESTORE
把这些宏展开整理下一就是下面这一段:
PTM_WARNING_DISABLE
const AFX_MSGMAP* theClass::GetMessageMap() const
{ return GetThisMessageMap(); }
const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap()
{
typedef theClass ThisClass;
typedef baseClass TheBaseClass;
__pragma(warning(push))
__pragma(warning(disable: 4640)) /* message maps can only be called by single threaded message pump */
static const AFX_MSGMAP_ENTRY _messageEntries[] =
{
{ 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)
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }
};
__pragma(warning(pop))
static const AFX_MSGMAP messageMap =
{ &TheBaseClass::GetThisMessageMap, &_messageEntries[0] };
return &messageMap;
}
PTM_WARNING_RESTORE
可以看到,这段宏展开最核心的定义就是中间的AFX_MSGMAP_ENTRY _messageEntries[]的定义了,在这里面把消息和响应函数做好了绑定,你每加一个ON_COMMAND指令或者是每加一个其他的新指令,都会在这个_messageEntries[]里面多出一个AFX_MSGMAP_ENTRY结构,告诉你哪个消息应该跟哪个响应函数对应(同在一个_messageEntries[]里,MFC主程序做WndProc的时候就自动把_messageEntries[]的响应循环做了监听判断了)。