windows SDK编程 --- 消息(3)

前置知识

一、消息的分类

1. 鼠标消息

处理与鼠标交互相关的事件,比如移动、点击和滚动等。例如:

  • WM_MOUSEMOVE: 当鼠标在窗口客户区内移动时发送。
  • WM_LBUTTONDOWN: 当用户按下鼠标左键时发送。
  • WM_LBUTTONUP: 当用户释放鼠标左键时发送。
  • WM_RBUTTONDOWN: 当用户按下鼠标右键时发送。
  • WM_RBUTTONUP: 当用户释放鼠标右键时发送。
  • WM_MBUTTONDOWN: 当用户按下鼠标中键时发送。
  • WM_MBUTTONUP: 当用户释放鼠标中键时发送。
  • WM_MOUSEWHEEL: 当用户旋转鼠标滚轮时发送。

2. 键盘消息

  • WM_KEYDOWN: 当用户按下一个键盘键时发送,不包括系统键,如 Alt 和 F10。
  • WM_KEYUP: 当用户释放一个键盘键时发送。
  • WM_CHAR: 当按下的键产生了一个字符时发送,比如按下了 ‘A’。

3. 快捷键消息

  • WM_HOTKEY: 当用户按下注册的热键时发送。

4. 菜单消息

  • WM_COMMAND: 可以由菜单、加速器、控件发送,用来指示用户选择了哪个命令或操作。

5. 窗口消息

  • WM_CREATE: 在创建窗口时发送,通常用于初始化操作。
  • WM_CLOSE: 当窗口被请求关闭时发送,可以由用户操作或程序控制触发。
  • WM_DESTROY: 当窗口即将被销毁时发送。
  • WM_MOVE: 当窗口改变位置时发送。
  • WM_SIZE: 当窗口改变大小时发送。
  • WM_PAINT: 当客户区需要重绘时发送。

6. 控件消息

  • WM_HSCROLL: 当水平滚动条被滚动时发送。
  • WM_VSCROLL: 当垂直滚动条被滚动时发送。
  • WM_NOTIFY: 控件向父窗口发送通知消息,例如列表视图的项被点击。

7. 自定义消息

  • WM_USER + X: 开发者定义的消息,用于特定应用程序的自定义事件,其中 X 是一个大于等于 0 的整数。

8.系统消息

  • WM_ACTIVATE: 窗口被激活或停用时发送。
  • WM_SETFOCUS: 窗口获得焦点时发送。
  • WM_KILLFOCUS: 窗口失去焦点时发送。
  • WM_TIMER: 处理定时器消息,当定时器到期时发送。
  • WM_QUIT: 指示程序退出,通常由 PostQuitMessage 发出。

二、消息处理流程

在 Windows 程序中,消息处理的流程是通过一个称为消息循环的结构,结合窗口过程(WndProc)来完成的。这个窗口过程是一个由开发者实现的函数,用于响应和处理发送到窗口的消息。以下是详细的消息处理流程:

1.消息循环

  1. 程序入口(WinMain):程序启动后,在 WinMain 函数中初始化应用程序,并进入消息循环。
  2. 消息获取(GetMessage):通过调用 GetMessage 函数从消息队列中检索消息。这个函数会阻塞,直到队列中有消息。
  3. 消息翻译(TranslateMessage):一些消息,如键盘输入,可能需要翻译和预处理。TranslateMessage 函数会对这些消息进行适当处理,比如生成字符消息(WM_CHAR)。
  4. 消息分发(DispatchMessage):然后调用 DispatchMessage 函数,将消息传递给相应窗口的窗口过程进行处理。

2. 窗口过程 (WndProc)

  1. 定义窗口过程:在创建窗口时指定的窗口过程函数(通常称为 WndProc)。
  2. 处理消息:窗口过程接收到消息后,会使用一个 switch 语句(或类似的结构)来识别消息类型,并对每种类型的消息做出响应。
  3. 执行动作:根据消息类型,窗口过程会执行特定的动作。例如,WM_PAINT 消息会导致窗口重新绘制其内容,WM_DESTROY 消息会触发清理资源的操作。
  4. 默认处理:对于窗口过程未处理的消息,通常会调用 DefWindowProc 函数,这是系统提供的默认窗口过程,用于处理标准动作。

3. 关闭流程

  1. 接收 WM_CLOSE:当用户点击窗口关闭按钮或者通过其他方式请求关闭窗口时,WM_CLOSE 消息会被发送到窗口过程。
  2. 可选的处理:窗口过程可以选择如何响应 WM_CLOSE。如果程序需要确认用户的关闭请求(比如,询问是否保存数据),就可以在这里实现。
  3. 调用 DestroyWindow:如果窗口过程确认关闭,它会调用 DestroyWindow 函数来销毁窗口。
  4. 接收 WM_DESTROY:DestroyWindow 调用后,WM_DESTROY 消息会被发送到窗口过程。在这里,窗口过程通常会进行资源的最终清理。
  5. 发送 WM_QUIT:在 WM_DESTROY 的处理结束后,窗口过程会调用 PostQuitMessage 函数,这会放置 WM_QUIT 消息到消息队列。
  6. 结束消息循环:当 GetMessage```检索到 WM_QUIT`` 消息时,它会返回 0,导致消息循环结束,程序随之退出。

三、WM_CLOSE 和 WM_DESTROY的使用时机

WM_CLOSE

目的与时机:
WM_CLOSE 消息是当用户点击窗口的关闭按钮,或者通过程序调用 CloseWindow() 函数时发送的。这个消息是一个请求,指示应用程序应当开始关闭窗口的过程。
处理:
接收到 WM_CLOSE 消息后,窗口过程可以选择执行多种操作,例如提示用户保存未保存的工作、清理资源或直接关闭。如果决定继续关闭窗口,窗口过程通常会调用 DestroyWindow() 函数来销毁窗口。
可选性:
WM_CLOSE 是可拦截和可忽略的。应用程序可以根据用户的选择或其他条件决定是否响应 WM_CLOSE,或者如何响应。

WM_DESTROY

目的与时机:
WM_DESTROY 消息是在窗口实际被销毁前发送的。当 DestroyWindow() 函数被调用时,该函数先处理所有必要的资源释放,然后发送 WM_DESTROY 消息给窗口过程。
处理:
接收到 WM_DESTROY 消息时,窗口过程应该处理所有最终的清理工作,如释放内存、保存状态等。处理完成后,通常会调用 PostQuitMessage() 函数来发送 WM_QUIT 消息,这会导致消息循环结束,进而使应用程序退出。
不可忽略:
WM_DESTROY 是窗口生命周期的自然部分,它表示窗口即将被销毁,不应被忽略或拦截,以确保资源得到正确释放。

总结:

  • WM_CLOSE 可以视为关闭过程的开始,是一个可以被程序控制和决定的阶段,而 WM_DESTROY 则标志着关闭过程的终结,窗口即将被销毁,此时应进行最后的清理工作。
  • WM_CLOSE 可以看作是一个警告或询问(即将关闭,是否继续?),而 WM_DESTROY 是确认(窗口正在被销毁)。


四、CreateWindowEx()

调用 CreateWindowEx() 函数会触发一系列窗口消息,这些消息涉及到窗口的创建和显示过程。以下是在调用 CreateWindowEx() 时通常会触发的主要消息,按照它们出现的典型顺序列出:

1. WM_GETMINMAXINFO

  • 这是创建过程中收到的第一个消息。
  • 在窗口创建期间,此消息请求窗口的最小和最大尺寸限制。
  • 这个消息可以用于限制窗口的大小或提供特定的尺寸限制。

2. WM_NCCREATE

  • 此消息在窗口的非客户区(如标题栏、边框等)被创建前发送。
  • 它用于准备窗口创建,如果窗口过程返回 FALSE,窗口创建将立即停止。

3. WM_NCCALCSIZE

  • 当系统或另一个应用程序发送大小和位置改变请求时,发送此消息。
  • 它用于计算窗口的客户区大小,即实际显示内容的区域。

4. WM_CREATE

  • 在窗口的客户区和非客户区都创建好之后发送。
  • 此消息通常用于执行初始化任务,如创建子控件、分配资源等。
  • 如果窗口过程返回 -1,则窗口创建将被终止,窗口也将被销毁。

五、调试技巧

1. 监视

在 Visual Studio 中使用 消息变量名,wm 来在监视窗口中查看 Windows 消息名称是一个非常方便的功能,它可以帮助开发者直观地理解当前处理的消息类型。

在这里插入图片描述

2. 调试输出函数

1.为什么不能用printf?
  • 一般开发 Windows GUI 应用程序并不附带控制台窗口,printf 只能向控制台输出文本,但如果没有控制台这些输出就无处显示。
2. OutputDebugString函数:
  • OutputDebugString 是 Windows API 中的一个调试辅助函数,它用于将字符串信息发送到调试器的输出窗口。这对于开发和调试 Windows 应用程序非常有用,尤其是当你需要在运行时监控程序的内部状态或行为时。
case WM_LBUTTONDOWN:{int x = (int)(short)LOWORD(lParam);  // 新的 X 坐标int y = (int)(short)HIWORD(lParam);  // 新的 Y 坐标char buffer[100];//将格式化的数据写入到buffer缓冲区中wsprintf(buffer, "你点击了,x坐标:%d, y坐标:%d\n", x, y);//输出调试信息OutputDebugString(buffer);return 0;}
3. 捕捉输出调试信息
  • 使用vs2019查看OutputDebugString输出的调试信息
    在这里插入图片描述
  • 使用 DebugView 来捕捉由 OutputDebugString 输出的调试信息。点击下载
  • 在 DebugView 中,确保勾选 Capture 菜单下的 Capture Global Win32 选项,这允许 DebugView 捕捉所有进程的输出,而不仅仅是当前用户会话的进程。
  • 注意:当你使用 Visual Studio 2019 或任何其他 IDE 调试程序时,可能会遇到 DebugView 无法捕捉到由 OutputDebugString 输出的调试信息的情况。这通常是因为调试器已经接管了调试输出。你需要在外部直接打开exe。

在这里插入图片描述

示例代码

#include <windows.h>//显示错误信息
void ShowErrorMessage();//5.消息处理
LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam
)
{// 根据消息类型进行分支处理switch (msg){case WM_CREATE:{OutputDebugString("WM_CREATE\n");return 0;}case WM_CLOSE:{//询问是否关闭窗口int id = MessageBox(NULL, "你确定关闭窗口吗", "WM_CLOSE", MB_YESNO);if (id == IDYES){DestroyWindow(hwnd);}return 0;}case WM_DESTROY:{OutputDebugString("WM_DESTROY\n");PostQuitMessage(0);return 0;}case WM_MOVE:      //窗口移动{int x = (int)(short)LOWORD(lParam);  // 新的 X 坐标int y = (int)(short)HIWORD(lParam);  // 新的 Y 坐标char buffer[100];wsprintf(buffer,"窗口移动到了:x坐标:%d, y坐标:%d\n",x,y);OutputDebugString(buffer);break;}case WM_LBUTTONDOWN:    //鼠标左键按下{int x1 = (int)(short)LOWORD(lParam);  // 新的 X 坐标int y1 = (int)(short)HIWORD(lParam);  // 新的 Y 坐标char buffer1[100];wsprintf(buffer1, "鼠标点击了,x坐标:%d, y坐标:%d\n", x1, y1);OutputDebugString(buffer1);return 0;}}return DefWindowProc(hwnd, msg, wParam, lParam);}int WINAPI WinMain(HINSTANCE hInstance,     // 当前实例的句柄HINSTANCE hPrevInstance, // 前一个实例的句柄,现在总是为 NULLLPSTR lpCmdLine,         // 命令行参数的字符串int nCmdShow             // 指示程序窗口应如何被显示
)
{//1.注册窗口char MyWindowClassName[] = "MyWindowClass";         //窗口类名WNDCLASSEX wc = { 0 };wc.cbSize = sizeof(WNDCLASSEX);wc.style = CS_VREDRAW | CS_HREDRAW;     //wc.lpfnWndProc = WndProc;    //窗口过程函数(窗口回调函数->处理消息)wc.hInstance = hInstance;wc.hIcon = NULL;             //图标wc.hCursor = NULL;          //光标wc.hbrBackground = CreateSolidBrush(RGB(0, 255, 0));    //窗口背景颜色刷子wc.lpszMenuName = NULL;     //菜单名称wc.lpszClassName = MyWindowClassName;    //窗口类名if (RegisterClassEx(&wc) == 0){ShowErrorMessage();return 0;}//2.创建窗口char MyWindowName[] = "MyWindowClass";         //窗口名称HWND hwnd = CreateWindowEx(0,MyWindowClassName,MyWindowName,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);if (hwnd == NULL){ShowErrorMessage();return 0;}//3.显示更新窗口ShowWindow(hwnd, SW_SHOWNORMAL);UpdateWindow(hwnd);//4.消息循环(消息队列)MSG msg = {};while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}return 0;
}void ShowErrorMessage()
{char szErrorMessage[512];  // 错误消息缓冲区DWORD dwResult = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,NULL,GetLastError(),0,szErrorMessage,sizeof(szErrorMessage) / sizeof(WCHAR),NULL);if (dwResult > 0) {// 使用 MessageBox 显示错误消息MessageBox(NULL, szErrorMessage, "Error", MB_OK | MB_ICONERROR);}else {// 如果无法获取错误消息,使用 MessageBox 显示一个失败通知MessageBox(NULL, "Failed to retrieve the error message.", "Error", MB_OK | MB_ICONERROR);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/827276.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

区块链交易所技术开发架构解析 交易所开发团队

区块链交易所是加密货币市场中的关键基础设施之一&#xff0c;它提供了一个平台&#xff0c;让用户可以买卖各种数字资产。而搭建一个功能完善、安全可靠的交易所需要一个复杂的技术开发架构&#xff0c;以及一个协调配合的交易所开发团队。下面我们将分析交易所的技术架构以及…

Elasticsearch:崭新的打分机制 - Learning To Rank (LTR)

警告&#xff1a;“学习排名 (Learning To Rank)” 功能处于技术预览版&#xff0c;可能会在未来版本中更改或删除。 Elastic 将努力解决任何问题&#xff0c;但此功能不受官方 GA 功能的支持 SLA 的约束。 注意&#xff1a;此功能是在版本 8.12.0 中引入的&#xff0c;并且仅适…

Ghost Buster Pro for Mac:强大的系统优化工具

Ghost Buster Pro for Mac是一款功能强大的系统优化工具&#xff0c;专为Mac用户设计&#xff0c;旨在提供全方位的系统清理、优化和维护服务。 Ghost Buster Pro for Mac v3.2.5激活版下载 这款软件拥有出色的垃圾清理能力&#xff0c;能够深度扫描并清除Mac上的无效目录、文件…

个人网站的SEO优化系列——如何实现搜索引擎的收录

如果你自己做了一个网站&#xff0c;并且想让更多的人知道你的网站&#xff0c;那么无非就是两种途径 一、自己进行宣传&#xff0c;或者花钱宣传 二、使用搜索引擎的自然流量 而如果搜索引擎都没有收录你的站点&#xff0c;别说是自然流量&#xff0c;就算是使用特定语句【sit…

文件上传服务器、文件展示等异步问题

问题&#xff1a; 文件上传模块&#xff1a;当文件已经上传完成&#xff0c;文件进度已经走完了&#xff0c;但是服务器响应还没有返回结果&#xff0c;出现了&#xff0c;获取不到上传后的文件路径&#xff0c;需要等待服务器返回结果后&#xff0c;才能获取文件路径并点击跳…

excel中怎么用乘法、加法来替代AND和OR函数

你可以使用乘法和加法来替代Excel中的AND和OR函数&#xff0c;虽然这样做可能会增加公式的复杂度&#xff0c;但在某些情况下是可行的。 1. 使用乘法替代AND函数&#xff1a;AND函数用于判断一系列条件是否同时成立&#xff0c;如果所有条件都为TRUE&#xff0c;则返回TRUE&…

IOMMU和SMMU详解

前言&#xff1a; IOMMU&#xff08;输入输出内存管理单元&#xff09;的原理与CPU中的MMU&#xff08;内存管理单元&#xff09;相似。它的作用是管理设备的内存访问请求&#xff0c;允许安全、高效地在设备和内存之间直接传输数据。IOMMU通常用于支持高速数据传输的设备&…

java生成数据库数据到excel当做下拉选择,copy就完事~

背景&#xff1a;由于需要下载模板&#xff0c;模板包含下拉选择框&#xff0c;但是下拉选择框不想手写&#xff0c;并且需要从数据库读取&#xff0c;由于直接设置excel会有单元格最大255个字符长度限制&#xff0c;所以用到以下部分代码。 思路&#xff1a;由于数据模板在sh…

怎么通过Javascript脚本实现远程控制一路开关

怎么通过Javascript脚本实现远程控制一路开关呢&#xff1f; 本文描述了使用Javascript脚本调用HTTP接口&#xff0c;实现控制一路开关。一路开关可控制一路照明、排风扇等电器。 可选用产品&#xff1a;可根据实际场景需求&#xff0c;选择对应的规格 序号设备名称1智能WiFi…

JSON Web Token 入门

JSON Web Token&#xff08;缩写 JWT&#xff09;是目前最流行的跨域认证解决方案&#xff0c;本文介绍它的原理和用法。 一、跨域认证的问题 互联网服务离不开用户认证。一般流程是下面这样。 1、用户向服务器发送用户名和密码。 2、服务器验证通过后&#xff0c;在当前对话&…

基于微信小程序的宠物寄养小程序,附源码

博主介绍&#xff1a;✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3…

Redis中的慢查询日志和监视器

慢查询 添加新日志 在每次执行命令的之前和之后&#xff0c;程序都会记录微妙格式的当前UNIX时间戳&#xff0c;这两个时间戳之间的差就是服务器执行命令所耗费的时长&#xff0c;服务器会将这个时长作为参数之一传给slowlogPushEntryIfNeeded函数&#xff0c;而slowlogPushE…

网络安全数字孪生:一种新颖的汽车软件解决方案

摘要 随着汽车行业转变为数据驱动的业务&#xff0c;软件在车辆的开发和维护中发挥了核心作用。随着软件数量的增加&#xff0c;相应的网络安全风险、责任和监管也随之增加&#xff0c;传统方法变得不再适用于这类任务。相应的结果是整车厂和供应商都在努力应对汽车软件日益增加…

System Dashboard for Mac:强大的系统监控与管理工具

System Dashboard for Mac是一款专为苹果电脑设计的系统监控与管理工具&#xff0c;以其直观易用的界面和全面的功能&#xff0c;深受用户喜爱。 System Dashboard for Mac v1.10.11激活版下载 这款软件能够实时监测系统的重要参数&#xff0c;包括CPU使用率、内存利用率、硬盘…

nginxtomcat笔记

nginx是一个轻量级高性能的http和反向代理web服务器&#xff0c;优点&#xff1a;占用内存少&#xff0c;并发能力强 实验主机&#xff1a;192.168.200.141 192.168.200.142 1.虚拟主机 1.1基于域名&#xff1a;一台服务器&#xff0c;一个端口&#xff0c;部署多个网站 在ng…

yolov5 的几个问题,讲的比较清楚

yolov5, 几个问题 【BCELoss】pytorch中的BCELoss理解 三个损失函数原理讲解 https://zhuanlan.zhihu.com/p/458597638 yolov5源码解析–输出 YOLOv5系列(十) 解析损失部分loss(详尽) 1、输入数据是 xywh, 针对原图的, 然后,变成 0-1, x/原图w, y/原图h, w/原图w, h/原图h,…

51-43 DragNUWA,集成文本、图像和轨迹实现视频生成细粒度控制

微软 NWA 系列主要功能及发布时间如下&#xff1a; 22年11月&#xff0c;微软亚洲研究院、北京大学联合提出同时覆盖语言、图像和视频的统一多模态生成模型女娲NWA&#xff0c;直接包揽草图转图像、图像补全、视频预测、文字指导修改视频等8项SOTA。23年3月&#xff0c;微软亚…

LLM学习之自然语言处理简单叙述

自然语言处理基础 自然语言处理&#xff1a;让计算机读懂人所写好的这些文本&#xff0c;能够像人一样进行交互。 自然语言处理的任务和应用 任务&#xff1a; 词性标注 part of speech tagging 动词&#xff0c;名词&#xff0c;形容词&#xff1f; 命名实体的识别 name…

【Java基础】23.接口

文章目录 一、接口的概念1.接口介绍2.接口与类相似点3.接口与类的区别4.接口特性5.抽象类和接口的区别 二、接口的声明三、接口的实现四、接口的继承五、接口的多继承六、标记接口 一、接口的概念 1.接口介绍 接口&#xff08;英文&#xff1a;Interface&#xff09;&#xf…

Springboot+Vue项目-基于Java+MySQL的海滨体育馆管理系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…