Win32下的消息流程清晰明了,但在MFC下,由于封装的缘故,隐藏的有点深,对一般的开发人员而言,就不甚明了喽。本文试图粗略展示出MFC下消息处理的基本流程。

 

一、先看一下Win32下的消息处理流程

 

每一个线程都对应有一个消息队列,利用API函数GetMessage从消息队列中获取消息,然后利用TranslateMessage翻译消息(主要是一些键盘消息),再利用DispatchMessage将消息分发给对应的窗口过程函数处理。


 

 

一般我们在WinMain函数中利用如下代码来处理消息:


 





  1. while (GetMessage(&msg, NULL, 0, 0))  
  2. {  
  3.     TranslateMessage(&msg);  
  4.     DispatchMessage(&msg);  
  5. }  
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}


 

 

很显然,整个消息循环很清楚。


 

二、MFC下的消息处理流程

 

1、MFC下的消息处理流程由thrdcore.cpp中的AfxInternalPumpMessage开始:


 





  1. BOOL AFXAPI AfxInternalPumpMessage()  
  2. {  
  3.     MSG msg;  
  4.     ::GetMessage(&msg, NULL, NULL, NULL);  
  5.     if (!AfxPreTranslateMessage(&msg))  
  6.     {  
  7.         ::TranslateMessage(&msg);  
  8.  ::DispatchMessage(&msg);  
  9.     }  
  10.     return TRUE;  
  11. }  
BOOL AFXAPI AfxInternalPumpMessage()
{
MSG msg;
::GetMessage(&msg, NULL, NULL, NULL);
if (!AfxPreTranslateMessage(&msg))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
return TRUE;
}


 

注:以上代码为示意代码,具体请参照MFC的源码。

很显然,其消息处理流程也类似<一>中Win32下的消息处理,只不过在调用TranslateMessage、DispatchMessage处理消息前增加了类似过滤的函数AfxPreTranslateMessage。该函数会调用CWnd类的PreTranslateMessage函数,函数返回True则消息将不会被处理。我们经常会通过重载CWnd类的PreTranslateMessage来改变MFC的消息控制流程。
2、窗口过程函数
通过调用DispatchMessage将消息分发给了具体的窗口过程函数处理。MFC下的所有窗口都拥有公用的窗口过程函数AfxWndProc。该函数的示意代码如下:


 





  1. LRESULT CALLBACK AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)  
  2. {  
  3.         CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);  //从HWND获取对应的CWnd*   
  4.         if (pWnd == NULL || pWnd->m_hWnd != hWnd)  
  5.                 return ::DefWindowProc(hWnd, nMsg, wParam, lParam);  
  6.         else      
  7.                 return pWnd->WindowProc(nMsg, wParam, lParam);  
  8. }  
LRESULT CALLBACK AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd); //从HWND获取对应的CWnd*
if (pWnd == NULL || pWnd->m_hWnd != hWnd)
return ::DefWindowProc(hWnd, nMsg, wParam, lParam);
else
return pWnd->WindowProc(nMsg, wParam, lParam);
}


    很显然,调用了CWnd类的虚函数virtual CWnd::WindowProc处理。




  1. LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)  
  2. {  
  3.     // OnWndMsg does most of the work, except for DefWindowProc call   
  4.     LRESULT lResult = 0;  
  5.     if (!OnWndMsg(message, wParam, lParam, &lResult))  
  6.         lResult = DefWindowProc(message, wParam, lParam);  
  7.     return lResult;  
  8. }  
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;
}


    WindowProc函数又调用了CWnd类的虚函数virtual CWnd::OnWndMsg处理。

 

 




  1. BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)  
  2. {  
  3.     LRESULT lResult = 0;  
  4.     union MessageMapFunctions mmf;  
  5.     mmf.pfn = 0;  
  6.     CInternalGlobalLock winMsgLock;  
  7.     // special case for commands   
  8.     if (message == WM_COMMAND)  
  9.     {  
  10.         if (OnCommand(wParam, lParam))  
  11.         {  
  12.             lResult = 1;  
  13.             goto LReturnTrue;  
  14.         }  
  15.         return FALSE;  
  16.     }  
  17.   
  18.     // special case for notifies   
  19.     if (message == WM_NOTIFY)  
  20.     {  
  21.         NMHDR* pNMHDR = (NMHDR*)lParam;  
  22.         if (pNMHDR->hwndFrom != NULL && OnNotify(wParam, lParam, &lResult))  
  23.             goto LReturnTrue;  
  24.         return FALSE;  
  25.     }  
  26.       
  27.     ......  
  28.   
  29.     return TRUE;  
  30. }  
BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
LRESULT lResult = 0;
union MessageMapFunctions mmf;
mmf.pfn = 0;
CInternalGlobalLock winMsgLock;
// 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;
}

......

return TRUE;
}
在OnWndMsg函数中会根据具体的消息类型,在MFC的消息映射表中找到对应的函数处理。
以上就是MFC处理消息的大致流程。