【转】Windows消息投递流程:WM_COMMAND消息流程
原文网址:http://blog.csdn.net/hyhnoproblem/article/details/6182585
该示例通过研究基本的单文档程序的“文件”--“打开”命令,分析WM_COMMAND消息投递流程。基于VS 2005 代码
AfxWndProc最终调用的是OnWndMsg,这个函数负责消息的分发处理。当消息是WM_COMMAND时,将消息投递给OnCommand函数。
- // wincore.cpp 1746
- 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;
- }
- //...
- }
OnCommand是个虚函数,因为消息是主窗口产生的,所以调用的是CFrameWnd::OnCommand函数该函数先检查该消息是不是在线请求帮助,如果是,则程序给框架窗口发送一个WM_COMMANDHELP消息,否则交由基类CWnd::OnCommand()处理。
- // winfrm.cpp 299
- BOOL CFrameWnd::OnCommand(WPARAM wParam, LPARAM lParam)
- // return TRUE if command invocation was attempted
- {
- HWND hWndCtrl = (HWND)lParam;
- UINT nID = LOWORD(wParam);
- CFrameWnd* pFrameWnd = GetTopLevelFrame();
- ENSURE_VALID(pFrameWnd);
- if (pFrameWnd->m_bHelpMode && hWndCtrl == NULL &&
- nID != ID_HELP && nID != ID_DEFAULT_HELP && nID != ID_CONTEXT_HELP)
- {
- // route as help
- if (!SendMessage(WM_COMMANDHELP, 0, HID_BASE_COMMAND+nID))
- SendMessage(WM_COMMAND, ID_DEFAULT_HELP);
- return TRUE;
- }
- // route as normal command
- return CWnd::OnCommand(wParam, lParam);
- }
CWnd::OnCommand首先检查表示控件的LPARAM。如果消息是由控件产生的,LPARAM就会包含控件窗口句柄。如果消息是控件通知,框架就会执行特定的处理过程。如果消息是为某个控件产生的,OnCommand会将消息直接发送给控件,然后OnCommand返回。否则,CWnd::OnCommand()要确保产生命令的界面元素没有被禁用,然后将消息传递给OnCmdMsg函数,调用的是CFrameWnd::OnCmdMsg函数
- // wParam
- // The high-order word specifies the notification code if the message is from a control.
- // If the message is from an accelerator, this value is 1. If the message is from a menu,
- // this value is zero.
- // The low-order word specifies the identifier of the menu item, control, or accelerator.
- // lParam
- // Handle to the control sending the message if the message is from a control.
- // Otherwise, this parameter is NULL.
- BOOL CWnd::OnCommand(WPARAM wParam, LPARAM lParam)
- // return TRUE if command invocation was attempted
- {
- UINT nID = LOWORD(wParam);
- HWND hWndCtrl = (HWND)lParam;
- int nCode = HIWORD(wParam);
- // default routing for command messages (through closure table)
- if (hWndCtrl == NULL)
- { // 菜单命令先走这里
- // zero IDs for normal commands are not allowed
- if (nID == 0)
- return FALSE;
- // make sure command has not become disabled before routing
- CTestCmdUI state;
- state.m_nID = nID;
- OnCmdMsg(nID, CN_UPDATE_COMMAND_UI, &state, NULL); // CFrameWnd::OnCmdMsg
- if (!state.m_bEnabled)
- {
- TRACE(traceAppMsg, 0, "Warning: not executing disabled command %d/n", nID);
- return TRUE;
- }
- // menu or accelerator
- nCode = CN_COMMAND;
- }
- else
- {
- // ToolBar命令走这里,或控件通知
- // control notification
- ASSERT(nID == 0 || ::IsWindow(hWndCtrl));
- if (_afxThreadState->m_hLockoutNotifyWindow == m_hWnd)
- return TRUE; // locked out - ignore control notification
- // reflect notification to child window control
- if (ReflectLastMsg(hWndCtrl))
- return TRUE; // eaten by child
- // zero IDs for normal commands are not allowed
- if (nID == 0)
- return FALSE;
- }
- // 调用CFrameWnd::OnCmdMsg
- return OnCmdMsg(nID, nCode, NULL, NULL);
- }
CFrameWnd::OnCmdMsg函数调用时,pExtra和pHandlerInfo是NULL,因为处理命令不需要这一信息。取出的消息按照以下顺序经过应用程序的各个部分:活动视图、活动视图的文档、文档模板、主窗口、应用程序。
- // winfrm.cpp 880
- BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,
- AFX_CMDHANDLERINFO* pHandlerInfo)
- {
- CPushRoutingFrame push(this);
- // 将消息传递给活动视图,调用CView::OnCmdMsg
- CView* pView = GetActiveView();
- if (pView != NULL && pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
- return TRUE;
- // 由框架处理该消息,CWnd没有覆盖OnCmdMsg,调用CCmdTarget::OnCmdMsg
- if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
- return TRUE;
- // 将消息传递给应用程序,CWinApp没有覆盖OnCmdMsg,所以调用CCmdTarget::OnCmdTarget
- CWinApp* pApp = AfxGetApp();
- if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
- return TRUE;
- return FALSE;
- }
- // viewcore.cpp 154
- BOOL CView::OnCmdMsg(UINT nID, int nCode, void* pExtra,
- AFX_CMDHANDLERINFO* pHandlerInfo)
- {
- // 首先由活动视图处理该消息,调用CCmdTarget::OnCmdMsg
- if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
- return TRUE;
- // then pump through document
- if (m_pDocument != NULL)
- {
- // 将该消息传递给视图对应的文档,调用CDocument::OnCmdMsg
- CPushRoutingView push(this);
- return m_pDocument->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
- }
- return FALSE;
- }
- // doccore.cpp 834
- BOOL CDocument::OnCmdMsg(UINT nID, int nCode, void* pExtra,
- AFX_CMDHANDLERINFO* pHandlerInfo)
- {
- if (CCmdTarget::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
- return TRUE;
- // otherwise check template,调用CDocTemplate::OnCmdMsg
- if (m_pDocTemplate != NULL &&
- m_pDocTemplate->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
- return TRUE;
- return FALSE;
- }
- // doctempl.cpp 370
- BOOL CDocTemplate::OnCmdMsg(UINT nID, int nCode, void* pExtra,
- AFX_CMDHANDLERINFO* pHandlerInfo)
- {
- BOOL bReturn;
- CCmdTarget* pFactory = DYNAMIC_DOWNCAST(CCmdTarget, m_pAttachedFactory);
- if (nCode == CN_OLE_UNREGISTER && pFactory != NULL)
- bReturn = pFactory->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
- else
- bReturn = CCmdTarget::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
- return bReturn;
- }
上面的一些函数确定了程序执行流程,最终会调用到CCmdTarget::OnCmdMsg,该函数通过查找消息映射表,进而调用到消息处理函数。
- // cmdtarg.cpp 297
- BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode, void* pExtra,
- AFX_CMDHANDLERINFO* pHandlerInfo)
- {
- // ...
- // determine the message number and code (packed into nCode)
- const AFX_MSGMAP* pMessageMap;
- const AFX_MSGMAP_ENTRY* lpEntry;
- UINT nMsg = 0;
- //...
- 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;
- // look through message map to see if it applies to us
- for (pMessageMap = GetMessageMap(); pMessageMap->pfnGetBaseMap != NULL;
- pMessageMap = (*pMessageMap->pfnGetBaseMap)())
- {
- // Note: catches BEGIN_MESSAGE_MAP(CMyClass, CMyClass)!
- ASSERT(pMessageMap != (*pMessageMap->pfnGetBaseMap)());
- lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, nMsg, nCode, nID);
- if (lpEntry != NULL)
- {
- // found it
- return _AfxDispatchCmdMsg(this, nID, nCode,
- lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo);
- }
- }
- return FALSE; // not handled
- }
转载于:https://www.cnblogs.com/wi100sh/p/4210211.html
【转】Windows消息投递流程:WM_COMMAND消息流程相关推荐
- 消息驱动 微服务器,消息驱动的微服务-Spring Cloud Stream整合RocketMQ
系列文章导航: Spring Cloud Alibaba微服务解决方案 常用MQ产品的选择 目前主流的MQ产品有kafka.RabbitMQ.ActiveMQ.RocketMQ等.在MQ选型时可以参照 ...
- Consumer消息拉取和消费流程分析
1. 前言 MQConsumer是RocketMQ提供的消费者接口,从接口定义上可以看到,它主要的功能是订阅感兴趣的Topic.注册消息监听器.启动生产者开始消费消息. 消费者获取消息的模式有两种 ...
- RocketMQ:Consumer概述及启动流程与消息拉取源码分析
文章目录 Consumer 概述 消费者核心类 消费者启动流程 消息拉取 PullMessageService实现机制 ProcessQueue实现机制 消息拉取基本流程 客户端发起消息拉取请求 消息 ...
- RocketMQ:Producer启动流程与消息发送源码分析
文章目录 Producer 1.方法和属性 2.启动流程 3.消息发送 3.1验证消息 3.2查找路由 3.3选择队列 3.4发送消息 3.5发送批量消息 Producer 在RocketMQ中,消息 ...
- 详解Windows消息分类以及WM_COMMAND与WM_NOTIFY的区别,以及模拟发送控件通知消息
Windows消息的分类 1. 标准消息(队列消息) 除WM_COMMAND之外,所有以WM_开头的消息都是标准消息,如WM_MOUSEMOVE.WM_LBUTTONUP.WM_KEYDOWN.W ...
- 【转】详解Windows消息分类以及WM_COMMAND与WM_NOTIFY的区别,以及模拟发送控件通知消息
转自:http://blog.sina.com.cn/s/blog_4b3c1f950100nten.html Windows消息的分类 1. 标准消息(队列消息) 除WM_COMMAND之外,所 ...
- ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(五) 之 加好友,加群流程,消息管理和即时消息提示的实现...
前言 前前一篇留了个小问题,在上一篇中忘了写了,就是关于LayIM已经封装好的上传文件或者图片的问题.对接好接口之后,如果上传速度慢,界面就会出现假死情况,虽然文件正在上传.于是我就简单做了个图标替代 ...
- 企业微信推送消息延迟_一种基于企业微信的消息推送方法与流程
本发明涉及消息推送技术领域,特别涉及一种基于企业微信的消息推送方法. 背景技术: 随着微信公众号的普及,微信企业号也越来越受到人们的关注.而腾讯公司在微信企业号的基础上又进行了进一步的升级,提供了类似 ...
- 【微信小程序】客服系统,客服聊天发送商品详情,快捷发送链接和图文消息,附代码和流程
客服聊天发送商品详情,快捷发送链接和图文消息,附代码和流程 遇到一个新需求,需要做一个客服聊天的功能能够发送链接和图文消息,先在小程序后台做一个配置,首先在后台添加客服 然后客服按钮编写,功能实现 小 ...
最新文章
- 《JavaScript设计模式与开发实践》模式篇(12)—— 装饰者模式
- HDU 1248 寒冰王座
- 对科目***货币 ***未定义汇率差额科目
- [Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated
- layui按钮展开、_layui可折叠的组织架构树形图
- 关联关系、依赖关系总结
- [html] 如果要开发一个在超级大屏上显示的可视化页面,你首先要考虑什么?
- Hadoop Balancer运行速度优化
- Python中的TCP的客户端UDP学习----第一篇博客
- 使用java 遍历文件夹
- Ora-00600 错误的代码含义及常用查询
- Linux下find命令实例
- 多多客api_蚂蚁星球(原好京客)(haojingke.com)- 做大京客,享大数据营销 - 拼多多API接口...
- python之 ffmpeg给图片添加文字
- 软件工程笔记四__实体联系图(ER图)
- MySQL5.5安装及其配置
- LCD与LED液晶显示屏
- 直播技术总结(三)ijkplayer的一些问题优化记录
- 无线运维的起源与项目建设思考
- async和await以及promise的区别
热门文章
- 团队开发冲刺1.2(2015.5.10)
- C++primer plus第六版课后编程题答案8.6
- SPOJ GCDEX (数论)
- 在DataTable中进行数据查询 (转)
- linux中的特殊文件权限
- Python中Collections模块的Counter容器类使用教程
- 就计算机结构与课程的论文,关于计算机组成原理的课程论文(2)
- (23)触发器verilog与VHDL编码(学无止境)
- 一寸照纯红色底图片_高大上的图片精修,其实只需要学会这7个方面!
- STM32F103_EXTI外部中断