zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    EasyPlayer-Android播放器是如何实现播放器退到后台后,再回到前台时,播放画面的无缝衔接?
    EasyPlayer网页全终端播放器之Android版的分屏策略及如何设置2分屏
    海康大华安防网络摄像头Onvif、RTSP网络无插件直播流媒体服务解决方案EasyNVR表单重复提交的优化方案
    Onvif/RTSP海康大华网络安防摄像机网页无插件直播方案EasyNVR中直播页面和视频列表页面的区别介绍
    Onvif/RTSP海康大华网络安防摄像机网页无插件直播方案EasyNVR如何使用Excel将通道配置简单化?
    集RTMP, HLS, FLV, WebSocket 于一身的网页直播/点播播放器EasyPlayer.js引用videojs无法自动播放问题解决
    Onvif/RTSP海康大华网络安防摄像机网页无插件直播方案EasyNVR登陆用户名密码失效问题解决方案
    RTSP转RTSP、RTMP、HLS、FLV安防摄像头网页无插件直播流媒体服务器EasyNVR在IE浏览器下的 pointer-events- none前端兼容性调试
    Onvif/RTSP网络安防摄像机网页无插件直播方案EasyNVR接口调用返回出现“Unauthorized”解决方案
    安防监控流媒体服务器对接宇视摄像机配置OCX插件安装时出现Failed to register ocx, error code 14001错误问题分析
  • 原文地址:https://www.cnblogs.com/findumars/p/8306951.html
Copyright © 2011-2022 走看看