您的位置:首页 > 其它

OnCmdMsg标准处理流程

2011-01-15 19:07 357 查看
MFC很古老的东西了,以前没怎么用过它,翻出来看了看,总结学习,不知有无错误,请各位指出。

默认情况下,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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: