[原创]MFC消息映射机制

MFC消息映射机制

MFC程序是靠消息映射驱动的,当用户执行鼠标/键盘、移动窗口等操作时,windows系统基于这些动作生成消息并存入系统消息队列。MFC程序执行消息循环,取出属于自己的消息并执行这些消息。MFC处理消息时,先进行预处理,预处理返回真的消息则当前处理结束,继续抓取下一条消息进行处理,预处理返回假的消息再分发处理,进入MFC消息映射机制。

1.       消息预处理

MFC消息循环在抓取消息后,先使用AfxPreTranslateMessage进行消息预处理,对没有预处理的消息再进行翻译和分发处理。


预处理流程从接受消息的窗口出发,逐步向其父窗口迭代,每次均使用迭代窗口进行预处理,直到窗口指针为空为止。没有预处理的消息则进行翻译(TranslateMessage)和分发处理(DispachMessage)。预处理函数(PreTranslateMessage)为虚函数。


2.       消息分发处理


分发时,根据CWnd::OnWndMsg(wincore.cpp:1760中)处理消息的方法,将消息分WM_COMMAND、WM_NOTIFY和其他消息。菜单消息、按钮消息等通过ON_COMMAND、ON_CONTROL等宏实现的消息属于WM_COMMAND消息,与WM_NOTIFY消息相比,只能传递一个通知码。WM_NOTIFY消息传递复杂一些(LPARAM参数使用一个NMHDR结构体),一般LISTCTRL控件传递的属于WM_NOTIFY消息,其他消息的处理方式参见2.3。

2.1   WM_COMMAND处理

Message Source

wParam (high word)

wParam (low word)

lParam

Menu

0

Menu identifier (IDM_*)

0

Accelerator

1

Accelerator identifier (IDM_*)

0

Control

Control-defined notification code

Control identifier

Handle to the control window

WM_COMMAND消息发送个父窗口,其消息参数如上图所示,处理方式如下:

CWnd::OnWndMsg

CWnd::OnCommand

         检测命令是否可用/CWnd::ReflectLastMsg

CmdTarget::OnCmdMsg

由于是虚函数,在实际运行时,可能根据对象的不同调用到不同类中的代码,所以此处以wincore.cpp中的CWnd对象为主,其余类中的处理方式可参阅具体的源代码。

CWnd::OnCommand处理流程:对于菜单和加速键(上表中lParam为0),先判断当前菜单、命令是否可用,然后再调用CCmdTarget::OnCmdMsg处理;对于控件,先反射给子窗口处理,如果子窗口没有处理,则调用CCmdTarget::OnCmdMsg进行处理。


CCmdTarget::OnCmdMsg处理流程:从当前类开始,向父类逐步向上查找,如果在消息映射表中找到了处理函数,则调用处理,否则到根类CCmdTarget还没有找到时,则使用默认处理方式DefWindowProc。

由于CWnd::OnCommand和CCmdTarget::OnCmdMsg是虚函数,所以可重写这两个函数,改变消息处理方法。MFC的CDialog,CFrameWnd, CSplitterWnd等类都重写了OnCOmmand函数。

2.2   WM_NOTIFY处理

wParam

lParam

Control identifier

NMHDR

NMHDR的定义如下:

typedef struct tagNMHDR{

    HWND hwndFrom;

    UINT_PTR idFrom;

    UINT code;

} NMHDR;

WM_NOTIFY消息发送给父窗口,消息参数的wParam值为控件ID,lParam值指向NMHDR,或指向第一个成员为NMHDR的结构体,可处理复杂的消息。处理方式如下:

CWnd::OnWndMsg

CWnd::OnNotify

                       CWnd::ReflectLastMsg

CmdTarget::OnCmdMsg

CWnd::OnNotify先调用ReflectLastMsg反射给子窗口处理,如果子窗口没有处理,则调用OnCmdMsg处理。


2.3  其他消息处理

其他消息如WM_VSCROLL,WM_CREATE等,消息参数、发送对象参考MSDN。从当前类开始,向父类逐步向上查找,如果在消息映射表中找到了处理函数,则调用处理。

3.      反射消息处理

在消息分发时,带句柄的WM_COMMAND消息和WM_NOTIFY消息,都会先反射给子窗口处理,最终通过CWnd::RefelectChildNotify进行反射处理,此时的this指针指向子窗口。消息码在当前的基础上,增加了WM_REFLECT_BASE。一般对COMBOBOX,EDIT,LISTCTRL进行子类化,然后实现其反射消息。


4.      小结

一般的WM_CREATE,WM_VSCROLL消息,映射机制简单,从子类到父类逐级查找,而对于WM_NOTIFY,WM_COMMAND,MFC提供了增加了OnNotify,OnCommand处理流程,并且对于CWnd,CFrameWnd等不同的类,OnNotify,OnCommand等内部的流程也是不同,这是通过虚函数实现的,OnNotify,OnCommand没有找到消息映射函数时,再从子类到父类逐级查找。需要注意的是,WM_NOTIFY,WM_COMMAND时发送给控件的父窗口的,如果我们通过SPY++剖析消息流程时,除了监控控件本身,控件的父窗口也要监控。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值