《MFC程序开发参考大全》学习笔记_5

窗口消息处理

MFC中的窗口函数

在MFC类库中,CWnd封装了窗口类的基类,并提供了处理消息的窗口函数WindowProc。在注册窗口类的时候,它是如何成为类的窗口函数的呢?以对话框的创建为例介绍WindowProc如何成为窗口类的窗口函数。

CMyDlg dlg;
dlg.Create(IDD_MYDLG_DIALOG,this);

当对话框执行Create方法时,会执行一系列的动作,首先调用CDialog的Create方法;

在CDialog的Create方法中又调用了CreateIndirect方法,根据模板直接创建对话框;

在CreateIndirect方法中又调用了重载的CreateIndirect方法,跟踪CreateIndirect;

在CreateIndirect方法中调用CreateDlgIndirect方法,实现了创建对话框,其中CreateDlgIndirect方法是CWnd类中一个比较重要的发放,它能够实现对话框类的注册、窗口函数的设置以及窗口的创建;

在CreateDlgIndirect方法中调用了AfxDeferRegisterClass方法,实现了注册窗口类,AfxDeferRegisterClass方法判断窗口类是否已经注册,如果没有注册,将调用AfxRegisterClass方法注册窗口类;

在AfxDeferRegisterClass方法中定义了窗口类的结构,并调用AfxRegisterClass方法注册窗口类。这里需要注意的是:窗口类的窗口函数设置为DefWindowProc,而不是CWnd类的WindowProc方法。那么CWnd类的WindowProc方法是如何成为窗口函数的呢?

CreateDlgIndirect方法调用AfxHookWindowCreate方法向系统中安装了钩子函数,分析AfxHookWindowCreate函数;

AfxHookWindowCreate方法调用SetWindowsHookEx方法安装一个钩子函数_AfxCbtFilterHook到钩子链中,监视系统发生的事件,当程序中有窗口创建时,将执行钩子函数_AfxCbtFilterHook;

_AfxCbtFilterHook调用AfxGetAfxWndProc方法获得窗口函数,通过调用SetWindowLongPtr方法将其设置为某个窗口的窗口函数;

AfxGetAfxWndProc方法在内部调用了AfxWndProc方法;

AfxWndProc方法又调用了AfxCallWndProc方法来获得窗口函数;

AfxCallWndProc方法最终嗲用了CWnd类中的WindowProc方法。

普通窗口消息处理

MFC中消息处理函数是存储在消息映射表中的,那么窗口函数是如何访问消息映射表执行消息处理函数的呢?这需要分析CWnd类中的WindowProc方法;

WindowProc方法首先调用OnWndMsg方法来处理消息,如果消息没有处理,则调用默认的窗口函数DefWindowProc来处理消息;

在OnWndMsg方法中首先判断消息是否为命令消息(WM_COMMAND),如果是,则调用OnCommand方法。否则继续判断消息是否为通知消息(WM_NOTIFY),如果是,则调用OnNotify方法。否则,对于一般的窗口消息,则搜索消息映射表,并调用相应的处理函数。

命令消息处理

从CWnd的OnWndMsg方法中可以发现,对于命令消息,将调用OnCommand方法。

OnCommand方法首先判断消息为命令消息还是控件通知消息,判断依据是lParam参数是否表示窗口句柄,如果是,则表示消息为控件通知消息,否则为命令消息。对于命令消息将调用OnCmdMsg方法处理消息,对于控件通知消息,则调用ReflectLastMsg方法将其转化为反射消息处理,让子控件优先处理;

OnCmdMsg方法是一个虚方法,因此它首先调用对话框本身的OnCmdMsg方法,在对话框本身的OnCmdMsg方法中会依次引起基类CDialog、CWnd、CCmdTarget的OnCmdMsg方法的调用;

在CCmdTarget的OnCmdMsg方法中主要搜索消息映射表,如果找到消息对应的处理函数则调用_AfxDispatchCmdMsg方法执行消息映射表中的消息处理函数。

通知消息处理

对于通知消息CWnd的OnWndMsg方法将调用OnNotify方法;

OnNotify方法根据参数获取通知消息信息,然后调用ReflectLastMsg方法将消息反射给子窗口,让子窗口优先处理消息,如果子窗口没有处理消息,将调用OnCmdMsg方法搜索消息映射表,最后调用_AfxDispatchCmdMsg方法执行消息处理函数。其过程与命令消息处理相同。

反射消息处理

在命令消息处理的OnCommand方法和通知消息处理的OnNotify方法中,都优先调用ReflectLastMsg方法,如果该方法没有处理消息,才调用OnCmdMsg方法处理消息。ReflectLastMsg方法的作用就是将消息反射给子窗口;

ReflectLastMsg首先根据子窗口句柄获得子窗口对象指针,然后调用子窗口的SendChildNotifyLastMsg方法发送反射消息;

SendChildNotifyLastMsg方法调用OnChildNotify方法发送通知;

在OnChildNotify方法中又调用了ReflectChildNotify方法。ReflectChildNotify方法真正实现了反射消息的处理。

猜你喜欢

转载自blog.csdn.net/Small_SaltedFish/article/details/81480478