窗口销毁消息 WM_DESTROY 的正确处理方式

news/2025/3/21 0:36:59/

上次,我提到了可能导致正常的消息循环被破坏的怪异之处。

有一位读者 Adrian 指出,WM_GETMINMAXINFO 消息在顶级窗口 WM_NCCREATE 之前到达。这确实很不幸,但(无论是否错误)十多年来一直如此,现在修改它会引入严重的兼容性风险。

但这不是我想到的怪异之处。

前段时间,我正在帮助调试一个使用 ListView 控件的程序的问题,该问题可追溯到 ListView 控件子类化的程序,并通过复杂的C++对象链,最终尝试销毁 ListView 控件,而它已经在销毁过程中。

让我们以新的例子程序为例,以一种更加明显的方式来说明我所提到的问题。

我在代码中添加了一些调试跟踪,以便更轻松地查看正在发生的事情。运行程序,然后关闭它,并观察会发生什么。

哎呀!发生了什么事?

当您单击窗口右上角的关闭按钮时,这将启动窗口销毁过程。正如预期的那样,窗口收到了一条 WM_DESTROY 消息,但程序通过尝试再次销毁窗口来响应此消息。请注意,IsWindow 报告此时该窗口仍然存在。这是真的:窗口仍然存在,尽管它恰好正在被破坏的过程中。在原始场景中,破坏窗口的代码类似于下面的代码:

if (IsWindow(hwndToDestroy))
{
DestroyWindow(hwndToDestroy);
}

无论如何,对 DestroyWindow 的递归调用导致一个新的窗口销毁周期开始,嵌套在第一个窗口内。这将生成一条新的 WM_DESTROY 消息,后跟一条 WM_NCDESTROY 消息。(请注意,此窗口现在已收到两条 WM_DESTROY 消息!然后,我们的代码对DestroyWindow 进行了另一个递归调用,从而开始了第三个窗口销毁周期。窗口获取其第三条 WM_DESTROY 消息,然后是第二条 WM_NCDESTROY 消息,此时返回对 DestroyWindow 的第二次递归调用。此时,窗口不再存在:DestroyWindow 已销毁窗口。

这就是程序崩溃的原因。基类通过销毁与窗口关联的实例变量来处理 WM_NCDESTROY 消息。因此,当最里面的 DestroyWindow 返回时,实例变量已被丢弃。然后,使用基类的 WM_NCDESTROY 处理程序恢复执行,该处理程序尝试访问实例变量并获取堆垃圾,然后使释放已释放的内存变得更糟,从而损坏堆。正是在这里,我们崩溃了,试图在已经破坏的对象上调用虚拟析构函数。

我有意选择使用新的例子程序(使用C++对象)而不是经典的例子程序(使用全局变量)来强调这样一个事实,即在递归 DestroyWindow 调用之后,所有实例变量都消失了,你正在已经释放的内存上运行代码,这很危险。

故事的寓意:了解你的窗口的生命周期,不要破坏一个你知道已经处于破坏过程中的窗口。

总结

在非托管平台上编写代码如履薄冰,你需要时时谨慎,因为,不再有人能暗中保护你了。

最后

Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。
本文来自:《When the normal window destruction messages are thrown for a loop》


http://www.ppmy.cn/news/3051.html

相关文章

第2章 线性表

上篇:数据结构 2.0 介绍2.1 顺序表2.1.1 静态分配2.1.2 动态分配2.1.3 顺序表的基本操作2.2 单链表2.2.1 单链表的存储方式2.2.2 单链表的基本操作2.3 双向链表2.3.1 双向链表的存储方式2.3.2 双向链表的基本操作2.4 循环链表2.5 线性表的应用2.5.1 合并有序顺序表2.5.2 合并有…

史上最全网络安全面试题合集

php爆绝对路径方法? 单引号引起数据库报错访问错误参数或错误路径探针类文件如phpinfo扫描开发未删除的测试文件google hackingphpmyadmin报路径:/phpmyadmin/libraries/lect_lang.lib.php利用漏洞读取配置文件找路径恶意使用网站功能,如本地…

Python爬虫实战,requests+openpyxl模块,爬取小说数据并保存txt文档(附源码)

前言 今天给大家介绍的是Python爬取小说数据并保存txt文档,在这里给需要的小伙伴们代码,并且给出一点小心得。 首先是爬取之前应该尽可能伪装成浏览器而不被识别出来是爬虫,基本的是加请求头,但是这样的纯文本数据爬取的人会很多…

Nginx配置虚拟域名

1.nginx.conf配置 server {listen 80;server_name www.gwzhjc.com;#charset koi8-r;#access_log logs/host.access.log main;location / {root html/web3;index index.html index.htm;}location /prod-api/ {proxy_set_header Host $http_host;proxy_set_header X-…

数学基础从高一开始6、全称量词与存在量词

数学基础从高一开始6、全称量词与存在量词 目录 数学基础从高一开始6、全称量词与存在量词 全称量词 存在量词 1.判断命题的真假 2.判断命题的真假 阅读下列两组命题,语言上有什么特点? A组: (1)对任意一个x∈Z,2x1是整数; (2)每一个素…

qq录屏怎么弄?图文教程,教你如何使用qq录屏

当你使用电脑时,你会使用什么方法来满足视频录制的需要?事实上,我们常用的通信软件qq就有录屏功能,很多小伙伴可能不知道。qq录屏怎么弄?今天小编给大家带来的qq录屏使用的详细技巧,图文教程,轻…

【Linux】Linux软件包管理器yum

希望你今天有一个好心情 文章目录一、(客户端&&服务器) (软件包&&软件包管理器yum) (利益链&&逻辑链)1.客户端&&服务器2.软件包&&软件包管理器3.一条利益链一条逻辑链二、Linux下包管理器yum的使用(root身份或sudo提权进行搜索list…

如何安然度过行业大萧条,听听10年测试老鸟的分析

国内的互联网行业发展较快,所以造成了技术研发类员工工作强度比较大,同时技术的快速更新又需要员工不断的学习新的技术。因此淘汰率也比较高,超过35岁的基层研发类员工,往往因为家庭原因、身体原因,比较难以跟得上工作…