【转】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
- }
【转】Windows消息投递流程:WM_COMMAND消息流程的更多相关文章
- WM_COMMAND消息
原文地址:https://blog.csdn.net/whm243149796/article/details/78966065 当用户点击菜单.按钮.下拉列表框等控件时候,会触发WM_COMMAND ...
- ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(五) 之 加好友,加群流程,消息管理和即时消息提示的实现
前言 前前一篇留了个小问题,在上一篇中忘了写了,就是关于LayIM已经封装好的上传文件或者图片的问题.对接好接口之后,如果上传速度慢,界面就会出现假死情况,虽然文件正在上传.于是我就简单做了个图标替代 ...
- Windows各种各种消息投递函数
1.SendMessage:发送消息给指定的窗口过程:直到窗口过程处理了消息才返回. 2.PostMessage:将消息放入消息队列(与指定窗口创建的线程相关)中:无需等待消息处理,立即返回. 不 ...
- [8]windows内核情景分析--窗口消息
消息与钩子 众所周知,Windows系统是消息驱动的,现在我们就来看Windows的消息机制. 早期的Windows的窗口图形机制是在用户空间实现的,后来为了提高图形处理效率,将这部分移入内核空间,在 ...
- skynet1.0阅读笔记2_skynet的消息投递skynet.call
为了了解 skynet.call 的调用过程,需要先看看 skynet的队列是如何把包分到不同工作线程的.看下图 查看 global_queue 的skynet_globalmq_push和skyne ...
- 【转】深入Windows内核——C++中的消息机制
上节讲了消息的相关概念,本文将进一步聊聊C++中的消息机制. 从简单例子探析核心原理 在讲之前,我们先看一个简单例子:创建一个窗口和两个按钮,用来控制窗口的背景颜色.其效果 图1.效果图 Win32 ...
- 深刻:截获windows的消息并分析实例(DefWindowProc),以WM_NCHITTEST举例(Windows下每一个鼠标消息都是由 WM_NCHITTEST 消息产生的,这个消息的参数包含了鼠标位置的信息)
1,回调函数工作机制 回调函数由操作系统自动调用,回调函数的返回值当然也是返回给操作系统了. 2,截获操作系统发出的消息,截获到后,将另外一个消息返回给操作系统,已达到欺骗操作系统的目的. 下面还是以 ...
- Kakfa消息投递语义
Message Delivery Semantics At most once -- Messages may be lost but are never redelivered(消息可能丢失但不会重 ...
- Windows消息【一】 消息队列
看了MSDN后,以下是我个人的理解! 消息能够被分为「队列化消息」和「非队列化消息」. 队列化消息是指当程序发生某事件时,由Windows主动捕获并把消息放入系统消息队列中,而程序在运行时会初始化一个 ...
随机推荐
- bzoj1604 / P2906 [USACO08OPEN]牛的街区Cow Neighborhoods
P2906 [USACO08OPEN]牛的街区Cow Neighborhoods 考虑维护曼哈顿距离:$\left | x_{1}-x_{2} \right |+\left | y_{1}-y_{2} ...
- 已知圆上三个点坐标,求圆半径 r 和 圆心坐标
问题: 已知圆上三个点坐标分别为(x1,y1).(x2,y2).(x3,y3) 求圆半径R和圆心坐标(X,Y) X,Y,R为未知数,x1,y1,x2,y2,x3,y3为常数 则由圆公式:(x1-X)² ...
- CentOS7.2 切换成iptables规则
关闭firewall service firewalld stop systemctl disable firewalld.service #禁止firewall开机启动 安装iptables规则: ...
- luogu P1162 填涂颜色
https://www.luogu.org/problem/show?pid=1162 //其实很简单的吧 //就是最外圈加一圈0 ,然后把外圈里面的0都遍历了 //剩下的0 就变成2 就行了 #in ...
- 更改idea快捷键方式为eclipse风格
打开配置窗口 菜单栏中的File-settings 或者快捷键 ctrl+alt+s 设置keymap 在弹出的setting页面中左侧导航中选择Keymap: 在keymaps下拉列表中选择Ecli ...
- 一个轻量级分布式 RPC 框架 — NettyRpc
原文出处: 阿凡卢 1.背景 最近在搜索Netty和Zookeeper方面的文章时,看到了这篇文章<轻量级分布式 RPC 框架>,作者用Zookeeper.Netty和Spring写了一个 ...
- Java如何将字符串中的敏感词替换为相等数量的星号*
Java如何将字符串中的敏感词替换为相等数量的星号* Java如何将字符串中的敏感词替换为相等数量的星号*,这也是我工作中遇到的问题,尝试了很多种方式最后采用这一种,在这里分享一下我的解决方式,代码效 ...
- Qt532_QWebView做成DLL供VC/Delphi使用_Bug
Qt5.3.2 vs2010 OpenGL ,VC6.0,Delphi7 1.自己继承 类QWebView,制作成DLL 供 VC6/Delphi7 使用 2.测试下来,DLL供VC6使用: 加载&q ...
- 豆知识扩展:HTML<meta> tag
豆知识: HTML<meta> tag Metadata 是关于数据的信息. The <meta> tag provides metadata关于网页.Metadat不会显示在 ...
- CentOS下安装Telnet服务
环境:centos6.6 IP:172.18.0.190 1.查看是否安装Telnet: rpm -qa telnet-server rpm -qa xinetd 2.安装Telnet: yum ...