最近在看深入浅出MFC,获益匪浅,不过这里有个疑问:在命令消息的传递中,书中说(P430)窗口得到这个消息,首先给View,View检查自己的Message Map,如果没有这个消息对应的处理函数,则转递给Document,同样,Document检查自己的Message Map,没有的话再转递,以此类推。可是反观代码:BOOL CView::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
// first pump through pane
if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE; // then pump through document
if (m_pDocument != NULL)
{
// special state for saving view before routing to document
CPushRoutingView push(this);
return m_pDocument->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
} return FALSE;
}在CView::OnCmdMsg 中,View没有检查自己的Message Map的操作呀,而是直接转递给了CWnd::OnCmdMsg。对于CDocument::OnCmdMsg也有同样的问题。而且似乎无论通过那条传递路径,最终都是由CCmdTarget::OnCmdMsg进行最后的处理,中间所经过的所有类中,都没有检查自己的Message Map。不知是怎么回事,望各位不吝赐教。

解决方案 »

  1.   

    在CWnd::OnCmdMsg中会检查。因为Message Map其实是一个虚函数,在CWnd::OnCmdMsg中会调用这个虚函数,也就是调用到了继承子类的Message Map函数。if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
    return TRUE;
    就是说OnCmdMsg处理了,就返回TRUE了。
    如果没处理就继续:
    m_pDocument->OnCmdMsg
      

  2.   

    又想了想,好像明白些了。BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode, void* pExtra,
    AFX_CMDHANDLERINFO* pHandlerInfo)
    {
        ....// look through message map to see if it applies to usfor (pMessageMap = GetMessageMap(); pMessageMap != NULL;
      pMessageMap = (*pMessageMap->pfnGetBaseMap)())
         {
    lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, nMsg, nCode, nID);
    {if (lpEntry != NULL)
    return _AfxDispatchCmdMsg(this, nID, nCode,
    lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo);
    }
         }
    return FALSE;   // not handled
    }GetMessageMap()是一个虚函数,this指针指向CView中的OnCmdMsg(),上面的for循环实现了从类CView到类CCmdTarget的消息映射的遍历。就是说,命令消息传递中,中间所经过的所有类中,其实都在检查自己的Message Map。是不是这样?
      

  3.   

    这样说的话,CCmdTarget的Message Map有可能会被检查(搜索)多次吧,因为每一条路径的最终指向都是CCmdTarget。PS:上面的for循环写错了,应该是:
    for (pMessageMap = GetMessageMap(); pMessageMap != NULL;
      pMessageMap = pMessageMap->pBaseMap)
      

  4.   

    to:visualwindMessage Map其实是一个虚函数——能展开讲一下吗?谢谢~~
      

  5.   

    Message Map就是GetMessageMap这个虚函数,其实也就是BEGIN_MESSAGE_MAP END_MESSAGE_MAP这堆宏定义的。你直接转到宏定义出看看就清楚了,只不过用了几个宏来声明GetMessageMap这个函数。
    CCmdTarget的Message Map有不会被检查多次,每次检查的只是当前实例对象的Message Map,因为每次检查的是虚函数,多态性决定了函数只会跳到当前实例对象的函数处。
      

  6.   

    Message Map就是GetMessageMap这个虚函数,其实也就是BEGIN_MESSAGE_MAP END_MESSAGE_MAP这堆宏定义的。你直接转到宏定义出看看就清楚了,只不过用了几个宏来声明GetMessageMap这个函数。
    CCmdTarget的Message Map有不会被检查多次,每次检查的只是当前实例对象的Message Map,因为每次检查的是虚函数,多态性决定了函数只会跳到当前实例对象的函数处。
      

  7.   

    getmessagemap 不同类取到得map都是和自己类相关的
      

  8.   


    to:visualwind“CCmdTarget的Message Map有不会被检查多次,每次检查的只是当前实例对象的Message Map,因为每次检查的是虚函数,多态性决定了函数只会跳到当前实例对象的函数处。”----------------------------------------------------------------------我是说“有可能”会被检查多次,就是说最坏的情况下。那个for循环不就决定了,在最坏情况下,只有在回溯到CCmdTarget,检查完CCmdTarget的Message Map后,仍没有找到消息对应的处理函数,就会被赋值为NULL,然后循环终止吗?还是没有这个可能?BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode, void* pExtra,
    AFX_CMDHANDLERINFO* pHandlerInfo)
    {
      ....// look through message map to see if it applies to usfor (pMessageMap = GetMessageMap(); pMessageMap != NULL;
    pMessageMap = pMessageMap->pBaseMap)
        {
    lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, nMsg, nCode, nID);
            {  if (lpEntry != NULL)
               return _AfxDispatchCmdMsg(this, nID, nCode,
               lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo);
            }
        }
    return FALSE; // not handled
    }
      

  9.   

    to:zzw820626这一点已经清楚了。谢谢~~
      

  10.   

    LZ没有看深入浅出的第三章 MFC六大关键技术之仿真么,看看。讲的很好。
      

  11.   


    LZ这里没明白这个for循环里面在干什么。
    虽然调用的是CCmdTarget::OnCmdMsg,但是你的窗口对象是继承于CCmdTarget的,for (pMessageMap = GetMessageMap()的时候这个GetMessageMap是你的继承类的GetMessageMap,而不是CCmdTarget的GetMessageMap。那么代码:
    for (pMessageMap = GetMessageMap(); pMessageMap != NULL;
    pMessageMap = pMessageMap->pBaseMap)
      {
    lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, nMsg, nCode, nID);
      { if (lpEntry != NULL)
      return _AfxDispatchCmdMsg(this, nID, nCode,
      lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo);
      }
      }for (pMessageMap = GetMessageMap(); pMessageMap != NULL;
    pMessageMap = pMessageMap->pBaseMap)
    是在遍历消息这个继承类的消息响应map,这里遍历的是继承类的map对象,也就是BEGIN_MESSAGE_MAP那堆宏。lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, nMsg, nCode, nID);
    这里查找消息nMsg对应的响应函数,赋值给pMessageMap->lpEntries
    然后return _AfxDispatchCmdMsg就是执行消息响应函数。如果循环没有找到对应的消息响应函数的话,就继续m_pDocument->OnCmdMsg,在Document里面找,如果还没找到的话再进一步回溯。
    其实应该不会去查CCmdTarget的Message Map,因为这个没有意义。
      

  12.   

    to:visualwind是在遍历消息这个继承类的消息响应map,这里遍历的是继承类的map对象,也就是BEGIN_MESSAGE_MAP那堆宏。---------------------------------------------------------------for (pMessageMap = GetMessageMap(); pMessageMap != NULL;
    pMessageMap = pMessageMap->pBaseMap)上面的for循环中,pMessageMap = pMessageMap->pBaseMap不就是使pMessageMap指向其父类的消息映射表吗?这样下一次循环中,lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, nMsg, nCode, nID);不就是在其父类的消息映射表中查找吗?以此类推,只有在CCmdTarget类中,pBaseMap才指向NULL,就是说,遍历CCmdTarget的消息映射表后,循环结束啊~~PS:我是新手,所以有好多问题可能很浅显,见笑~~
      

  13.   


    LZ参考一下文章:
    http://tech.ddvip.com/2006-04/11444435404354.html
    讲得很清楚
      

  14.   

    to:visualwind我看了一下,还是饿米能解释我的疑问,其实,关键是在这里:for (pMessageMap = GetMessageMap(); pMessageMap != NULL;
    pMessageMap = pMessageMap->pBaseMap)这个for循环有可能进行下一次循环,那么在下次循环前,执行语句pMessageMap = pMessageMap->pBaseMap,再查看pMessageMap 是否 == NULL,进而决定是否进行下一次循环。关键问题是:执行语句pMessageMap = pMessageMap->pBaseMap后,pMessageMap指向哪里?
    我分析着觉得是指向它父类的Message Map 结构,进而调用AfxFindMessageEntry(pMessageMap->lpEntries, nMsg,nCode, nID); 查找他父类的MessageEntry[](由lpEntries所指)中有无对应的消息处理函数。