深入显出MFC笔记(3)

深入浅出MFC笔记(3)

深入显出MFC笔记(3)

深入显出MFC笔记(3)


MFC六大关键技术之六消息的绕行:command routing (消息的二万五千里长征)

LRESULT  AfxWndProc (HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam,CWnd *pWnd) 

{//推动引擎的起始点。在CWinThread:: Run 中被调用

  return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);

}

LRESULT AfxCallWndProc(CWnd* pWnd,,HWND hWnd, UINT nMsg,WPARAM wParam, LPARAM lParam)

{

  LRESULT lResult =  pWnd->WindowProc(nMsg, wParam, lParam);

  return lResult;

} //pWnd-> Window是虚拟函数,调用pWnd指向对象的函数,但子类没有改写其实是CWnd:: WindowProc

LRESULT CWnd::WindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam){

    AFX_MSGMAP* pMessageMap;

    AFX_MSGMAP_ENTRY* lpEntry;

    if (nMsg == WM_COMMAND) {   // 判断消息是否为WM_COMMAND

          if (OnCommand(wParam, lParam))  return 1L; //①调用 OnCommand是一个CWnd的虚拟函数

          else  return (LRESULT) DefWindowProc (nMsg, wParam, lParam);⑨  

    }//消息往父类别推去

    pMessageMap = GetMessageMap();

    for (; pMessageMap != NULL;pMessageMap = pMessageMap->pBaseMessageMap){

            lpEntry = pMessageMap->lpEntries;

            printlpEntries(lpEntry);

    }

    return 0;  

}

1. 如果①指向CMyFrameWnd  对象,那么调用的是CFrameWnd:: OnCommand

2. 如果①指向CMyView 对象,那么调用的是CView:: OnCommand。而因为CView并没有改写OnCommand,所以调用的其实是CWnd:: OnCommand

BOOL CFrameWnd::OnCommand(WPARAM wParam, LPARAM lParam){//以第1种情况为例

  return CWnd::OnCommand(wParam, lParam); //

}

BOOL CWnd::OnCommand(WPARAM wParam, LPARAM lParam){

    return OnCmdMsg(0, 0); //CCmdTarget 的虚拟函数

}//CMyFrameWnd/CMyView/CMyDoc的对象使用CFrameWnd/CView/CDoc::OnCmdMsg

//CMyWinApp对象并没有改写OnCmdMsg ,所以调用的是CCmdTarget::OnCmdMsg

BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode){

      CView* pView = GetActiveView();

     if (pView->OnCmdMsg(nID, nCode))  return TRUE;//

     if (CWnd::OnCmdMsg(nID, nCode))   return TRUE;//

       CWinApp* pApp = AfxGetApp();

       if (pApp->OnCmdMsg(nID, nCode))   return TRUE;//

       return FALSE;

}//Frame窗口处理WM_COMMAND 的次序。最先调用的是pView-> OnCmdMsg 

BOOL CView::OnCmdMsg(UINT nID, int nCode){

  if (CWnd::OnCmdMsg(nID, nCode))  return  TRUE;//

  BOOL bHandled = FALSE;

  bHandled = m_pDocument->OnCmdMsg(nID, nCode); //

  return bHandled;

}//View窗口处理WM_COMMAND 的次序。最先调用⑤CWnd::OnCmdMsgCCmdTarget:: OnCmdMsg

BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode){

    AFX_MSGMAP* pMessageMap;

    AFX_MSGMAP_ENTRY* lpEntry;

for (pMessageMap = GetMessageMap() ; pMessageMap != NULL;

pMessageMap = pMessageMap->pBaseMessageMap){

           lpEntry =  pMessageMap->lpEntries;

  printlpEntries(lpEntry);

     }

return FALSE; // not handled

}

如果在映射表中找到了对应的消息,就调用对应的处理例程,然后也就结束了二万五千里长征。如果没找到,长征还没有结束,这时候退守回到CView:: OnCmdMsg ,调用⑥CDocument:: OnCmdMsg

BOOL CDocument::OnCmdMsg(UINT nID, int nCode){

    if (CCmdTarget::OnCmdMsg(nID, nCode)   return TRUE;

    return FALSE;

}

如果在映射表中还是没找到对应消息,这时候退到CFrameWnd::OnCmdMsg,调用⑦CWnd:: OnCmdMsg (也就是CCmdTarge t:: OnCmdMsg

如果在映射表中还是没找到对应消息,再退回到CFrameWnd:: OnCmdMsg,调用⑧CWinApp :: OnCmdMsg(亦即CCmdTarge t:: OnCmdMsg 

还是没找到对应的消息,退回到⑨CWnd::WindowProc,调用 CWnd:: DefWindowProc。你可以想象,在真正的MFC 中这个成员函数必是调用Windows API 函数:: DefWindowProc


分别从frame  对象和view 对象中推动消息,消息分一般Windows 消息WM_COMMAND

// test Message Routing

AfxWndProc(0, WM_CREATE, 0, 0, pMyFrame);

AfxWndProc(0, WM_PAINT, 0, 0, pMyView);

AfxWndProc(0, WM_COMMAND, 0, 0, pMyView);

AfxWndProc(0, WM_COMMAND, 0, 0, pMyFrame);