windows 消息处理
文章目录
- 一、windows 消息类型
- 二、windows 消息队列
- 三、windows 队列消息和非队列消息
- 四、windows 消息优先级
- 五、TranslateMessage()
- 六、DispatchMessage()
- 七、SendMessage()与PostMessage()的区别
- 八、GetMessage()和PeekMessage()的区别
- 九、消息死锁
- 十、广播消息
- 十一、Windows 消息系统组成
- 十一、Windows 消息处理过程
- 十二、Windows 消息处理代码示例
一、windows 消息类型
Windows系统定义消息:
与窗口的内部运作有关,如创建窗口,绘制窗口,销毁窗口等。这种消息以WM_打头,如:WM_CREATE, WM_PAINT, WM_MOUSEMOVE控件通知消息
针对标准Windows控件的消息。这些控件包括:按钮(Button)、 组合框(ComboBox)、编辑框(TextBox)、列表框(ListBox)、 ListView控件、Treeview控件、 工具条(Toolbar)、 菜单(Menu)等。每种消息以不同的字符串打头自定义消息
二、windows 消息队列
- 系统消息队列
这是windows系统自身唯一的Queue,设备驱动把输入转化成消息存在系统队列中,然后系统会把此消息放到目标窗口所在的线程的消息队列中 - 应用程序线程消息队列
每一个GUI线程都会维护一个线程消息队列。为避免给non-GUI线程创建消息队列,所有线程创建时并没有消息队列,仅当线程第一次调用GDI函数时系统才给线程创建一个消息队列,然后线程消息队列中的消息会被送到相应的窗口过程去处理。CWinThread专门负责线程创建,它可以创建用户界面线程,及工作者线程,其中用户界面线程是包含消息队列的,而工作者线程是不包含消息队列的
三、windows 队列消息和非队列消息
- 队列消息
消息会先保存在消息队列中,消息循环会从此队列中取消息并分发到各窗口处理、如鼠标,键盘消息,WM_KEY*、WM_TIMER、WM_PAINT - 非队列消息
消息会绕过系统消息队列和应用程序线程消息队列,直接发送到窗口过程被处理,如: WM_ACTIVATE, WM_SETFOCUS, WM_SETCURSOR
四、windows 消息优先级
GetMessage()
从队列中按消息优先级获取消息,优先级由高到低:
- 其他线程通过
SendMessage()
发送给该窗口线程的消息,GetMessage()
直接调用窗口回调函数处理消息,直到没有该种类消息,再按顺序查找下面类型的消息 - 其他线程通过
PostMessage()
发送给该窗口线程的消息 WM_QUIT
消息,队列中轮询到该消息,GetMessage()
返回0,退出消息循环- 系统输入消息,如键盘,鼠标
WM_PAINT
消息WM_TIMER
消息
五、TranslateMessage()
用于将虚拟键值信息转换为字符信息,这一步是可选的。当我们敲击键盘上的某个字符键时,系统将产生 WM_KEYDOWN
和 WM_KEYUP
消息,这两个消息的附加参数(wParam和lParam)包含的是虚拟键代码和扫描码等信息,而我们在程序中往往需要得到某个字符的ASCII码,TranslateMessage
可以将 WM_KEYDOWN
和 WM_ KEYUP
消息的组合转换为一条WM_CHAR
消息(该消息的wParam附加参数包含了字符的ASCII码),并将转换后的新消息投递到调用线程的消息队列中。注意,TranslateMessage
函数并不会修改原有的消息,它只是产生新的消息并投递到消息队列中
六、DispatchMessage()
把 TranslateMessage
转换的消息交给操作系统,操作系统通过注册窗口类时指定的窗口过程对消息进行处理
七、SendMessage()与PostMessage()的区别
PostMessagex()
异步处理,发送的消息是队列消息,把消息放到指定窗口所在的线程消息队列中后立即返回,不等消息处理完成
SendMessage()
同步处理,发送的消息是非队列消息,发送的消息不会被加入到消息队列中,直接把消息送到窗口过程处理,处理完了才返回
八、GetMessage()和PeekMessage()的区别
GetMessage()
阻塞方式,直到消息队列中有消息才返回,并且会将消息从队列中删除,如果没有消息则阻塞等待
PeekMessage()
非阻塞方式,不管消息队列是否有消息均返回,通过参数决定是否将消息从队列删除,类似于查询队列
当获取到 WM__QUIT
消息时,返回0,否则返回非零值,当输入参数无效时返回-1
九、消息死锁
如果一个线程通过调用 SendMessage
函数给其他线程发送消息,那么这个线程要等到窗口处理函数处理完之后,SendMessage
函数才会返回,这个线程才能继续执行。假如接收线程在处理消息过程中让出来控制权,如接收线程也调用了 SendMessage
,那么双方线程都不能继续执行,都需要等待SendMessage
函数返回,这就有可能导致应用程序死锁
为了避免应用程序永久死锁,发送方应该考虑使用 SendNotifyMessage
或者 SendMessageTimeout
函数,或者窗口过程应该在调用上面那些可能让出控制权的函数之前先处理消息,如调用ReplyMessage
函数,以便于让对方能够继续执行,从而避免死锁
十、广播消息
消息广播简化了系统中需要向多个接收者发送消息的情况。通过 BroadcastSystemMessage
函数,定义好消息的接收者就是了。这个时候只需要定义一个或者多个接收者类型就行了,这些类型指的是应用程序,安装型驱动程序,网络驱动程序和系统级的设备驱动程序,系统会发送广播消息给每个指定类型的所有成员。
系统发送广播消息一般是在系统级设备驱动程序发生变化的时候而做出的响应,驱动程序可以广播消息给应用程序和其他组件来通知他们发生了改变。例如,当用户在软驱里面插入磁盘的时候,软驱的驱动程序就会广播一个消息,相关组件就会对这个消息作出反应
十一、Windows 消息系统组成
- 消息队列。Windows为每个应用程序维护一个消息队列,Windows消息队列是以GUI线程来分组的,也就是说每个GUI线程都有自己的消息队列
- 消息循环。应用程序从消息队列中获取消息,再把它分派给适当的某个窗口,然后继续从消息队列中获取下一条消息,再分派给适当的某个窗口,循环进行
- 窗口过程。每个窗口都有一个窗口过程来处理分派给窗口的消息,窗口过程是一个回调函数,处理了一个消息后,它通常要返回一个值给Windows
十一、Windows 消息处理过程
- 当鼠标、键盘事件被触发后,相应的设备驱动程序就把事件转换成消息,然后存到windows系统的消息队列中
- windows从系统消息队列取出的消息,并根据
hwnd
字段送往对应窗口所在线程的消息队列,同时消息从系统消息队列删除 - 应用程序通过
GetMessage()
从自己的消息队列中取出消息,如果队列中没有消息则阻塞 - 取出的消息通过
TranslateMessage()
进行转换,将虚拟键值信息转换为需要的字符信息 - 调用
DispatchMessage()
将消息再转给操作系统 - 操作系统调用注册窗口类时设置的窗口过程回调函数去处理消息,若不处理则会调用
DefWindowProc
函数做默认处理 - 循环 c~f 过程
十二、Windows 消息处理代码示例
#include <windows.h>
#include <stdio.h>// 窗口过程回调函数,DispatchMessage()后由操作系统调用
LRESULT CALLBACK MyWinProc(HWND hwnd, // handle to windowUINT uMsg, // message identifierWPARAM wParam, // first message parameterLPARAM lParam // second message parameter) {switch (uMsg) {case WM_CHAR: MessageBox(hwnd, "Pressed key xxx", "按键按下", MB_OK); break;case WM_LBUTTONDOWN: MessageBox(hwnd,"left button down","左键按下",MB_OK); break;case WM_CLOSE: DestroyWindow(hwnd); break; // 点击窗口关闭按钮,发送 WM_DESTROY 消息到应用消息队列,此时程序并没有退出case WM_DESTROY:PostQuitMessage(0); break; // 发送 WM_QUIT 消息到应用消息队列,GetMessage()返回0退出消息循环,此时程序退出default : return DefWindowProc(hwnd,uMsg,wParam,lParam); // 如果没有设置自定义消息处理,则使用默认消息处理}return 0;
}// 操作系统调用,参数已经赋值
int WINAPI WinMain(HINSTANCE hInstance, // handle to current instanceHINSTANCE hPrevInstance, // handle to previous instanceLPSTR lpCmdLine, // command lineint nCmdShow // show state) {WNDCLASS wndcls; //定义窗口类结构体变量wndcls.style = CS_HREDRAW|CS_VREDRAW;wndcls.lpfnWndProc = MyWinProc; // 设置自定义窗口过程,即注册自定义消息处理函数wndcls.cbClsExtra = 0;wndcls.cbWndExtra = 0;wndcls.hInstance = hInstance;wndcls.hIcon = LoadIcon(NULL, IDI_QUESTION);wndcls.hCursor = LoadCursor(NULL, IDC_SIZEALL);wndcls.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH); //笔,画刷,字体,调色板wndcls.lpszMenuName = NULL;wndcls.lpszClassName = "wenhui";/*注册窗口类*/RegisterClass(&wndcls);/*创建一个具体的窗口*/HWND hwnd = CreateWindow("wenhui", "红楼梦", WS_OVERLAPPEDWINDOW&~WS_MAXIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, 600, 400, NULL, NULL, hInstance, NULL);/*显示创建的一个具体窗口*/ShowWindow(hwnd, SW_SHOWNORMAL);/*更新一个窗口的客户区*/UpdateWindow(hwnd);MSG msg;while (GetMessage(&msg, NULL, 0, 0)) { // 只有取到 WM_QUIT 消息后,返回值为0才退出 while 循环 TranslateMessage(&msg); // 转换消息,将虚拟键值信息转换为字符信息DispatchMessage(&msg); // 发送消息给操作系统,然后由操作系统调用注册窗口类时设置的消息处理回调函数}return 0;
}/*
typedef struct tagMSG { HWND hwnd; // 窗口句柄UINT message; // 消息常量标识符WPARAM wParam; // 16位消息的特定附加信息 LPARAM lParam; DWORD time; // 消息创建时的时间POINT pt; // 消息创建时的鼠标位置
} MSG, *PMSG;
*/
windows 消息处理相关推荐
- 张赐荣 | Windows 消息处理机制 入门
张赐荣 | Windows 消息处理机制 入门 [文 / 张赐荣] 事件驱动和消息循环 消息概述 消息,就是指Windows发出的一个通知,告诉应用程序某个事情发生了.例如,单击鼠标.改变窗口尺寸.按 ...
- VC编程Windows消息处理机制、阻塞试验、SetTimer、MessageBox、小心消息响应处理函数
VC6标准WIN32程序,Windows消息处理机制: 1.在注册窗口类时,指定了消息处理函数WndProc(). 2.WinMain()里有消息循环: while (GetMessage(& ...
- windows消息处理机制
消息 Windows程序设计是一种完全不同于传统的DOS方式的程序设计方式,它是一种事件驱动的程序设计模式,主要是基于消息的. 例如,当用户在窗口窗口中画图的时候,按下鼠标左键,此时,操作系统会感知到 ...
- Windows消息处理
这里简述一下关于window消息处理,主要在实际应用中: 在一个Windows程序中,一个程序的的消息是通过一个大循环来实现接收处理的: 这个可以查看win32程序的编写,具体可以详细查找相关资料: ...
- windows消息处理过程及消息钩子
应用层发消息: 发送消息过程 SendMessage(user32.dll)->SendMessageWorker,先检查有没有hook消息钩子,有的话调用CsSendMessage,进入消息钩 ...
- C# winform自己实现Windows消息处理
Windows消息循环是Windows系统机制之一.在Win32的窗口程序中,一部分是通过WndProc这个函数来完成的. 在C# winform中,编程时看不到WndProc函数.但是form的基类 ...
- 《windows核心编程系列》十八谈谈windows钩子
windows应用程序是基于消息驱动的.各种应用程序对各种消息作出响应从而实现各种功能. windows钩子是windows消息处理机制的一个监视点,通过安装钩子能够达到监视指定窗体某种类型的消息的功 ...
- MFC消息处理学习总结
Windows消息机制概述 http://www.cppblog.com/suiaiguo/archive/2009/07/18/90412.html 消息是指什么? 消息系统对于一个win ...
- C# 消息处理学习总结
C# 收发和处理自定义的WINDOWS消息 http://blog.sina.com.cn/s/blog_45eaa01a01013zbs.html 为了程序启动后自动执行主函数,在Form1_Loa ...
最新文章
- git 远程分支创建与推送
- 将jar文件转换成exe可执行文件[转]
- Puppet 的部署与应用,看这一篇就够了
- 如何删除 macOS 压缩包中的隐藏文件?
- 【数字信号调制】基于matlab二进制数字频率调制(2FSK)【含Matlab源码 998期】
- 中文乱码问题:JSP页面的显示问题,获取中文参数值问题
- nvme固件升级 linux,Intel NVME SSD 固件升级步骤
- Skywalking vs Pinpoint
- windows无法上网:代理服务器出现问题或地址有误
- RASNet视频目标跟踪论文笔记
- linux proc/pid/stat解析
- 不是运算容错,而是高温降频率,软件劣化老硬件
- electron 主进程与渲染进程通讯
- 并发编程面试汇总(2020)
- 手把手教你使用java对接微信公众号-获取地理位置信息
- MYSQL学习笔记(自用)第七章
- 《LSTM神经网络和双色球预测例子》
- 偏微分方程简明教程第一章部分答案
- 更深、更轻量级的Transformer!Facebook提出:DeLighT
- 7月22日第壹简报,星期五,农历六月廿四
热门文章
- 相机里面删除的照片能找回来吗 相机上删除的照片可以找回吗
- 八道简单入门编程题详解+拓展(水花仙,二进制序列……)
- DAX中的ALL函数
- 太空上新 | 张肇达 张凯惠:嫦娥奔月有了现实版
- GO语言 | go work 神一般的管理 多个module没烦恼
- 【前端必备】使用NodeJs写接口(本地连接MySQL + 连接到云服务MySQL)
- 我与小娜(20):去LIGO,探秘光子接力赛
- IGA(In-Game Advertising):游戏内置广告
- 读书笔记 - 《天局》
- 阿里云国际版设置电子邮件托管教程详解