接上篇, 窗口消息(3)
5. MFC中的消息分发
消息的Hook:标准的消息循环被MFC封装在AfxPumpMessage方法中。消息一旦被Dispatch,那么接下来如何进入到窗口的WndProc方法中呢?MFC在窗口创建时,使用AfxHookWindowCreate方法(使用SetWindowsHookEx API方法+WH_CBT参数),使得消息能够输出到一个全局方法AfxWndProcBase中(如果是静态链接到MFC,则为AfxWndProc)。以此为出发点,MFC通过消息的窗口句柄获得对应的窗口对象,然后调用其WndProc方法(在AfxCallWndProc中)。
在消息被分发前,有两点值得注意:
1. WM_KICKIDLE消息不会被分发。该消息为MFC私有消息。其处理方式请参见《对话框》一文。
2. AfxPreTranslateMessage先被调用。如果返回TRUE,那么消息将不会被进一步处理(分发)
在MFC中,根据分发机制的不同,可将消息分为两类,一类为命令消息,即:WM_COMMAND消息,包括:菜单响应消息,一些基础控件的通知消息(例如:BN_CLICKED,EN_UPDATE等)。它的分发路径为由顶向下,即:从应用主窗口向下传递。另一类为直接分发到窗口的消息,包括:鼠标消息、键盘消息。
通知消息还有一种形式,即:WM_NOTIFY消息。
实际上,从消息的角度来看,消息都是直接到窗口的。只有在MFC的框架下,才引申出消息分发和路由的概念。对于所谓的命令消息的传递,是由命令消息的接收窗口发起的,结合MFC的各种消息映射宏,能够方便地处理消息,最直接地就是避免了消息参数格式的转换,另外,消息可以灵活地被路由。
1.1 WM_COMMAND消息
下面的场景是在一个对话框上点击一个按钮后,程序调用堆栈的情况:
1.Dialog1.exe!CDialog1Dlg::OnBnClickedButton1() Line 157 C++
2.mfc71d.dll!_AfxDispatchCmdMsg(CCmdTarget * pTarget=0x0012fe38, unsigned int nID=1000, int nCode=0, void (void)* pfn=0x004114dd, void * pExtra=0x00000000, unsigned int nSig=53, AFX_CMDHANDLERINFO * pHandlerInfo=0x00000000) Line 89 C++
3.mfc71d.dll!CCmdTarget::OnCmdMsg(unsigned int nID=1000, int nCode=0, void * pExtra=0x00000000, AFX_CMDHANDLERINFO * pHandlerInfo=0x00000000) Line 396 + 0x 27 C++
4.mfc71d.dll!CDialog::OnCmdMsg(unsigned int nID=1000, int nCode=0, void * pExtra=0x00000000, AFX_CMDHANDLERINFO * pHandlerInfo=0x00000000) Line 88 + 0x 18 C++
5.mfc71d.dll!CWnd::OnCommand(unsigned int wParam=1000, long lParam=264964) Line 2550 C++
6.mfc71d.dll!CWnd::OnWndMsg(unsigned int message=273, unsigned int wParam=1000, long lParam=264964, long * pResult=0x 0012f 81c ) Line 1759 + 0x 1c C++
7.mfc71d.dll!CWnd::WindowProc(unsigned int message=273, unsigned int wParam=1000, long lParam=264964) Line 1745 + 0x1e C++
8.mfc71d.dll!AfxCallWndProc(CWnd * pWnd=0x0012fe38, HWND__ * hWnd=0x00030aba, unsigned int nMsg=273, unsigned int wParam=1000, long lParam=264964) Line 241 + 0x 1a C++
9.mfc71d.dll!AfxWndProc(HWND__ * hWnd=0x00030aba, unsigned int nMsg=273, unsigned int wParam=1000, long lParam=264964) Line 389 C++
10.mfc71d.dll!AfxWndProcBase(HWND__ * hWnd=0x00030aba, unsigned int nMsg=273, unsigned int wParam=1000, long lParam=264964) Line 209 + 0x 15 C++
上述内容中,除了前面已经提到的几个MFC中所有消息的入口及相关方法外,已经用红色标出了消息链条上更进一步的重要的方法,这些方法也是命令消息传递最基本的路线。其中,
CWnd::WndProc