091009(星期五)熟悉Dlg消息处理函数的调用流程

熟悉Dlg消息处理函数的调用流程,基于Frame8进行模拟。

 

断点下的调用栈:

CDlgSmbList::OnButtonSearch() line 117

_AfxDispatchCmdMsg(CCmdTarget * 0x0013fd50 {CDlgSmbList hWnd=0x00010c4a}, unsigned int 1028, int 0, void (void)* 0x004012b2 CDlgSmbList::OnButtonSearch(void), void * 0x00000000, unsigned int 12, AFX_CMDHANDLERINFO * 0x00000000) line 88

 

CCmdTarget::OnCmdMsg(unsigned int 1028, int 0, void * 0x00000000, AFX_CMDHANDLERINFO * 0x00000000) line 302 + 39 bytes

CDialog::OnCmdMsg(unsigned int 1028, int 0, void * 0x00000000, AFX_CMDHANDLERINFO * 0x00000000) line 97 + 24 bytes

CWnd::OnCommand(unsigned int 1028, long 68708) line 2099

CWnd::OnWndMsg(unsigned int 273, unsigned int 1028, long 68708, long * 0x0013f0e4) line 1608 + 28 bytes

CWnd::WindowProc(unsigned int 273, unsigned int 1028, long 68708) line 1596 + 30 bytes

AfxCallWndProc(CWnd * 0x0013fd50 {CDlgSmbList hWnd=0x00010c4a}, HWND__ * 0x00010c4a, unsigned int 273, unsigned int 1028, long 68708) line 215 + 26 bytes

AfxWndProc(HWND__ * 0x00010c4a, unsigned int 273, unsigned int 1028, long 68708) line 379

 

顺藤摸瓜看代码:

1,接收到消息,回调函数AfxWndProc被调用

LRESULT CALLBACK

AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)

{

       // special message which identifies the window as using AfxWndProc

       if (nMsg == WM_QUERYAFXWNDPROC)

              return 1;

 

       // all other messages route through message map

       CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);

       ASSERT(pWnd != NULL);

       ASSERT(pWnd->m_hWnd == hWnd);

       if (pWnd == NULL || pWnd->m_hWnd != hWnd)

              return ::DefWindowProc(hWnd, nMsg, wParam, lParam);

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

}

 

2,调用AfxCallWndProc,再delegate to object's WindowProc

LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg,

         WPARAM wParam = 0, LPARAM lParam = 0)

{

         _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();

         MSG oldState = pThreadState->m_lastSentMsg;   // save for nesting

         pThreadState->m_lastSentMsg.hwnd = hWnd;

         pThreadState->m_lastSentMsg.message = nMsg;

         pThreadState->m_lastSentMsg.wParam = wParam;

         pThreadState->m_lastSentMsg.lParam = lParam;

 

         // Catch exceptions thrown outside the scope of a callback

         // in debug builds and warn the user.

         LRESULT lResult;

         TRY

         {

                   // special case for WM_INITDIALOG

                   CRect rectOld;

                   DWORD dwStyle = 0;

                   if (nMsg == WM_INITDIALOG)

                            _AfxPreInitDialog(pWnd, &rectOld, &dwStyle);

 

                   // delegate to object's WindowProc

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

 

                   // more special case for WM_INITDIALOG

                   if (nMsg == WM_INITDIALOG)

                            _AfxPostInitDialog(pWnd, rectOld, dwStyle);

         }

         CATCH_ALL(e)

         {

                   CWinThread* pWinThread = AfxGetThread();

                   if ( pWinThread != NULL )

                   {

                            lResult = pWinThread->ProcessWndProcException(e, &pThreadState->m_lastSentMsg);

                            TRACE1("Warning: Uncaught exception in WindowProc (returning %ld)./n",

                                     lResult);

                   }

                   else

                   {

                            TRACE0("Warning: Uncaught exception in WindowProc./n");

                            lResult = 0;

                   }

                   DELETE_EXCEPTION(e);

         }

         END_CATCH_ALL

 

         pThreadState->m_lastSentMsg = oldState;

         return lResult;

}

 

3pWnd->WindowProc(nMsg, wParam, lParam)这里的pWnd是指向CDlgSmbList

CDlgSmbList没有重写WindowProc,其父类class CDlgSmbList : public CDialog也没有重写,继续看父类的父类Cwnd

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

{

       // OnWndMsg does most of the work, except for DefWindowProc call

       LRESULT lResult = 0;

       if (!OnWndMsg(message, wParam, lParam, &lResult))

              lResult = DefWindowProc(message, wParam, lParam);

       return lResult;

}

实际上是调用CDlgSmbList::OnWndMsgItem4进行跟踪。

 

4CDlgSmbList::OnWndMsg,进入WM_COMMAND分支,再调用CDlgSmbList:: OnCommand

CDlgSmbList没有重写OnWndMsg,其父类class CDlgSmbList : public CDialog也没有重写,继续看父类的父类Cwnd

BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)

{

       LRESULT lResult = 0;

       // special case for commands

       if (message == WM_COMMAND)

       {

              if (OnCommand(wParam, lParam))

              {

                     lResult = 1;

                     goto LReturnTrue;

              }

              return FALSE;

       }

       // special case for notifies

       if (message == WM_NOTIFY)

       {

              NMHDR* pNMHDR = (NMHDR*)lParam;

              if (pNMHDR->hwndFrom != NULL && OnNotify(wParam, lParam, &lResult))

                     goto LReturnTrue;

              return FALSE;

       }

       // special case for activation

       if (message == WM_ACTIVATE)

              _AfxHandleActivate(this, wParam, CWnd::FromHandle((HWND)lParam));

 

       // special case for set cursor HTERROR

       if (message == WM_SETCURSOR &&

              _AfxHandleSetCursor(this, (short)LOWORD(lParam), HIWORD(lParam)))

       {

              lResult = 1;

              goto LReturnTrue;

       }

……

}

 

5CDlgSmbList:: OnCommand中继续调用CDlgSmbList:: OnCmdMsg

CDlgSmbList没有重写OnCommand,其父类class CDlgSmbList : public CDialog也没有重写,继续看父类的父类Cwnd

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

       // return TRUE if command invocation was attempted

{

       UINT nID = LOWORD(wParam);

       HWND hWndCtrl = (HWND)lParam;

       int nCode = HIWORD(wParam);

 

       // default routing for command messages (through closure table)

 

       if (hWndCtrl == NULL)

       {

              // zero IDs for normal commands are not allowed

              if (nID == 0)

                     return FALSE;

 

              // make sure command has not become disabled before routing

              CTestCmdUI state;

              state.m_nID = nID;

              OnCmdMsg(nID, CN_UPDATE_COMMAND_UI, &state, NULL);

              if (!state.m_bEnabled)

              {

                     TRACE1("Warning: not executing disabled command %d/n", nID);

                     return TRUE;

              }

 

              // menu or accelerator

              nCode = CN_COMMAND;

       }

       else

       {

              // control notification

              ASSERT(nID == 0 || ::IsWindow(hWndCtrl));

 

              if (_afxThreadState->m_hLockoutNotifyWindow == m_hWnd)

                     return TRUE;        // locked out - ignore control notification

 

              // reflect notification to child window control

              if (ReflectLastMsg(hWndCtrl))

                     return TRUE;    // eaten by child

 

              // zero IDs for normal commands are not allowed

              if (nID == 0)

                     return FALSE;

       }

 

       return OnCmdMsg(nID, nCode, NULL, NULL);

}

 

6CDlgSmbList:: OnCmdMsg中显式调用CWnd::OnCmdMsg

CDlgSmbList没有重写OnCommand,其父类class CDlgSmbList : public CDialog进行了重写:

BOOL CDialog::OnCmdMsg(UINT nID, int nCode, void* pExtra,

       AFX_CMDHANDLERINFO* pHandlerInfo)

{

// 显式调用CWnd::OnCmdMsg

       if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))

              return TRUE;

……

}

 

7CWnd::OnCmdMsg进行遍历分发

OnCmdMsg没有重写OnCmdMsg,其父类CCmdTarget进行了重写:

BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode, void* pExtra,

       AFX_CMDHANDLERINFO* pHandlerInfo)

{

#ifndef _AFX_NO_OCC_SUPPORT

       // OLE control events are a special case

       if (nCode == CN_EVENT)

       {

              ASSERT(afxOccManager != NULL);

              return afxOccManager->OnEvent(this, nID, (AFX_EVENT*)pExtra, pHandlerInfo);

       }

#endif // !_AFX_NO_OCC_SUPPORT

 

       // determine the message number and code (packed into nCode)

       const AFX_MSGMAP* pMessageMap;

       const AFX_MSGMAP_ENTRY* lpEntry;

       UINT nMsg = 0;

 

#ifndef _AFX_NO_DOCOBJECT_SUPPORT

       if (nCode == CN_OLECOMMAND)

       {

              BOOL bResult = FALSE;

 

              const AFX_OLECMDMAP* pOleCommandMap;

              const AFX_OLECMDMAP_ENTRY* pEntry;

 

              COleCmdUI* pUI = (COleCmdUI*) pExtra;

              const GUID* pguidCmdGroup = pUI->m_pguidCmdGroup;

 

#ifdef _AFXDLL

              for (pOleCommandMap = GetCommandMap(); pOleCommandMap != NULL && !bResult;

                     pOleCommandMap = pOleCommandMap->pfnGetBaseMap())

#else

              for (pOleCommandMap = GetCommandMap(); pOleCommandMap != NULL && !bResult;

                     pOleCommandMap = pOleCommandMap->pBaseMap)

#endif

              {

                     for (pEntry = pOleCommandMap->lpEntries;

                            pEntry->cmdID != 0 && pEntry->nID != 0 && !bResult;

                            pEntry++)

                     {

                            if (nID == pEntry->cmdID &&

                                   IsEqualNULLGuid(pguidCmdGroup, pEntry->pguid))

                            {

                                   pUI->m_nID = pEntry->nID;

                                   bResult = TRUE;

                            }

                     }

              }

 

              return bResult;

       }

#endif

 

       if (nCode != CN_UPDATE_COMMAND_UI)

       {

              nMsg = HIWORD(nCode);

              nCode = LOWORD(nCode);

       }

 

       // for backward compatibility HIWORD(nCode)==0 is WM_COMMAND

       if (nMsg == 0)

              nMsg = WM_COMMAND;

 

       // look through message map to see if it applies to us

#ifdef _AFXDLL

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

         pMessageMap = (*pMessageMap->pfnGetBaseMap)())

#else

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

         pMessageMap = pMessageMap->pBaseMap)

#endif

       {

              // Note: catches BEGIN_MESSAGE_MAP(CMyClass, CMyClass)!

              lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, nMsg, nCode, nID);

              if (lpEntry != NULL)

              {

                     // found it

                     return _AfxDispatchCmdMsg(this, nID, nCode,

                            lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo);

              }

       }

       return FALSE;   // not handled

}

 

8_AfxDispatchCmdMsg全局函数,调用到具体的处理函数

AFX_STATIC BOOL AFXAPI _AfxDispatchCmdMsg(CCmdTarget* pTarget, UINT nID, int nCode,

       AFX_PMSG pfn, void* pExtra, UINT nSig, AFX_CMDHANDLERINFO* pHandlerInfo)

              // return TRUE to stop routing

{

       ASSERT_VALID(pTarget);

       UNUSED(nCode);   // unused in release builds

 

       union MessageMapFunctions mmf;

       mmf.pfn = pfn;

       BOOL bResult = TRUE; // default is ok

 

       if (pHandlerInfo != NULL)

       {

              // just fill in the information, don't do it

              pHandlerInfo->pTarget = pTarget;

              pHandlerInfo->pmf = mmf.pfn;

              return TRUE;

       }

 

       switch (nSig)

       {

       case AfxSig_vv:

              // normal command or control notification

              ASSERT(CN_COMMAND == 0);        // CN_COMMAND same as BN_CLICKED

              ASSERT(pExtra == NULL);

              (pTarget->*mmf.pfn_COMMAND)();

              break;

 

       case AfxSig_bv:

              // normal command or control notification

              ASSERT(CN_COMMAND == 0);        // CN_COMMAND same as BN_CLICKED

              ASSERT(pExtra == NULL);

              bResult = (pTarget->*mmf.pfn_bCOMMAND)();

              break;

……

 

       default:    // illegal

              ASSERT(FALSE);

              return 0;

       }

       return bResult;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值