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

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

  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的值:

  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完成对消息的处理。

  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)的更多相关文章

  1. 【转】Windows消息投递流程:WM_COMMAND消息流程

    原文网址:http://blog.csdn.net/hyhnoproblem/article/details/6182585 该示例通过研究基本的单文档程序的“文件”--“打开”命令,分析WM_COM ...

  2. Windows窗口消息大全(转)

    Windows窗口消息大全,全不全自己看 ////////////////////////////////////////////////////////////////////////// #inc ...

  3. Windows窗口消息大全

    ////////////////////////////////////////////////////////////////////////// #include "AFXPRIV.H& ...

  4. Windows程序设计--(三)窗口与消息

    3.1 窗口的创建 3.1.1 系统结构概述 所谓「Windows给程序发送消息」,是指Windows呼叫程序中的一个函数,该函数的参数描述了这个特定消息.这种位于Windows程序中的函数称为「窗口 ...

  5. [8]windows内核情景分析--窗口消息

    消息与钩子 众所周知,Windows系统是消息驱动的,现在我们就来看Windows的消息机制. 早期的Windows的窗口图形机制是在用户空间实现的,后来为了提高图形处理效率,将这部分移入内核空间,在 ...

  6. 关于 OnCloseQuery: 顺序、不能关机等(所有的windows的广播消息都是逐窗口传递的)——如果一个窗体的OnCloseQuery事件中如果写了代码那么WM_QUERYENDSESSION消息就传不过去了msg.result会返回0,关机事件也就停止了

    系统关闭窗体的事件顺序为: OnCloseQuery ----> OnClose ----> OnDestroy 下面的代码说明问题: unit Unit3; interface uses ...

  7. 深刻:截获windows的消息并分析实例(DefWindowProc),以WM_NCHITTEST举例(Windows下每一个鼠标消息都是由 WM_NCHITTEST 消息产生的,这个消息的参数包含了鼠标位置的信息)

    1,回调函数工作机制 回调函数由操作系统自动调用,回调函数的返回值当然也是返回给操作系统了. 2,截获操作系统发出的消息,截获到后,将另外一个消息返回给操作系统,已达到欺骗操作系统的目的. 下面还是以 ...

  8. Windows消息理解(系统消息队列,进程消息队列,非队列消息)

    // ====================Windows消息分类==========================在Windows中,消息分为以下三类:标准消息——除WM_COMMAND之外,所 ...

  9. [转] C#中发送消息给指定的窗口,以及接收消息

    原文C#中发送消息给指定的窗口,以及接收消息 public class Note { //声明 API 函数 [DllImport("User32.dll", EntryPoint ...

随机推荐

  1. 【运维技术】CentOS7上从零开始安装阿里RocketMQ版本:release-4.0.1【亲测哈哈】

    CentOS7上从零开始安装阿里RocketMQ版本:release-4.0.1[亲测哈哈] 安装git # 更新包 $ yum update # 安装git $ yum install git # ...

  2. 20155201 实验三《Java面向对象程序设计》实验报告

    20155201 实验三<Java面向对象程序设计>实验报告 一.实验内容 XP基础 XP核心实践 相关工具 二.实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门 ...

  3. 20145311 《Java程序设计》第5周学习总结

    20145311 <Java程序设计>第5周学习总结 教材学习内容总结 第八章 8.1语法与继承结构 8.1.1Try.catch java中所有的错误都会打包为对象,可以try catc ...

  4. Android Studio安装与使用

    2013年谷歌推出android studio后,单独支持android开发,这是基于Java语言集成开发环境IntelliJ搭建的IDE.特别在android studio1.0稳定版出来后,谷歌将 ...

  5. HBase Shell相关

    1.进入hbase命令行 ./hbase shell 2.基本命令 显示hbase中的表List list 查询user表中的所有信息Scan scan 'users' 清空user表中的数据Trun ...

  6. CUDA、tensorflow与cuDNN的版本匹配问题【转】

    本文转载自:https://blog.csdn.net/MahoneSun/article/details/80809042 一.问题现象 CUDA.tensorflow 与 cuDNN有版本匹配的问 ...

  7. hdu_2048 错排问题

    错排问题本质上就是一个动态规划问题,其状态转移方程为: 记d[n]为n个人错排情况的总数. 那么策略可以描述为:分析第n个人错排的可能情况: 1)前n-1个人满足错排的情况,那么第n个人加入后还要错排 ...

  8. Android 旋转、平移、缩放和透明度渐变的补间动画

    补间动画就是通过对场景里的对象不断进行图像变化来产生动画效果.在实现补间动画时,只需要定义开始和结束的“关键帧”,其他过渡帧由系统自动计算并补齐.在Android中,提供了以下4种补间动画. **1. ...

  9. Stub学习

    RPC RPC(Remote Procedure Call)就是某台主机A(一般为client)像调用本地的过程一样去调用另一台主机B(一般为server)上的某个过程.RPC代码可能长成这个样子: ...

  10. 用 SQL 对关系型数据库进行查询

    前面几节中,我们已经掌握了如何向 SQLite 数据库中写入数据.这一节,我们将学习如何根据需求对数据库进行查询,进而从中获取数据.接下来的例子中会使用 data/datasets.sqlite(之前 ...