探索MFC读书笔记——CommandRouting(命令绕行)

一、Windows消息的分类

    1、标准消息:除WM_COMMAND外,其他所有以WM开头的消息;

    2、非标准消息:以WM_COMMAND形式呈现:

        命令消息:由菜单、工具栏、加速键产生,在MFC中通过菜单项的标识(ID)区分不同消息,在SDK中通过消息的wParam参数来区别不同消息,从CCmdTarget类派生下来的类,都可以接收这类消息。

        通告消息:有控件产生,比如:按钮的单击、列表框的选择都会产生此类消息,目的是通告事件的发生,这类消息的目的是为了向父窗口(通常是对话框)通知事件的发生。比如:按钮的单击、列表框的选择都会产生这类消息,目的是通告事件的发生,这类消息目的是为了向父窗口(通常是对话框)通知事件的发生,这类消息也是以WM_COMMAND

形式呈现的,从CCmdTarget派生的类,都可以收到该消息

 

二、消息绕行

    1、标准消息

         标准windows消息根据MessageMap索引,从派生类流向基类,没有旁流的可能。

    2、非标准消息

         如果命令消息时WM_COMMAND,则消息的流向较为特殊。

(1)、与消息绕行有关的成员函数

              AfxWndProc

              AfxCallWndProc

         virtual CCmdTarget::OnCmdMsg

         virtual CDocument::OnCmdMag

              virtual CWnd::WindowProc

              virtual CWnd::OnCommand

              virtual CWnd::DefWindowProc

         virtual CFrameWnd::OnCommand

         virtual CFrameWnd::OnCmdMsg

              virtual CView::OnCmdMsg

(2)、消息绕行过程

        Windows应用程序的动力源在CWinThread::Run中,该线程函数维持消息泵的运行。

        *首先在WinThread::Run函数中不断调用API函数AfxWndProc;

        *接着是AfxCallWndProc,在该函数中调用pWnd->WindowProc;

        *pWnd->WindowProc是虚函数,如果是pWnd是从CFrameWnd派生下来的,那么调用的就是CFrameWnd::WindowProc,如果pWnd是从CView派生下来的,那么调用的就是CView::WindowProc, 由于CView和CFrameWnd都没有改写WindowProc,因此调用的都是CWnd::WindowProc;

        *CWnd::WindowProc函数首先判断消息是否是WM_COMMAND,如果不是使用消息映射表比对AFX_MSGMAP_ENTRY中的每一个元素,比对成功调用相应处理函数;如果是WM_COMMAND消息,调用虚函数OnCommand;如果使pWnd是CFrameWnd的派生类,调用CFrameWnd::OnCommand,CFrameWnd::OnCommand执行末尾会返回CWnd::OnCommand的执行结果,如果使CView的派生类,应该调用CView的OnCommand函数,因为CView没有改写OnCommand函数,因此实际调用CWnd::OnCommand.

        *CWnd::OnCommand返回虚函数OnCmdMsg的结果。OnCmdMsg是CCmdTarget的虚函数:

        根据this指针的指向,可能调用的函数是CFrameWnd::OnCmdMsg或CView::OnCmdMsg或CDocument::OnCmdMsg或CWinApp::OnCmdMsg(由于CWinApp未改写该函数,所以调用的是CCmdTarget::OnCmdMsg)

        --->如果调用的是CFrameWnd::OnCmdMsg,则该函数按照以下顺序执行:

              CView* pView = GetActiveView();
              if (pView->OnCmdMsg(nID, nCode)) 
                     return TRUE;
              // then pump through frame
              if (CWnd::OnCmdMsg(nID, nCode)) 
                     return TRUE;
              // last but not least, pump through app
                     CWinApp* pApp = AfxGetApp();
              if (pApp->OnCmdMsg(nID, nCode)) 
                     return TRUE;
              return FALSE;

        --->如果调用的是CView::OnCmdMsg,则该函数按照以下顺序执行:

             BOOL CView::OnCmdMsg(UINT nID, int nCode)
             {
                  cout<< "CView::OnCmdMsg()" << endl;
                  if(CWnd::OnCmdMsg(nID, nCode)) 
                  return TRUE;
                  BOOLbHandled = FALSE;
                  bHandled = m_pDocument->OnCmdMsg(nID, nCode);  
                  return bHandled;
             }

        --->如果调用的是CWinApp::OnCmdMsg或CWnd::OnCmdMsg,则由于CWinApp和CWnd没有改写该函数,所以会调用CCmdTarget::OnCmdMsg)函数,该函数按照以下顺序执行:

         BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode)
         {
                cout << "CCmdTarget::OnCmdMsg()" << endl;
                // Now look through message map to see if it applies to us
               AFX_MSGMAP* pMessageMap;
               AFX_MSGMAP_ENTRY* lpEntry;
               for(pMessageMap = GetMessageMap(); pMessageMap != NULL;
               pMessageMap= pMessageMap->pBaseMessageMap)
               {
                    lpEntry= pMessageMap->lpEntries;
               }

         }

        --->如果调用的是CDocument::OnCmdMsg,则该函数按照以下顺序执行:

         BOOL CDocument::OnCmdMsg(UINT nID, int nCode)
         {
                if (CCmdTarget::OnCmdMsg(nID, nCode))
                     return TRUE;
                return FALSE;
         }

        *如果此时仍未找到匹配的消息处理函数,则退回到CWnd::WindowProc,然后调用CWnd::DefWindowProc,该函数最终会调用WindowsAPI中的DefWindowsProc。消息绕行到此结束。

 

(3)、当CMyFrameWnd 对象获得一个WM_COMMAND,所引起的函数调用次序。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值