瑞星卡卡安全论坛技术交流区系统软件 MFC代码分析02:初探MFC程序消息处理机制

1   1  /  1  页   跳转

MFC代码分析02:初探MFC程序消息处理机制

MFC代码分析02:初探MFC程序消息处理机制

上一篇:MFC代码分析01:初探MFC程序初始化及运行


经典的Windows版Hello World,当消息产生,系统就会把消息放到应用程序消息队列中,应用程序通过GetMessage取出消息内容,并通过DispatchMessage把消息交换给操作系统。此时,窗口消息回调函数就会被激活,去处理这一消息。

然而,在MFC中,消息是不是按照这样的机制进行中转处理呢?答案是不是的。为什么呢?虽然多态的特性,允许子类去改写一函数,使得在实际使用中使用子类的函数而不是父类的函数。但这样的代价就是背负着一个虚函数表。MFC各类的关系是一个复杂的树状结构,我们知道,如果一旦通过子类重写父类消息响应函数取实现消息的中转,那么每一个MFC类都要背负一个沉重的虚函数表,这样来说,对资源是一种极大的浪费。
MFC消息处理采取消息映射的策略进行实现:在每一个能接收和处理消息的类中,定义一个消息和响应函数的映射表。当接收到消息时,程序从消息表中检索是否存在该消息及其绑定的响应函数,如果存在则将消息交由该响应函数处理。

我们用一个最简单的例子进行说明,我们以WM_CREATE消息为例进行说明。当我们用向导创建一个WM_CREATE的响应函数时,VC便会为你在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间创建一段代码:
BEGIN_MESSAGE_MAP()
...
ON_WM_CREATE()
...
END_MESSAGE_MAP()

我们看一看,这一个ON_WM_CREATE()是个什么东西。转到其定义,我们发现,其实它是一个宏,其位于afxmsg_.h中:


引用:

#define ON_WM_CREATE() \
{ WM_CREATE, 0, 0, 0, AfxSig_is, \
  (AFX_PMSG) (AFX_PMSGW) \
  (static_cast< int (AFX_MSG_CALL CWnd::*)(LPCREATESTRUCT) > (OnCreate)) },

我们发现,这些宏进行的就是一个静态绑定的过程。以下是其中另外一些宏的含义:


引用:

AfxSig_is:枚举值,表示一函数指针类型 int (LPTSTR),存储于Entries in a message map (a 'AFX_MSGMAP_ENTRY') table中
AFX_PMSG: typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);
AFX_PMSGW:typedef void (AFX_MSG_CALL CWnd::*AFX_PMSGW)(void);

我们在同一文件中也能发现一些最基本的系统消息的定义。


我们采用跟踪的方法,跟踪WM_CREATE消息,看看MFC的消息到底是怎么中转的。我们发现,其轨迹如下:
AfxWndProcBase --> AfxCallWndProc --> CWnd::WindowProc --> CWnd::OnWndMsg --> 消息处理函数


引用:

AfxWndProcBase,AfxCallWndProc(消息中转通道)
作用:将消息转至窗口消息回调函数

CWnd::WindowProc(主消息回调函数)
转交CWnd::OnWndMsg

CWnd::OnWndMsg
其中有个MessageMapFunctions结构,表示消息映射数据成员。进行消息的中转



用户系统信息:Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322)
最后编辑天下奇才 最后编辑于 2008-09-28 15:38:32

一点点的激情,一点点的执着,让我一步一步的走入了自己梦寐以求的行业。从一个学校里年少轻狂的孩子,成为了一名信息安全的研发工程师。从只知道写代码,真正开始慢慢的去思考、设计和实现一种技术、一种算法、一个模块、一个软件乃至一个系统。
人生本来就该不断的追求梦想,不断的跨过一个又一个不可能穿越的鸿沟。别人看来,我很疯狂,但我笑了,人生能有几回疯?真正疯狂的人是不计后果的向前冲的,至少我还不是。我所想的,只是别人不敢想的。我所做的,只是别人不敢做的。一个一个虚无缥缈的事物,都必须是有一个一个疯狂的人逐渐的具体和完善。但愿我是这样的人,我只愿做这样的人。
分享到:
gototop
 

回复:MFC代码分析02:初探MFC程序消息处理机制(编辑中)

相关代码


CWnd::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;
#ifdef _DEBUG
_AfxTraceMsg(_T("WndProc"), &pThreadState->m_lastSentMsg);
#endif
// Catch exceptions thrown outside the scope of a callback
// in debug builds and warn the user.
LRESULT lResult;
TRY
{
#ifndef _AFX_NO_OCC_SUPPORT
  // special case for WM_DESTROY
  if ((nMsg == WM_DESTROY) && (pWnd->m_pCtrlCont != NULL))
  pWnd->m_pCtrlCont->OnUIActivate(NULL);   
#endif
  // 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)
{
  lResult = AfxProcessWndProcException(e, &pThreadState->m_lastSentMsg);
  TRACE(traceAppMsg, 0, "Warning: Uncaught exception in WindowProc (returning %ld).\n",
  lResult);
  DELETE_EXCEPTION(e);
}
END_CATCH_ALL
pThreadState->m_lastSentMsg = oldState;
return lResult;
}


CWnd::WindowProc


引用:

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;
}


CWnd::OnWndMsg


引用:

BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
LRESULT lResult = 0;
union MessageMapFunctions mmf;
mmf.pfn = 0;
检查是否特殊消息
映射至消息处理函数   
return TRUE;
}
本帖被评分 1 次
最后编辑天下奇才 最后编辑于 2008-09-28 15:41:13

一点点的激情,一点点的执着,让我一步一步的走入了自己梦寐以求的行业。从一个学校里年少轻狂的孩子,成为了一名信息安全的研发工程师。从只知道写代码,真正开始慢慢的去思考、设计和实现一种技术、一种算法、一个模块、一个软件乃至一个系统。
人生本来就该不断的追求梦想,不断的跨过一个又一个不可能穿越的鸿沟。别人看来,我很疯狂,但我笑了,人生能有几回疯?真正疯狂的人是不计后果的向前冲的,至少我还不是。我所想的,只是别人不敢想的。我所做的,只是别人不敢做的。一个一个虚无缥缈的事物,都必须是有一个一个疯狂的人逐渐的具体和完善。但愿我是这样的人,我只愿做这样的人。
gototop
 
1   1  /  1  页   跳转
页面顶部
Powered by Discuz!NT