OnCmdMsg标准处理流程
2011-01-15 19:07
357 查看
MFC很古老的东西了,以前没怎么用过它,翻出来看了看,总结学习,不知有无错误,请各位指出。
默认情况下,OnCmdMsg是类CCmdTarget的虚函数,用来查找和分派消息,其具体处理流程如下:
以标准MFC SDI应用程序test为例:在启动时,执行特定初始化:
ProcessShellCommand(cmdInfo);中对Shell Command 命令FileNew进行了分派处理:
默认情况下,OnCmdMsg是类CCmdTarget的虚函数,用来查找和分派消息,其具体处理流程如下:
以标准MFC SDI应用程序test为例:在启动时,执行特定初始化:
ProcessShellCommand(cmdInfo);中对Shell Command 命令FileNew进行了分派处理:
//Shell command FILENEW process //使用CCmdTraget的OnCmdMsg()执行该命令。此处由于派生类没有覆盖该虚函数。 BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { (1) //AfxMsg_.h中定义了几个nCode //#define CN_COMMAND 0 // void () //#define CN_UPDATE_COMMAND_UI ((UINT)(-1)) // void (CCmdUI*) //#define CN_EVENT ((UINT)(-2)) // OLE event //#define CN_OLECOMMAND ((UINT)(-3)) // OLE document command //#define CN_OLE_UNREGISTER ((UINT)(-4)) // OLE unregister //首先对OLE事件特殊处理,此处没有,跳过 if (nCode == CN_EVENT) { ASSERT(afxOccManager != NULL); return afxOccManager->OnEvent(this, nID, (AFX_EVENT*)pExtra, pHandlerInfo); } // determine the message number and code (packed into nCode) /* AfxWin.h中定义 struct AFX_MSGMAP { #ifdef _AFXDLL const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)(); #else const AFX_MSGMAP* pBaseMap; #endif const AFX_MSGMAP_ENTRY* lpEntries; };*/ const AFX_MSGMAP* pMessageMap; //定义了一个指向消息映射的指针 /* AfxWin.h struct AFX_MSGMAP_ENTRY { UINT nMessage; // windows message UINT nCode; // control code or WM_NOTIFY code UINT nID; // control ID (or 0 for windows messages) UINT nLastID; // used for entries specifying a range of control id's UINT nSig; // signature type (action) or pointer to message # AFX_PMSG pfn; // routine to call (or special value) }; */ const AFX_MSGMAP_ENTRY* lpEntry; //定义一个指向消息映射条目的指针 UINT nMsg = 0; //nMsg //此处跳过对Ole Command的处理; // //判断是否是UPDATE UI 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; //nMsg Now is 273 //查找消息映射,看看有没有对该命令的处理例程 // look through message map to see if it applies to us //循环调用GetMessageMap()查找App对象中以及基类中是否存在对该命令的处理程序(handler) //因为此时this指针指向的是CTestApp,所以此处的第一个GetMessageMap(),获取到的是对CTestApp对象的MessageMap成员变量的指针 #ifdef _AFXDLL //使用MFC动态库 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)! #ifdef _AFXDLL ASSERT(pMessageMap != (*pMessageMap->pfnGetBaseMap)()); //检查是否有把宏定义错的情况。派生类=基类 #else ASSERT(pMessageMap != pMessageMap->pBaseMap); #endif lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, nMsg, nCode, nID); (2)//调用函数AfxFindMessageEntry查找匹配命令的处理函数 if (lpEntry != NULL) //在该类的_messageEntries[]数组找到了handler //找到就退出函数,具体分析,见下文(2) { // found it #ifdef _DEBUG if (afxTraceFlags & traceCmdRouting) //如果定义了调试标志,调试时,会在调试窗口输出命令和通知跟踪消息 { if (nCode == CN_COMMAND) { TRACE2("SENDING command id 0x%04X to %hs target./n", nID, GetRuntimeClass()->m_lpszClassName); } else if (nCode > CN_COMMAND) { if (afxTraceFlags & traceWinMsg) { TRACE3("SENDING control notification %d from control id 0x%04X to %hs window./n", nCode, nID, GetRuntimeClass()->m_lpszClassName); } } } #endif //_DEBUG //返回_AfxDispatchCmdMsg,返回结果 return _AfxDispatchCmdMsg(this, nID, nCode, (3) //以上面找到的消息映射条目调用_AfxDispatchCmdMsg函数分派 lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo); //具体分析见下文(3) } } return FALSE; // not handled } (1) (2)//查找消息映射条目的函数 //AfxFindMessageEntry(pMessageMap->lpEntries, nMsg, nCode, nID); ///////////////////////////////////////////////////////////////////////////// // Routines for fast search of message maps const AFX_MSGMAP_ENTRY* AFXAPI AfxFindMessageEntry(const AFX_MSGMAP_ENTRY* lpEntry, UINT nMsg, UINT nCode, UINT nID) { #if defined(_M_IX86) && !defined(_AFX_PORTABLE) //没指定可移植标志&X86 // 32-bit Intel 386/486 version. //针对32bit x86架构做了优化,使用部分汇编代码提高查找效率 ASSERT(offsetof(AFX_MSGMAP_ENTRY, nMessage) == 0); //检查变量长度及偏移 ASSERT(offsetof(AFX_MSGMAP_ENTRY, nCode) == 4); ASSERT(offsetof(AFX_MSGMAP_ENTRY, nID) == 8); ASSERT(offsetof(AFX_MSGMAP_ENTRY, nLastID) == 12); ASSERT(offsetof(AFX_MSGMAP_ENTRY, nSig) == 16); _asm { MOV EBX,lpEntry MOV EAX,nMsg MOV EDX,nCode MOV ECX,nID __loop: CMP DWORD PTR [EBX+16],0 ; nSig (0 => end) //找到消息映射数组末尾 JZ __failed //跳转到失败处理 CMP EAX,DWORD PTR [EBX] ; nMessage JE __found_message //找到匹配的消息,跳转到nCode的匹配 __next: ADD EBX,SIZE AFX_MSGMAP_ENTRY JMP short __loop __found_message: CMP EDX,DWORD PTR [EBX+4] ; nCode JNE __next //nCode不匹配,查找下一条 // message and code good so far // check the ID //nCode也匹配 CMP ECX,DWORD PTR [EBX+8] ; nID //验证nID是否在条目中ID范围内(nID-nLastID之间) JB __next //比nID小,查找下一条 CMP ECX,DWORD PTR [EBX+12] ; nLastID JA __next //比nID大,查找下一条 // found a match //nID也匹配 MOV lpEntry,EBX ; return EBX JMP short __end //找到了 __failed: XOR EAX,EAX ; return NULL MOV lpEntry,EAX __end: } return lpEntry; //返回该消息映射条目的指针 #else // _AFX_PORTABLE // C version of search routine //可移植版本,目的在于移植到非X86架构 while (lpEntry->nSig != AfxSig_end) //查找方法同上述一致 { if (lpEntry->nMessage == nMsg && lpEntry->nCode == nCode && nID >= lpEntry->nID && nID <= lpEntry->nLastID) { return lpEntry; } lpEntry++; } return NULL; // not found //找不到只能返回NULL #endif // _AFX_PORTABLE } (3) //以上面找到的消息映射条目调用_AfxDispatchCmdMsg函数分派 //_AfxDispatchCmdMsg(this, nID, nCode,lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo) ///////////////////////////////////////////////////////////////////////////// // CCmdTarget windows message dispatching //原型: 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 //定义了联合结构 mmf,其具体结构见下文:(2)//MessageMapFunctions联合结构 union MessageMapFunctions mmf; mmf.pfn = pfn; //将消息条目指针赋给pfn; BOOL bResult = TRUE; // default is ok if (pHandlerInfo != NULL) //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)(); //调用mmf相应原型函数,无返回值,直接返回bResault; break; //此处即调用了消息条目中的指定函数。CWinApp::OnFileNew() //见下文(3):分析。 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; case AfxSig_vw: // normal command or control notification in a range ASSERT(CN_COMMAND == 0); // CN_COMMAND same as BN_CLICKED ASSERT(pExtra == NULL); (pTarget->*mmf.pfn_COMMAND_RANGE)(nID); break; case AfxSig_bw: // extended command (passed ID, returns bContinue) ASSERT(pExtra == NULL); bResult = (pTarget->*mmf.pfn_COMMAND_EX)(nID); break; case AfxSig_vNMHDRpl: { AFX_NOTIFY* pNotify = (AFX_NOTIFY*)pExtra; ASSERT(pNotify != NULL); ASSERT(pNotify->pResult != NULL); ASSERT(pNotify->pNMHDR != NULL); (pTarget->*mmf.pfn_NOTIFY)(pNotify->pNMHDR, pNotify->pResult); } break; case AfxSig_bNMHDRpl: { AFX_NOTIFY* pNotify = (AFX_NOTIFY*)pExtra; ASSERT(pNotify != NULL); ASSERT(pNotify->pResult != NULL); ASSERT(pNotify->pNMHDR != NULL); bResult = (pTarget->*mmf.pfn_bNOTIFY)(pNotify->pNMHDR, pNotify->pResult); } break; case AfxSig_vwNMHDRpl: { AFX_NOTIFY* pNotify = (AFX_NOTIFY*)pExtra; ASSERT(pNotify != NULL); ASSERT(pNotify->pResult != NULL); ASSERT(pNotify->pNMHDR != NULL); (pTarget->*mmf.pfn_NOTIFY_RANGE)(nID, pNotify->pNMHDR, pNotify->pResult); } break; case AfxSig_bwNMHDRpl: { AFX_NOTIFY* pNotify = (AFX_NOTIFY*)pExtra; ASSERT(pNotify != NULL); ASSERT(pNotify->pResult != NULL); ASSERT(pNotify->pNMHDR != NULL); bResult = (pTarget->*mmf.pfn_NOTIFY_EX)(nID, pNotify->pNMHDR, pNotify->pResult); } break; case AfxSig_cmdui: { // ON_UPDATE_COMMAND_UI or ON_UPDATE_COMMAND_UI_REFLECT case ASSERT(CN_UPDATE_COMMAND_UI == (UINT)-1); ASSERT(nCode == CN_UPDATE_COMMAND_UI || nCode == 0xFFFF); ASSERT(pExtra != NULL); CCmdUI* pCmdUI = (CCmdUI*)pExtra; ASSERT(!pCmdUI->m_bContinueRouting); // idle - not set (pTarget->*mmf.pfn_UPDATE_COMMAND_UI)(pCmdUI); bResult = !pCmdUI->m_bContinueRouting; pCmdUI->m_bContinueRouting = FALSE; // go back to idle } break; case AfxSig_cmduiw: { // ON_UPDATE_COMMAND_UI case ASSERT(nCode == CN_UPDATE_COMMAND_UI); ASSERT(pExtra != NULL); CCmdUI* pCmdUI = (CCmdUI*)pExtra; ASSERT(pCmdUI->m_nID == nID); // sanity assert ASSERT(!pCmdUI->m_bContinueRouting); // idle - not set (pTarget->*mmf.pfn_UPDATE_COMMAND_UI_RANGE)(pCmdUI, nID); bResult = !pCmdUI->m_bContinueRouting; pCmdUI->m_bContinueRouting = FALSE; // go back to idle } break; // general extensibility hooks case AfxSig_vpv: (pTarget->*mmf.pfn_OTHER)(pExtra); break; case AfxSig_bpv: bResult = (pTarget->*mmf.pfn_OTHER_EX)(pExtra); break; default: // illegal ASSERT(FALSE); return 0; } return bResult; } (2)//MessageMapFunctions联合结构 //AfxIMpl.h union MessageMapFunctions { AFX_PMSG pfn; // generic member function pointer // specific type safe variants for WM_COMMAND and WM_NOTIFY messages void (AFX_MSG_CALL CCmdTarget::*pfn_COMMAND)(); BOOL (AFX_MSG_CALL CCmdTarget::*pfn_bCOMMAND)(); void (AFX_MSG_CALL CCmdTarget::*pfn_COMMAND_RANGE)(UINT); BOOL (AFX_MSG_CALL CCmdTarget::*pfn_COMMAND_EX)(UINT); void (AFX_MSG_CALL CCmdTarget::*pfn_UPDATE_COMMAND_UI)(CCmdUI*); void (AFX_MSG_CALL CCmdTarget::*pfn_UPDATE_COMMAND_UI_RANGE)(CCmdUI*, UINT); void (AFX_MSG_CALL CCmdTarget::*pfn_OTHER)(void*); BOOL (AFX_MSG_CALL CCmdTarget::*pfn_OTHER_EX)(void*); void (AFX_MSG_CALL CCmdTarget::*pfn_NOTIFY)(NMHDR*, LRESULT*); BOOL (AFX_MSG_CALL CCmdTarget::*pfn_bNOTIFY)(NMHDR*, LRESULT*); void (AFX_MSG_CALL CCmdTarget::*pfn_NOTIFY_RANGE)(UINT, NMHDR*, LRESULT*); BOOL (AFX_MSG_CALL CCmdTarget::*pfn_NOTIFY_EX)(UINT, NMHDR*, LRESULT*); // type safe variant for thread messages void (AFX_MSG_CALL CWinThread::*pfn_THREAD)(WPARAM, LPARAM); // specific type safe variants for WM-style messages BOOL (AFX_MSG_CALL CWnd::*pfn_bD)(CDC*); BOOL (AFX_MSG_CALL CWnd::*pfn_bb)(BOOL); BOOL (AFX_MSG_CALL CWnd::*pfn_bWww)(CWnd*, UINT, UINT); BOOL (AFX_MSG_CALL CWnd::*pfn_bHELPINFO)(HELPINFO*); BOOL (AFX_MSG_CALL CWnd::*pfn_bWCDS)(CWnd*, COPYDATASTRUCT*); HBRUSH (AFX_MSG_CALL CWnd::*pfn_hDWw)(CDC*, CWnd*, UINT); HBRUSH (AFX_MSG_CALL CWnd::*pfn_hDw)(CDC*, UINT); int (AFX_MSG_CALL CWnd::*pfn_iwWw)(UINT, CWnd*, UINT); int (AFX_MSG_CALL CWnd::*pfn_iww)(UINT, UINT); int (AFX_MSG_CALL CWnd::*pfn_iWww)(CWnd*, UINT, UINT); int (AFX_MSG_CALL CWnd::*pfn_is)(LPTSTR); LRESULT (AFX_MSG_CALL CWnd::*pfn_lwl)(WPARAM, LPARAM); LRESULT (AFX_MSG_CALL CWnd::*pfn_lwwM)(UINT, UINT, CMenu*); void (AFX_MSG_CALL CWnd::*pfn_vv)(void); void (AFX_MSG_CALL CWnd::*pfn_vw)(UINT); void (AFX_MSG_CALL CWnd::*pfn_vww)(UINT, UINT); void (AFX_MSG_CALL CWnd::*pfn_vvii)(int, int); void (AFX_MSG_CALL CWnd::*pfn_vwww)(UINT, UINT, UINT); void (AFX_MSG_CALL CWnd::*pfn_vwii)(UINT, int, int); void (AFX_MSG_CALL CWnd::*pfn_vwl)(WPARAM, LPARAM); void (AFX_MSG_CALL CWnd::*pfn_vbWW)(BOOL, CWnd*, CWnd*); void (AFX_MSG_CALL CWnd::*pfn_vD)(CDC*); void (AFX_MSG_CALL CWnd::*pfn_vM)(CMenu*); void (AFX_MSG_CALL CWnd::*pfn_vMwb)(CMenu*, UINT, BOOL); void (AFX_MSG_CALL CWnd::*pfn_vW)(CWnd*); void (AFX_MSG_CALL CWnd::*pfn_vWww)(CWnd*, UINT, UINT); void (AFX_MSG_CALL CWnd::*pfn_vWp)(CWnd*, CPoint); void (AFX_MSG_CALL CWnd::*pfn_vWh)(CWnd*, HANDLE); void (AFX_MSG_CALL CWnd::*pfn_vwW)(UINT, CWnd*); void (AFX_MSG_CALL CWnd::*pfn_vwWb)(UINT, CWnd*, BOOL); void (AFX_MSG_CALL CWnd::*pfn_vwwW)(UINT, UINT, CWnd*); void (AFX_MSG_CALL CWnd::*pfn_vwwx)(UINT, UINT); void (AFX_MSG_CALL CWnd::*pfn_vs)(LPTSTR); void (AFX_MSG_CALL CWnd::*pfn_vOWNER)(int, LPTSTR); // force return TRUE int (AFX_MSG_CALL CWnd::*pfn_iis)(int, LPTSTR); UINT (AFX_MSG_CALL CWnd::*pfn_wp)(CPoint); UINT (AFX_MSG_CALL CWnd::*pfn_wv)(void); void (AFX_MSG_CALL CWnd::*pfn_vPOS)(WINDOWPOS*); void (AFX_MSG_CALL CWnd::*pfn_vCALC)(BOOL, NCCALCSIZE_PARAMS*); void (AFX_MSG_CALL CWnd::*pfn_vwp)(UINT, CPoint); void (AFX_MSG_CALL CWnd::*pfn_vwwh)(UINT, UINT, HANDLE); BOOL (AFX_MSG_CALL CWnd::*pfn_bwsp)(UINT, short, CPoint); void (AFX_MSG_CALL CWnd::*pfn_vws)(UINT, LPCTSTR); };(2)
相关文章推荐
- R12现金管理系统:银行对账单(Bank Statement)的标准处理流程
- R12 应付款模块(AP):预付款(prepayment)的标准处理流程(转)
- R12 应付款模块(AP):预付款(prepayment)的标准处理流程
- R12 应付款模块(AP):预付款(prepayment)的标准处理流程
- 【EMV L2】标准动态数据认证处理流程
- 标准的Windows蓝屏故障的分析、处理流程和VMware服务错误记录
- R12 应付款模块(AP):预付款(prepayment)的标准处理流程
- R12 AR的应收票据(Bill Receivable)的标准处理流程
- R12现金管理系统:银行对账单(Bank Statement)的标准处理流程
- R12 AR的应收票据(Bill Receivable)的标准处理流程
- chromium手势事件处理流程
- 高通msm8x60 boot(lk)的usb处理解析流程
- Android的frameworks层键盘事件处理流程分析
- asp.net页面处理流程 - 2 (Preload, Load, LoadComplete)
- tables->urls->views->forms处理工作流程-openstack E版
- ARM中断处理流程
- MTK 按键处理流程
- Asp.Net构架(Http请求处理流程) - Part.1
- Atheros AR9344中断处理流程
- 三读内核中断处理(3):中断处理流程