Win32 SDK基础(八)之 关于Windows消息机制的详解(图)

夏涛小哥_7992

夏涛小哥_7992

2017-06-06

4476人浏览

原创

一、 什么是消息

        在解释什么是消息之前,我们先讨论一下程序的执行机制问题。大体上说,程序按照执行机制可以分为两类:
第一类是过程驱动。比如我们最早接触编程时写的c程序,又或者单片机程序。这类程序往往预先已经设定好了执行流程,我们执行时只是按部就班的执行;
第二类是事件驱动。事件,相信大家都能够理解。每个事件的发生都是随机的,每个事件都会有发生的时刻,类似生活中的事件。程序中的事件也会有自己的触发点,事件驱动程序就是事先编写好了针对每个事件的处理流程。在windows的操作系统中,消息就是windows中的事件。windows中的几乎每个操作都会触发消息,像我们之前讲过的创建窗口会触发wm_create消息,绘制窗口会触发wm_paint消息,我们点击鼠标、键盘、都会触发相应的消息。
        windows的消息被封装成了一个叫做msg的结构体,其原型如下:

typedef struct tagMSG { // msg 
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG;

Hwnd —— 触发消息的窗口的句柄。
Message —— 消息ID。Windows操作系统为每个消息都分配了一个消息ID,这个ID是唯一的。我们在上文中提到过的WM_CREATE本质就是一个整数,就是消息ID。
wParam —— 消息可附带的参数。
lParam —— 消息可附带的参数。
Time —— 发生消息的时刻。
Pt —— 发生消息时鼠标所在的位置。
以上参数对消息来说,缺一不可。
Windows中就是将一个个消息封装成MSG对象,发送消息时,将这些对象放置到消息队列中;获取消息时,也是获取的这些MSG对象。

二、 消息获取

2.1 消息队列

        我们说过,在Windows中几乎每个操作都会触发一条消息,这些消息都被发送到消息队列中。何为消息队列?我们可以将其理解为使用了一个存放Msg对象的先进先出的Deque—— Deque。消息队列分为两种,一种是系统消息队列,另外一种是进程消息队列。我们在触发消息后,消息先进入系统消息队列。操作系统处理后会根据消息的的窗口句柄hwnd值将消息分配到我们程序自己的消息队列,然后在我们程序内部进行消息的处理。

2.2 消息循环

        在前面的文章中,我们曾经写过一个消息循环。所谓的消息循环,就是不断的读取我们的进程中的消息队里中的消息,然后在进行处理。

void Message()  
{  
    MSG nMsg = { 0 };  
    while (GetMessage(&nMsg, NULL, 0, 0))  
    {  
        TranslateMessage(&nMsg);  
        DispatchMessage(&nMsg);  
    }  
}


        这里面,GetMessage()不断的在消息队列中抓取消息,其函数原型如下:
GetMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax)
lpMsg —— 用来存放消息的MSG类型的指针。
hWnd —— 指定取得其消息的窗口的句柄。当其值取NULL时,GetMessage为任何属于调用线程的窗口检索消息。
wMsgFilterMin —— 指定被检索的最小消息值的整数。
wMsgFilterMax —— 指定被检索的最大消息值的整数。

        GetMessage()获取到消息后,TranslateMessage会将消息进行翻译,主要是把虚拟键消息转换为字符消息。字符消息被寄送到调用线程的消息队列里,当下一次线程调用函数GetMessage或PeekMessage时被读出。Windows中每一个键盘按键,都对应了一个宏,这个键盘按键发出的消息就是虚拟键消息。TranslateMessage的作用就是将虚拟键消息转成字符消息WM_CHAR、WM_SYSCHAR等等。

三、消息处理

        DispatchMessage的作用就是将消息,分派到我们实现定义好的窗口处理函数中进行处理,下面是我们在之前的文章中定义的窗口处理函数:

笔目鱼英文论文写作器
笔目鱼英文论文写作器

一款AI论文写作工具,主要用于写高质量英文论文,就用笔目鱼,适合需要提升相关任务效率的用户。

下载
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)  
{  
	switch (uMsg)  
	{  
	case WM_DESTROY:  
		PostQuitMessage(0);//可¨¦以°?使º1GetMessage返¤¦Ì回?0  
		break;  
	default:  
		break;  
	}  
	return DefWindowProc(hWnd, uMsg, wParam, lParam);  
}


        hWnd就是产生消息的窗口句柄,uMsg是传递的消息,wParam和lParam分别是消息携带的两个参数。在上面的窗口处理函数中,我们定只处理了一个消息WM_DESTROY,这是我们在点击窗口的关闭按钮后产生的一个消息。我们说过,我们在创建窗口是,也会产生一个WM_CREATE消息。下面我们在窗口处理函数中处理这个消息:

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)  
{  
	switch (uMsg)  
	{  
	case WM_DESTROY:  
		PostQuitMessage(0);//可¨¦以°?使º1GetMessage返¤¦Ì回?0  
		break; 
	case  WM_CREATE:
		MessageBox(NULL,"WM_CREATE消息被处理了","消息处理",MB_OK);
	default:  
		break;  
	}  
	return DefWindowProc(hWnd, uMsg, wParam, lParam);  
}


        我们在接受到WM_CREATE后,会弹出一个对话框。预期的效果是点击这个对话框的确定按钮后才会显示窗口。如下面所示:

        运行程序,先弹出对话框:


        点击确定按钮后,弹出窗口:


相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
Go-Zero API开发使用教程
Go-Zero API开发使用教程

本专题聚焦Go-Zero的API开发,拆解.api描述文件的语法结构、路由与分组定义、参数绑定与校验规则,说明统一响应体、JWT鉴权、跨域与接口文档生成的落地方式,并给出网关聚合与接口测试的实践建议。

2026.11.12

80

15

Go-Zero安装与goctl环境配置教程
Go-Zero安装与goctl环境配置教程

本专题围绕Go-Zero的安装与工具链配置展开,讲清Go版本要求、goctl安装方式、代理镜像、protoc依赖与环境变量设置,说明多版本共存、升级回退与CI流水线安装的做法,并整理安装阶段的常见报错与验证步骤。

2026.11.12

60

15

Go-Zero零基础入门教程
Go-Zero零基础入门教程

本专题整理Go-Zero的入门知识,从框架定位、环境准备到跑通第一个API服务,讲清目录分层、配置加载、日志与中间件的基本用法,并对比Gin、Kratos的差异,帮助Go开发者建立整体认知,判断它是否适合当前项目。

2026.11.12

40

15

Postman身份认证怎么配置
Postman身份认证怎么配置

本专题从实际API接口调试场景出发,讲解Postman身份认证的完整配置流程,包括常见认证协议介绍、授权参数设置、访问令牌填写、OAuth 2.0授权及认证失败排查,帮助用户正确完成接口授权与访问验证。

2026.11.06

140

12

Postman请求头Headers怎么设置
Postman请求头Headers怎么设置

围绕Postman HTTP请求头配置展开,讲解Headers选项的具体使用方式,包括Key和Value参数填写、请求头信息添加、常见Header字段设置及请求头修改方法,帮助用户解决接口调试过程中遇到的请求头配置问题。

2026.11.06

120

13

Postman接口请求发送教程
Postman接口请求发送教程

详细介绍Postman接口请求的创建与发送方法,涵盖GET和POST请求、URL配置、请求参数、Headers请求头、Body请求体设置以及响应结果查看,帮助用户掌握Postman接口请求的完整操作流程。

2026.11.06

120

10

DBeaver怎么导入数据
DBeaver怎么导入数据

DBeaver数据导入专题,整理Excel、CSV、SQL、TXT等常见文件的数据导入方法,涵盖目标数据库选择、数据表创建、字段映射、数据类型设置及导入参数配置等操作,帮助用户将本地文件中的数据写入数据库,并了解批量导入、重复数据处理和导入失败等常见问题的解决方法。

2026.11.05

100

12

DBeaver安全防护教程大全
DBeaver安全防护教程大全

DBeaver安全防护专题,围绕数据库连接安全、账号密码保护和访问权限管理展开,整理SSL/TLS加密连接、SSH隧道、数据库凭据保存及证书验证等配置方法,同时介绍敏感信息保护、远程连接风险和高权限账号使用等注意事项,帮助用户提高数据库日常管理的安全性。

2026.11.05

80

12

DBeaver连接创建与配置教程
DBeaver连接创建与配置教程

本专题聚焦DBeaver数据库连接配置与管理,覆盖从新建连接、选择数据库类型到填写连接参数和验证连接的完整流程。针对MySQL、PostgreSQL、SQL Server等常见数据库,整理相应的连接设置方法,并提供驱动缺失、认证失败和连接异常等问题的排查方向。

2026.11.04

100

16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP注册时短信通知功能
PHP注册时短信通知功能

共8课时 | 13.1万人学习