【转】Windows消息投递流程:一般窗口消息投递(WM_LBUTTONCLICK)

原文网址:http://blog.csdn.net/hyhnoproblem/article/details/6182646

本例通过在单文档程序的视图中添加WM_LBUTTONCLICK消息处理函数,来解释一般窗口消息的投递流程。 基于VS 2005

 

[cpp] view plaincopy
 
  1. BEGIN_MESSAGE_MAP(CMyView, CView)  
  2.     ON_WM_LBUTTONDBLCLK()  
  3. END_MESSAGE_MAP()  
  4. // ON_WM_LBUTTONDBLCLK宏展开  
  5. #define ON_WM_LBUTTONDBLCLK() /  
  6. { WM_LBUTTONDBLCLK, 0, 0, 0, AfxSig_vwp, /  
  7.     (AFX_PMSG)(AFX_PMSGW) /  
  8.     (static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, CPoint) > ( &ThisClass :: OnLButtonDblClk)) },  

 

 

从上面的代码可以看出WM_LBUTTONCLICK消息的类型标签是AfxSig_vwp, 在afxmsg_.h中有一个枚举类型AfxSig,消息标签主要用于区分消息处理函数的类型。该类型中定义了AfxSig_vwp的值:

 

 

[cpp] view plaincopy
 
  1. enum AfxSig  
  2. {  
  3.     //...  
  4.     AfxSig_vWp = AfxSig_v_W_p  
  5.     //...  
  6. }  

 

 

 

在AfxWndProc中,将消息中的句柄映射成窗口类指针,这个指针指向CMyView。AfxWndProc调用AfxCallWndProc,AfxCallWndProc调用CWnd::WindowProc,CWnd::WindowProc调用CWnd::OnWndMsg,CWnd::OnWndMsg完成对消息的处理。

 

 

[cpp] view plaincopy
 
  1. // wincore.cpp 1746  
  2. BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)  
  3. {  
  4.     // ...  
  5.     // GetMessageMap是个虚函数,因为当前指针是指向CMyView,所以取到的是CMyView的消息映射表  
  6.     const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap();     
  7.     UINT iHash; iHash = (LOWORD((DWORD_PTR)pMessageMap) ^ message) & (iHashMax-1);  
  8.     winMsgLock.Lock(CRIT_WINMSGCACHE);  
  9.     // 全局消息散列缓存,查找缓存  
  10.     AFX_MSG_CACHE* pMsgCache; pMsgCache = &_afxMsgCache[iHash];  
  11.     const AFX_MSGMAP_ENTRY* lpEntry;  
  12.     if (message == pMsgCache->nMsg && pMessageMap == pMsgCache->pMessageMap)  
  13.     {  
  14.         // cache hit  
  15.         lpEntry = pMsgCache->lpEntry;  
  16.         winMsgLock.Unlock();  
  17.         if (lpEntry == NULL)  
  18.             return FALSE;  
  19.         // cache hit, and it needs to be handled  
  20.         if (message < 0xC000)  
  21.             goto LDispatch;     // 系统消息?  
  22.         else  
  23.             goto LDispatchRegistered;       // 已注册消息?  
  24.     }  
  25.     else  
  26.     {  
  27.         // not in cache, look for it  
  28.         pMsgCache->nMsg = message;  
  29.         pMsgCache->pMessageMap = pMessageMap;  
  30.         for (/* pMessageMap already init‘ed */; pMessageMap->pfnGetBaseMap != NULL;  
  31.             pMessageMap = (*pMessageMap->pfnGetBaseMap)())  
  32.         {  
  33.             // Note: catch not so common but fatal mistake!!  
  34.             //      BEGIN_MESSAGE_MAP(CMyWnd, CMyWnd)  
  35.             ASSERT(pMessageMap != (*pMessageMap->pfnGetBaseMap)());  
  36.             if (message < 0xC000)  
  37.             {  
  38.                 // constant window message  
  39.                 if ((lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries,  
  40.                     message, 0, 0)) != NULL)  
  41.                 {  
  42.                     pMsgCache->lpEntry = lpEntry;  
  43.                     winMsgLock.Unlock();  
  44.                     goto LDispatch;  
  45.                 }  
  46.             }  
  47.             else  
  48.             {  
  49.                 // registered windows message  
  50.                 lpEntry = pMessageMap->lpEntries;  
  51.                 while ((lpEntry = AfxFindMessageEntry(lpEntry, 0xC000, 0, 0)) != NULL)  
  52.                 {  
  53.                     UINT* pnID = (UINT*)(lpEntry->nSig);  
  54.                     ASSERT(*pnID >= 0xC000 || *pnID == 0);  
  55.                     // must be successfully registered  
  56.                     if (*pnID == message)  
  57.                     {  
  58.                         pMsgCache->lpEntry = lpEntry;  
  59.                         winMsgLock.Unlock();  
  60.                         goto LDispatchRegistered;  
  61.                     }  
  62.                     lpEntry++;      // keep looking past this one  
  63.                 }  
  64.             }  
  65.         }  
  66.         pMsgCache->lpEntry = NULL;  
  67.         winMsgLock.Unlock();  
  68.         return FALSE;  
  69.     }  
  70.     // ...  
  71. LDispatch:  
  72.     mmf.pfn = lpEntry->pfn;  
  73.     switch (lpEntry->nSig)  
  74.     {  
  75.         //...  
  76.     case AfxSig_v_u_p:      // 消息标签  
  77.         {  
  78.             CPoint point(lParam);  
  79.             (this->*mmf.pfn_v_u_p)(static_cast<UINT>(wParam), point);  
  80.         }  
  81.         break;  
  82.         //...  
  83.     }  
  84.     //...  
  85. LDispatchRegistered:    // for registered windows messages  
  86.     ASSERT(message >= 0xC000);  
  87.     ASSERT(sizeof(mmf) == sizeof(mmf.pfn));  
  88.     mmf.pfn = lpEntry->pfn;  
  89.     lResult = (this->*mmf.pfn_l_w_l)(wParam, lParam);  
  90. }  
  91. // 消息处理函数类型枚举  
  92. union MessageMapFunctions  
  93. {  
  94.     AFX_PMSG pfn;   // generic member function pointer  
  95.     // ...  
  96.     LRESULT (AFX_MSG_CALL CWnd::*pfn_l_w_l)(WPARAM, LPARAM);  
  97. };  

 

【转】Windows消息投递流程:一般窗口消息投递(WM_LBUTTONCLICK)

上一篇:WinForm设置DataGridView某些行和列只读


下一篇:C#中的cookie编程