MFC下WM_NOTIFY消息處理流程


參考文章:MFC的消息反射機制

    在前一篇文章:MFC消息處理流程概述中描述了MFC消息處理的大體流程。由CWnd::OnWndMsg函數可知,當消息為WM_NOTIFY消息時,調用的是virtual CWnd::OnNotify處理。
[cpp]  view plain  copy
 
  1. if (message == WM_NOTIFY)  
  2. {  
  3.     NMHDR* pNMHDR = (NMHDR*)lParam;  
  4.     if (pNMHDR->hwndFrom != NULL && OnNotify(wParam, lParam, &lResult))  
  5.     goto LReturnTrue;  
  6.     return FALSE;  
  7. }  
[cpp]  view plain  copy
 
  1. BOOL CWnd::OnNotify(WPARAM, LPARAM lParam, LRESULT* pResult)  
  2. {  
  3.     NMHDR* pNMHDR = (NMHDR*)lParam;  
  4.     HWND hWndCtrl = pNMHDR->hwndFrom;  
  5.   
  6.     // get the child ID from the window itself  
  7.     UINT_PTR nID = _AfxGetDlgCtrlID(hWndCtrl);  
  8.     int nCode = pNMHDR->code;  
  9.   
  10.     // reflect notification to child window control  
  11.     if (ReflectLastMsg(hWndCtrl, pResult))  
  12.         return TRUE;        // eaten by child  
  13.   
  14.     AFX_NOTIFY notify;  
  15.     notify.pResult = pResult;  
  16.     notify.pNMHDR = pNMHDR;  
  17.     return OnCmdMsg((UINT)nID, MAKELONG(nCode, WM_NOTIFY), ¬ify, NULL);  
  18. }  
    以上hWndCtrl為子窗口的句柄,通過調用ReflectLastMsg(hWndCtrl, pResult)給子窗口一個自身處理的機會,將消息反射給子窗口處理。ReflectLastMsg返回TRUE,表明子窗口處理了此消息,則OnNotify返回並不交由父窗口處理;反之,表示子窗口未處理此消息,此時,調用OnCmdMsg(...)由父窗口進行處理。
    ReflectLastMsg通過層層調用最終會調用CWnd::ReflectChildNotify函數來處理WM_NOTIFY反射消息。
[cpp]  view plain  copy
 
  1. BOOL PASCAL CWnd::ReflectLastMsg(HWND hWndChild, LRESULT* pResult)  
  2. {  
  3.     CWnd* pWnd = (CWnd*)pMap->LookupPermanent(hWndChild);  
  4.     return pWnd->SendChildNotifyLastMsg(pResult);  
  5. }  
  6.   
  7. BOOL CWnd::SendChildNotifyLastMsg(LRESULT* pResult)  
  8. {  
  9.     return OnChildNotify(pThreadState->m_lastSentMsg.message,  
  10.         pThreadState->m_lastSentMsg.wParam, pThreadState->m_lastSentMsg.lParam, pResult);  
  11. }  
  12.   
  13. BOOL CWnd::OnChildNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult)  
  14. {  
  15.     return ReflectChildNotify(uMsg, wParam, lParam, pResult);  
  16. }  
    CWnd::ReflectChildNotify函數如下:
[cpp]  view plain  copy
 
  1. BOOL CWnd::ReflectChildNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult)  
  2. {  
  3.     // Note: reflected messages are send directly to CWnd::OnWndMsg  
  4.     //  and CWnd::OnCmdMsg for speed and because these messages are not  
  5.     //  routed by normal OnCmdMsg routing (they are only dispatched)  
  6.   
  7.     switch (uMsg)  
  8.     {  
  9.         ......  
  10.     case WM_NOTIFY:  
  11.         {  
  12.             // reflect the message through the message map as OCM_NOTIFY  
  13.             NMHDR* pNMHDR = (NMHDR*)lParam;  
  14.             int nCode = pNMHDR->code;  
  15.             AFX_NOTIFY notify;  
  16.             notify.pResult = pResult;  
  17.             notify.pNMHDR = pNMHDR;  
  18.             return CWnd::OnCmdMsg(0, MAKELONG(nCode, WM_REFLECT_BASE+WM_NOTIFY), ¬ify, NULL);  
  19.         }  
  20.         ......  
  21. }  
    很顯然,調用了virtual CWnd::OnCmdMsg函數來處理,實際上是virtual CCmdTarget::OnCmdMsg函數,CWnd繼承自CCmdTarget。

注意:以上return CWnd::OnCmdMsg(0, MAKELONG(nCode, WM_REFLECT_BASE+WM_NOTIFY), ¬ify, NULL)語句,在WM_NOTIFY的基礎上+WM_REFLECT_BASE,因為消息流程走到這步,是在子控件窗口的消息映射表中查找反射消息處理函數。
    注意區分WM_NOTIFY消息與WM_NOTIFY反射消息,WM_NOTIFY反射消息即消息WM_REFLECT_BASE+WM_NOTIFY,父窗口收到WM_NOTIFY消息而扔給子窗口處理時,為了區分,子窗口處理的消息被譯成WM_REFLECT_BASE+WM_NOTIFY消息,否則豈不和子窗口本身的WM_NOTIFY消息混淆了。

[cpp]  view plain  copy
 
  1. BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode, void* pExtra,  
  2.     AFX_CMDHANDLERINFO* pHandlerInfo)  
  3. {  
  4.     //從消息映射中查找對應的處理函數  
  5.     for (pMessageMap = GetMessageMap(); pMessageMap->pfnGetBaseMap != NULL;  
  6.       pMessageMap = (*pMessageMap->pfnGetBaseMap)())  
  7.     {  
  8.         lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, nMsg, nCode, nID);  
  9.         if (lpEntry != NULL)  
  10.         {  
  11.             // 找到對應的消息處理函數  
  12.             return _AfxDispatchCmdMsg(this, nID, nCode,  
  13.                 lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo);  
  14.         }  
  15.     }  
  16.     return FALSE;   // not handled  沒有對應的消息處理函數則返回FALSE  
  17. }  
    在子控件窗口類的消息映射表中沒有找到對應的WM_REFLECT_BASE+WM_WM_NOTIFY消息(即對應WM_NOTIFY的反射消息)處理函數返回FALSE,也即以上ReflectLastMsg(hWndCtrl, pResult)返回FALSE,這樣父窗口就會處理。
    否則,在_AfxDispatchCmdMsg函數中會調用對應的反射消息處理函數處理,ReflectLastMsg(hWndCtrl, pResult)返回TRUE,這樣父窗口就不會處理了。

http://blog.csdn.net/hisinwang/article/details/8045382


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM