1.MFC中的消息分为三种
2.为什么要消息路由?什么叫消息路由?
如果像SDK那样,我们的程序只有一个窗口,一个窗口函数,那哪还有消息路由呢?所有的消息都有一个窗口函数来处理了。至所以要消息路由,是因为MFC程序中有CMyView,CMyDoc,CMyFrameWnd,CMyApp等,MFC框架要做的工作是给用户提供一个机会,让用户可以选择这些类当中的任意一个来处理我们的命令消息。
注意,消息路由主要是针对上述的第二类消息(命令消息)。对于第一类窗口消息,其消息的接收者是确定的,不需要路由。比如:对于WM_CREATE消息,处理这个消息的类就是产生这个消息的窗口,你不可能让CMyDoc,CMyFrame,CMyApp去处理CView的WM_CREATE消息,那根本不符合逻辑,MFC框架当然也不会让你那么做。而对于来自菜单,工具栏的命令消息,用户是有选择权的,用户可以选择其接收者为View,Doc,App,Frame等当中的任意一个。下面就详细说一下命令消息的路由过程,主要通过分析MFC源代码。
3.首先说一下函数的调用顺序.所有的三类消息初始都被送入一个全局函数AfxWndProc,
之后是pWnd->WindowProc,pWnd->OnWndMsg,在OnWndMsg()中这三类消息分道扬镳了,其中第一类消息由OnWndMsg自己处理,第二类交给了OnCommand(),第三类交给了OnNotify(),下面主要说第二类的处理过程:
AfxWndProc()
注意:WindowProc和OnWndMsg这两个函数实际只有CWnd类中才有,在其它类中并没有重写这两个虚函数,所以我们调用的是CWnd::WindowProc()和CWnd::OnWndMsg(),但要注意:它们的this指针是指向我们的程序中的具体类对象(这是下面运用多态的前提)。
下面以多文档为例,解析其对第二类消息的处理过程:
AfxWndProc-->CWnd::WindProc()-->CWnd::OnWndMsg()(此处三类消息分道扬镳)-->CMyFrameWnd::OnCommand(不存在)-->CMDIFrameWnd::OnCommand(),
下面是CMDIFrameWnd::OnCommand()的源代码:
父框架窗口是先认子框架窗口来处理,如果其不处理,再自己处理。
那子框架窗口又是如何处理的呢?由于子框架窗口没有重写上面的WindowProc,OnWndMsg,OnCommand,所以最终调用的是其父类CFrameWnd::OnCommand().注意:这里虽然调用了两次CFrameWnd::OnCommand,
但其this指针却不同,一个this指针指向的是CMyChildWnd,一个指向的是CFrameWnd.下面是CFrameWnd::OnCommand()源代码:
子框架窗口是先让CMyView处理,如果其不处理,再自己处理(CWnd::OnCmdMsg),否则,再 App处理.
那CMyView又是如何处理的呢,下面是其CView::OnCmdMsg()源代码
{
}
CMyView是先让自己处理,如果其不处理,再让其对应的Document处理,而Document是先自己处理,如果自己不处理,现让CDocTemplate处理(此处这一代码就不在写出,因为通常不会让文档模板处理)
所谓自己处理,就是调用CCmdTarget::OnCmdMsg(),CWnd并没有重写这个函数,调用CWnd::OnCmdMsg就是调用CCmdTarget::OnCmdMsg(),这个函数的主要干的事情就是:调用GetMessageMap()这个虚函数,获得我们的子类的消息映射表,然后把该消息和此消息映射表对照,看其是否有对应的消息响应函数。如果没有,再看其父类是否有,父类也没有,就返回false,让其它的类来处理了。
注意:这里App先于MainFrame,在有些书上说成是App最后(特纠正)
对于单文档,那就比这简单了,
CMyView-->CMyDoc-->CSingleDocTemplate-->CMyFrame-->CMyApp
注意:在单文档中CMyApp是最后,因为这里的主框架实际占据的是MDI中子框架的位置。
联系客服