当_WIN32_WINNT大于0x500时,ToolTip窗口不显示问题排查

news2025/1/16 9:18:17

目录

1、前言

2、回退代码后,ToolTip窗口不显示了

3、使用历史版本比对法找到ToolTip窗口何时开始不显示的

4、为了给字体设置ClearType属性,_WIN32_WINNT宏的值从0x500修改成0x501

5、将_WIN32_WINNT宏值由从0x500修改成0x501,导致系统的ToolTip窗口组件出问题

6、解决办法


C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.htmlVC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585C++软件分析工具从入门到精通案例集锦(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795开源组件及数据库技术(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12458859.html网络编程与网络问题分享(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_2276111.html

1、前言

       最近测试同事发现,在Slider滑块控件显示百分比的ToolTip时有问题,在拖动滑块时ToolTip窗口没有显示实时的百分比,显示的还是之前的百分比,如下所示:

于是在排查这个问题的过程中遇到了一系列问题,在此做个总结,以供大家借鉴和参考。

2、回退代码后,ToolTip窗口不显示了

       这个问题是必现的。用老版本对比了一下,老版本中这个滑块控件的ToolTip显示是没有问题的。那说明这个问题肯定是修改代码,改出来的。于是,到svn上查看代码的修改记录,果然前段时间有人修改过相关代码。于是尝试将修改的代码还原,看看还没有问题,验证一下是不是这次修改引起的。

       将代码还原之后,重新编译执行,发现问题更严重了,ToolTip提示窗口直接不显示了。这就有点奇怪了,老版本中是没问题的,估计更早的时候还有人修改过代码,导致ToolTip提示窗口不显示了。


         在这里,给大家重点推荐一下我的几个热门畅销专栏:

专栏1:(该专栏订阅量已达到400个,有很强的实战参考价值,广受好评!专栏文章持续更新中,预计更新到200篇以上!)

C++软件调试与异常排查从入门到精通系列文章汇总icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931

本专栏根据近几年C++软件异常排查的项目实践,系统地总结了引发C++软件异常的常见原因以及排查C++软件异常的常用思路与方法,详细讲述了C++软件的调试方法与手段,以图文并茂的方式给出具体的实战问题分析实例,带领大家逐步掌握C++软件调试与异常排查的相关技术,适合基础进阶和想做技术提升的相关C++开发人员!

专栏中的文章均是通过项目实战总结出来的(通过项目实战积累了大量的异常排查素材和案例),有很强的实战参考价值!专栏文章还在持续更新中,预计文章篇数能更新到200篇以上!

专栏2: 

C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html

以多年的开发实战为基础,总结并讲解一些的C/C++基础与进阶内容,以图文并茂的方式对相关知识点进行详细地展开与阐述!专栏涉及了C/C++领域的多个方面的内容,同时给出C/C++及网络方面的常见笔试面试题,并详细讲述Visual Studio常用调试手段与技巧!

专栏3: 

开源组件及数据库技术icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12458859.html

以多年的开发实战为基础,分享一些开源组件及数据库技术!


3、使用历史版本比对法找到ToolTip窗口何时开始不显示的

       我们之前讲过可以使用历史版本比对法去排查一些问题,即安装不同时间点的版本,看看问题是从哪个时间点开始出现的。找到这个时间点后,大概就是前一天提交的代码或者底层发布过来的新dll库导致的。

       于是使用二分法安装不同时间点的版本,发现之前的版本长时间都有ToolTip不显示的问题,一直没有人反馈,所有界面的ToolTip都有问题。一直找到一年前的某个版本没有问题。于是继续使用二分法缩小范围,最终找到ToolTip窗口从那一天开始不显示的。

      于是到svn上查看前一天的代码修改记录,在directui库的Stdafx.h头文件中定义了_WIN32_WINNT宏,用该宏指定当前程序支持的最低操作系统版本,将该_WIN32_WINNT宏的值由0x500改成了0x501,事后证明正是这个修改导致的ToolTip窗口不显示的。

4、为了给字体设置ClearType属性,_WIN32_WINNT宏的值从0x500修改成0x501

       为什么要将_WIN32_WINNT宏的值从0x500修改成0x501呢?当时我们的软件在设置高DPI的电脑上运行,系统会对软件界面进行放大,放大后字体会比较模糊,为了将文字显示的更清晰一点,给绘制文字的字体设置ClearType属性,这样绘制出来的文字会更有棱角一点,会清晰一些。操作系统也支持设置ClearType选项,如下所示:

       如何给字体设置ClearType属性呢?我们在使用LOGFONT结构体创建字体时,直接给LOGFONT结构体中的lfQuality字段设置CLEARTYPE_QUALITY值即可,如下所示:

       跳转到CLEARTYPE_QUALITY宏的定义处:

可以看到只有当定义的NT版本达到0x501,才定义这个CLEARTYPE_QUALITY宏,但我们的directui工程中将_WIN32_WINNT宏值定义为0x500,于是为了支持CLEARTYPE_QUALITY宏,直接_WIN32_WINNT的值由0x500改成0x501。

5、将_WIN32_WINNT宏值由从0x500修改成0x501,导致系统的ToolTip窗口组件出问题

       开始出问题的时间点之前值只对这个_WIN32_WINNT宏值做了修改,难道是这个宏值对系统的ToolTip窗口也有影响?于是将_WIN32_WINNT宏的值重新改成0x500,将使用CLEARTYPE_QUALITY宏的代码注释掉,重新编译运行,ToolTip窗口就能正常显示了。果然与_WIN32_WINNT宏的值有关系!

        那将_WIN32_WINNT宏的值设置成为0x501,为啥会导致ToolTip窗口组件出问题呢?这个要看ToolTip窗口对应的结构体TOOLINFO,可以跳转到这个结构体的定义处,如下所示:

TOOLINFO最后一个字段是void *lpReserved,这个字段有点特殊,当NTDDI_VERSION大于NTDDI_WINXP时才会定义。

       我们可以go到这两个宏的定义处,NTDDI_WINXP宏的值为0x05010000:

而NTDDI_VERSION是直接与_WIN32_WINNT相关的:

       本例中我们将_WIN32_WINNT宏改成0x501,所以#if (NTDDI_VERSION >= NTDDI_WINXP)条件为真,所以当前场景下,TOOLINFO最后一个字段void *lpReserved是有效的!

       我们在定义TOOLINFO结构体对象时,给该结构体的cbSize字段赋值的是sizeof(TOOLINFO):

即当前TOOLINFO结构体的大小,包含void *lpReserved字段的。Windows系统默认加载的是comctl 5.82版本组件,这个版本中的ToolTip组件对应的TOOLINFO结构体中的size不包含void *lpReserved字段,而我们当前给cbSize字段设置的大小是包含void *lpReserved的,所以cbSize字段设大了,所以ToolTip组件内部出错了,导致ToolTip窗口显示不出来了。

       在Win32编程中使用ToolTip窗口组件时,先是调用CreateWindowEx创建一个TOOLTIPS_CLASS类窗口,然后给这个窗口发送TTM_ADDTOOL消息将定义的TOOLINFO结构体对象值(TOOLINFO结构体中存放的是给ToolTip窗口设置属性),如下所示:

应该是这一步设置进去后就出问题了。

6、解决办法

       在给TOOLINFO结构体对象的cbSize字段赋值时,不再赋sizeof(TOOLINFO),而是赋TTTOOLINFOA_V2_SIZE宏值:

::ZeroMemory(&m_ToolTip, sizeof(TOOLINFO));

// 赋值为TTTOOLINFOA_V2_SIZE,不用sizeof(TOOLINFO)
m_ToolTip.cbSize = TTTOOLINFOA_V2_SIZE; 

这个宏值就是将void *lpReserved字段去除后的TOOLINFO结构体大小。可以查看TTTOOLINFOA_V2_SIZE宏的定义看出来:

#define TTTOOLINFOA_V1_SIZE CCSIZEOF_STRUCT(TTTOOLINFOA, lpszText)
#define TTTOOLINFOW_V1_SIZE CCSIZEOF_STRUCT(TTTOOLINFOW, lpszText)

// 1、TTTOOLINFOW_V2_SIZE宏的定义
#define TTTOOLINFOA_V2_SIZE CCSIZEOF_STRUCT(TTTOOLINFOA, lParam)
#define TTTOOLINFOW_V2_SIZE CCSIZEOF_STRUCT(TTTOOLINFOW, lParam)
#define TTTOOLINFOA_V3_SIZE CCSIZEOF_STRUCT(TTTOOLINFOA, lpReserved)
#define TTTOOLINFOW_V3_SIZE CCSIZEOF_STRUCT(TTTOOLINFOW, lpReserved)


// 2、CCSIZEOF_STRUCT宏的定义
#ifndef CCSIZEOF_STRUCT
#define CCSIZEOF_STRUCT(structname, member)  (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member))
#endif


// 3、TTTOOLINFO宏的定义
typedef struct tagTOOLINFOW {
    UINT cbSize;
    UINT uFlags;
    HWND hwnd;
    UINT_PTR uId;
    RECT rect;
    HINSTANCE hinst;
    LPWSTR lpszText;
    LPARAM lParam;
#if (NTDDI_VERSION >= NTDDI_WINXP)
    void *lpReserved;
#endif
} TTTOOLINFOW, NEAR *PTOOLINFOW, *LPTTTOOLINFOW;

根据TTTOOLINFOA_V2_SIZE的定义,TTTOOLINFOA_V2_SIZE就是只计算到TOOLINFO倒数第二个参数lParam的长度,包含lParam成员长度,正好将最后一个字段void *lpReserved给跳过去了,这样ToolTip就能正常显示了。

       也可以使用#pragma comment预编译指令,将comctrl指定为使用6.0版本的:

#pragma comment(linker, "\"/manifestdependency:type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'\"")

对应范例如下:

#include <windows.h>
#include <commctrl.h>
#include <stdio.h>

#pragma comment(lib, "user32.lib")
#pragma comment(lib, "comctl32.Lib")
#pragma comment(lib, "gdi32.Lib")

#pragma comment(linker, "\"/manifestdependency:type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'\"")

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

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

相关文章

2024最新轻量应用服务器简介_轻量应用服务器购买指南

腾讯云轻量应用服务器开箱即用、运维简单的轻量级云服务器&#xff0c;CPU内存带宽配置高并且价格特别便宜&#xff0c;大带宽&#xff0c;但是限制月流量&#xff0c;轻量2核2G3M带宽61元一年、2核2G4M优惠价99元一年&#xff0c;540元三年、2核4G5M带宽165元一年&#xff0c;…

c++11语法特性

c11 1.c11发展简介 ​ 第一个比较正式的c标准是1998提出的c98标准。之后定了5年计划&#xff0c;每5年来一次大更新。在2003年C标准委员会曾经提交了一份技术勘误表(简称TC1)&#xff0c;使得C03这个名字已经取代了C98称为C11之前的最新C标准名称。不过由于C03(TC1)主要是对C…

java组合模式揭秘:如何构建可扩展的树形结构

组合模式&#xff08;Composite Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许将对象组合成树形结构以表示整体/部分层次结构。组合模式使得客户端可以统一对待单个对象和组合对象&#xff0c;从而使得客户端可以处理更复杂的结构。 组合模式的主要组成部分包括&…

Text-to-SQL 工具Vanna进阶|数据库对话机器人的多轮对话

跟数据库对话机器人对话,我可不止一个问题。 可能基于第一句问话,还有第二句、第三句问话。。。第N句对话。所以本文测试了多轮对话功能。 单轮对话的环境搭建参考博客 Text-to-SQL 工具Vanna + MySQL本地部署 | 数据库对话机器人 我的数据是这样 1. 基础配置 import vann…

Mysql锁与MVCC

文章目录 Mysql锁的类型锁使用MVCC快照读和当前读读视图【Read View】串行化的解决 exlpain字段解析ACID的原理日志引擎整合SpringBoot博客记录 Mysql锁的类型 MySQL中有哪些锁&#xff1a; 乐观锁&#xff08;Optimistic Locking&#xff09;&#xff1a;假设并发操作时不会发…

CodeReview 规范及实施

优质博文&#xff1a;IT-BLOG-CN 一、为什么需要CodeReview 随着业务压力增大&#xff0c;引发代码质量下降&#xff0c;代码质量的下降导致了开发效率的降低&#xff0c;维护成功高等问题&#xff0c;开发效率下降后又加重了业务压力&#xff0c;最终陷入了死亡三角的内耗之…

OCR-free相关论文梳理

⚠️注意&#xff1a;暂未写完&#xff0c;持续更新中 引言 通用文档理解&#xff0c;是OCR任务的终极目标。现阶段的OCR各种垂类任务都是通用文档理解任务的子集。这感觉就像我们一下子做不到通用文档理解&#xff0c;退而求其次&#xff0c;先做各种垂类任务。 现阶段&…

MongoDB从0到1:高效数据使用方法

MongoDB&#xff0c;作为一种流行的NoSQL数据库。从基础的文档存储到复杂的聚合查询&#xff0c;从索引优化到数据安全都有其独特之处。文末附MongoDB常用命令大全。 目录 1. 引言 MongoDB简介 MongoDB的优势和应用场景 2. 基础篇 安装和配置MongoDB MongoDB基本概念 使…

百度云加速即将下线

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 松松商城作为多年百度云加速代理商&#xff0c;上周接到通知&#xff1a;百度云加速产品计划于2024年4月30日下线&#xff0c;目前也无法做实名了。 同时&#xff0c;百度云加速也开始逐步迁移到百度云&#xff0…

构造函数、原型、instanceof运算符

通过构造函数创建对象 构造函数是学习面向对象的基础 任何函数都有原型对象 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.…

卡尔曼滤波器笔记——最详细

笔记来源— 卡尔曼滤波算法原理及代码实现&#xff01;https://www.bilibili.com/video/BV1WZ4y1F7VN/?spm_id_from333.337.search-card.all.click&vd_source8d55784dc9c7530bc9e3fa220380be56 简单介绍一下 现在我们就是不知道是距离多少&#xff0c;就需要用到这个卡尔…

C++进阶--mep和set的模拟实现

红黑树链接入口 底层容器 模拟实现set和map时常用的底层容器是红黑树。 红黑树是一种自平衡的搜索二叉树&#xff0c;通过对节点进行颜色标记来保持平衡。 在模拟实现set和map时&#xff0c;可以使用红黑树来按照元素的大小自动排序&#xff0c;并且保持插入和删除操作的高效…

缓冲区与C库函数的实现

目录 一、缓冲区 二、C库函数的实现 一、缓冲区 缓冲区本质就是一块内存&#xff0c;而缓冲区存在的意义本质是提高使用者(用户)的效率【把缓冲区理解成寄送包裹的菜鸟驿站】 缓冲区的刷新策略 1. 无缓冲(立即刷新) 2. 行缓冲(行刷新) 3. 全缓冲(缓冲区满了&#xff0c;再刷…

三. 操作系统 (6分) [理解|计算]

🌟三. 操作系统 (6分) [理解|计算] PV操作, 分页存储管理, 文件的索引, 位示图 考试重点 文章目录 🌟三. 操作系统 (6分) [理解|计算]==PV操作, 分页存储管理, 文件的索引, 位示图 考试重点==3.1 进程管理3.2 存储管理3.3 设备管理3.4 文件管理3.1 进程管理 进程的特征 进…

部署docker仓库harbor

1、下载包 1、包已上传有两个harbor.v2.6.0.tar与harbor.tar 2、harbor.tar解压后会生成harbor目录&#xff0c;将harbor.v2.6.0.tar移动到harbor目录下。 3、执行harbor目录下的install.sh 4、执行完后修改配置文件 2、修改配置文件 vim /root/harbor/make/ harbor.yml.tmpl …

【JAVA】CSS3:3D、过渡、动画、布局、伸缩盒

1 3D变换 1.1 3D空间与景深 /* 开启3D空间,父元素必须开启 */transform-style: preserve-3d;/* 设置景深&#xff08;你与z0平面的距离 */perspective:50px; 1.2 透视点位置 透视点位置&#xff1a;观察者位置 /* 100px越大&#xff0c;越感觉自己边向右走并看&#xff0c;…

亚信安慧AntDB:系统稳定性的守护

在国产化升级改造的过程中&#xff0c;AntDB不断地适应不同的需求&#xff0c;为用户提供个性化的解决方案。其致力于确保数据安全和系统稳定&#xff0c;预防数据泄露和系统崩溃等问题的发生。AntDB的团队不仅专注于技术的提升和创新&#xff0c;更关注用户的实际需求&#xf…

Docker 笔记(五)--链接

这篇笔记记录了Docker 的Link。 官方文档&#xff1a; Legacy container links - Communication across links 目录 参考Legacy container linksConnect using network port mappingConnect with the linking systemThe importance of naming Communication across linksEnviro…

《IAB视频广告标准:综合指南(2022)》之概述篇 - 我为什么要翻译介绍美国人工智能科技公司IAB 系列(2)

IAB平台&#xff0c;使命和功能 IAB成立于1996年&#xff0c;总部位于纽约市。 作为美国的人工智能科技巨头社会媒体和营销专业平台公司&#xff0c;互动广告局&#xff08;IAB- the Interactive Advertising Bureau&#xff09;自1996年成立以来&#xff0c;先后为700多家媒体…

漫步者、南卡、Oladance开放式耳机怎么样?巅峰测评谁是公认力作

​最近朋友们经常向我询问开放式耳机的选择问题&#xff0c;他们购买了开放式耳机后发现音质不佳&#xff0c;上耳佩戴舒适性几乎为零。市面上的开放式耳机琳琅满目&#xff0c;大家不知道该如何选择。漫步者、南卡、Oladance开放式耳机怎么样&#xff1f;我作为音乐爱好者已经…