开源项目CuteSqlite开发笔记(八):Windows 64位/32位使用GetWindowLongPtr钩子函数

需求描述

在开发CuteSqlite的时候, 有一个功能需要实现,鼠标移到WTL::CStatic上后,发送消息通知CToolTipCtrl弹出。

遇到问题

WTL::CStatic控件没有相应 WM_MOUSEMOVE 消息,需要返回一个HTCLIENT消息来让窗口处理函数执行 WM_MOUSEMOVE消息,因为控件实例的鼠标消息,比如WM_MOUSEMOVE不会发送到父窗口上,只会发送到它本身,所以我们不能在父窗口的消息映射里添加处理CStatic的WM_MOUSEMOVE消息处理函数。针对这种情况,我们可以通过钩子的方式hook掉CStatic的原窗口处理内部函数。

如果是开发win 32位的应用程序,这个时候需要用到两个32位的勾子函数:GetWindowLong和SetWindowLong。

如果是开发win 64位的应用程序,这个时候需要用到两个64位的勾子函数:GetWindowLongPtr和SetWindowLongPtr。

处理64位的上述两个函数(GetWindowLongPtr和SetWindowLongPtr)兼容32位的应用程序,微软的MSDN解释如下:

GetWindowLongPtr检索有关指定窗口的信息。 该函数还会将指定偏移量的值检索到额外的窗口内存中。

注意 若要编写与 32 位和 64 位版本的 Windows 兼容的代码,请使用  GetWindowLongPtr。 为 32 位 Windows 编译时,  GetWindowLongPtr 定义为对  GetWindowLong 函数的调用。

编译错误

**特别注意的是:**如果在64位开发环境中,还使用32位的函数GetWindowLong和SetWindowLong,会发生编译错误,类似错误如下:

1>QParamElem.cpp
1>f:\project\wtlproject\cutesqlite\cutesqlite\ui\common\param\qparamelem.cpp(288): error C2065: “GWL_WNDPROC”: 未声明的标识符
1>f:\project\wtlproject\cutesqlite\cutesqlite\ui\common\param\qparamelem.cpp(291): error C2065: “GWL_USERDATA”: 未声明的标识符
1>f:\project\wtlproject\cutesqlite\cutesqlite\ui\common\param\qparamelem.cpp(292): error C2065: “GWL_WNDPROC”: 未声明的标识符

问题原因

原因是在64位开发环境中,头文件WinUser.h对宏GWL_WNDPROC,GWL_USERDATA等的声明改成了GWLP_WNDPROC,GWLP_USERDATA

解决方案

而解决的方法,64位开发环境使用函数GetWindowLongPtr和SetWindowLongPtr,替换32位的函数GetWindowLong和SetWindowLong。

实例解释

针对上述的需求:鼠标移到WTL::CStatic上后,发送消息通知CToolTipCtrl弹出。下面我们通过代码来解释这两个函数的使用。

头文件QParamElem.h声明的变量和钩子函数:

class QParamElem: public CWindowImpl<QParamElem> {
...CStatic desLabel; // 需要显示tooltip的文本框CToolTipCtrl tooltipCtrl; // tooltip提示控件std::pair<WNDPROC, HWND> procWndPair; // 钩子使用的变量,保存原来CStatic消息处理函数的地址和控件句柄HWNDWNDPROC m_pWndProc; // 原来CStatic消息处理函数的地址
...// 初始化和绑定tooltipCtrl提示控件void createAndBindToolTip();
...// CStatic消息替换函数static LRESULT funcLabelProcWnd(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam);
...
}

QParamElem.cpp实现的函数如下:

// 初始化和绑定tooltipCtrl
void QParamElem::createAndBindToolTip()
{if (tooltipCtrl.IsWindow() || !desLabel.IsWindow() ) {return;}tooltipCtrl.Create(desLabel.m_hWnd, NULL, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP);tooltipCtrl.AddTool(desLabel.m_hWnd, data.description.c_str());tooltipCtrl.Activate(TRUE);		// 拦截鼠标消息.m_pWndProc = (WNDPROC)::GetWindowLongPtr(desLabel.m_hWnd, GWLP_WNDPROC); // 获取原窗口处理函数procWndPair.first = m_pWndProc; // 这个是用户定义的类型1,不重要procWndPair.second = tooltipCtrl.m_hWnd; // 这个是用户定义的类型2,不重要::SetWindowLongPtr(desLabel.m_hWnd, GWLP_USERDATA, (LONG_PTR)&procWndPair); // 设置窗口的自定义数据,用于存储原处理函数和ToolTip句柄::SetWindowLongPtr(desLabel.m_hWnd, GWLP_WNDPROC, (LONG_PTR)QParamElem::funcLabelProcWnd); // 自定义一个窗口处理函数,对鼠标消息预先过滤.
}// 钩子替换的消息处理函数
LRESULT QParamElem::funcLabelProcWnd(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{auto pp = (std::pair<WNDPROC, HWND> *)::GetWindowLongPtr(hWnd, GWLP_USERDATA);WNDPROC funcOld = pp->first;auto tooltip_hwnd = pp->second;if(nMsg == WM_NCHITTEST){// 1.static 控件没有相应 WM_MOUSEMOVE 消息,需要返回一个HTCLIENT来让窗口处理函数执行 WM_MOUSEMOVE 消息.// 2.就是把 WM_NCHITTEST 消息转换为 WM_MOUSEMOVE消息.return HTCLIENT;} else if(nMsg == WM_MOUSEMOVE){// WM_MOUSEMOVE// WM_NCHITTEST// 1.发送一格WM_MOUSEMOVE消息给tooltip控件处理.这样tooltip才会在指定位置显示.MSG msg = { hWnd, nMsg, wParam, lParam };CToolTipCtrl tip;tip.Attach(tooltip_hwnd);tip.RelayEvent(&msg);}return CallWindowProc(funcOld, hWnd, nMsg, wParam, lParam);
}

OK, 这样子就可以实现了对 CStatic消息的转换,从而实现tooltip的显示。

完整的实例源码:

GitHub:   QParamElem.h    QParamElem.cpp

Gitee:      QParamElem.h    QParamElem.cpp

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

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

相关文章

【征服redis16】收官-redis缓存一致性问题解决方案

今天我们来写redis最后一篇&#xff1a;redis作为缓存时如何与数据库实现数据一致的问题。 最近看redis看得有点麻了&#xff0c;这篇就简单描述吧 目录 1.什么是缓存与数据库一致性问题 1.1 缓存一致性的概念 1.2 缓存不一致的场景 2.缓存不一致的解决思路 1.什么是缓存…

ITSS认证有用吗❓属于gj级证书吗❓

&#x1f525;ITSS由中国电子技术标准化研究院推出&#xff0c;包括“IT 服务工程师”和“IT 服务经理”两种认证。该系列认证符合GB/T 28827.1 的评估和ITSS服务资质升级要求。 &#x1f3af;ITSS是受到gj认可的&#xff0c;在全国范围内对IT服务管理人员从业资格为一的权威的…

docker运行redis,jdk,nginx

Redis 1.查询redis [rootlocalhost ~]# docker search redis NAME DESCRIPTION STARS OFFICIAL redis Redis is an open source key-value store that… 12620 …

BACnet网关 BL120BN实现楼宇自控设备统一接入系统,BACnet转Modbus

随着物联网技术的迅猛发展&#xff0c;人们深刻认识到在智能化生产和生活中&#xff0c;实时、可靠、安全的数据传输至关重要。在此背景下&#xff0c;高性能的物联网数据传输解决方案——协议转换网关应运而生&#xff0c;广泛应用于工业自动化和数字化工厂应用环境中。 钡铼…

OpenCV书签 #差值哈希算法的原理与相似图片搜索实验

1. 介绍 差值哈希算法&#xff08;Difference Hash Algorithm&#xff0c;简称dHash&#xff09; 是哈希算法的一种&#xff0c;主要可以用来做以图搜索/相似图片的搜索工作。 2. 原理 差值哈希算法通过计算相邻像素的差异来生成哈希&#xff0c;即通过缩小图像的每个像素与平…

uniapp中vue2项目导入高德地图

1、看官网新手入门链接导入原生高德地图&#xff1a; JS API 结合 Vue 使用-基础-进阶教程-地图 JS API 2.0|高德地图API (amap.com) 具体步骤&#xff1a; 第一步&#xff0c;安装插件 npm i amap/amap-jsapi-loader --save 第二步&#xff0c;在vue组件中写代码显示地图…

DEB方式安装elastic search7以及使用

参考&#xff1a;https://www.cnblogs.com/anech/p/15957607.html 1、安装elastic search7 #手动下载安装 wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.17.1-amd64.deb wget https://artifacts.elastic.co/downloads/elasticsearch/elastics…

【linux】 查看 Linux 重启历史记录(reboot)

了解 Linux 重启日志 /var/log 目录隐藏着 Linux 日志机制的核心信息&#xff0c;它是记录系统活动的宝贵仓库。然而&#xff0c;仅仅有日志还不够&#xff0c;真正的难题在于&#xff0c;如何从大量数据中提炼出与系统重启相关的关键信息。 在 /var/log 目录中&#xff0c;可…

【XR806开发板试用】系列之一 - Linux环境下Ubuntu完全开发流程

前言 为了让极术社区开发者体验搭载安谋科技STAR-MC1处理器的面向IoT领域的全志XR806开发板&#xff0c;极术社区联合全志在线开发者社区共同推出XR806开发板免费试用活动。 极术社区特准备了200块XR806开发板作为2022年社区新年活动&#xff0c;申请的人数有600多&#xff0c…

【江科大】STM32:外部中断(Extern Interrupt)

文章目录 EXTI&#xff08;Extern Interrupt&#xff09;外部中断EXIT的基本结构EXIT框图 旋转编码器简介库函数&#xff1a;对射式红外传感器计次&#xff1a;代码展示&#xff1a;旋转编码器计次注意&#xff1a; EXTI&#xff08;Extern Interrupt&#xff09;外部中断 功能…

Leetcode56. 合并区间

文章目录 题目原题链接思路代码 题目 以数组intervals表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 示例 1&#xff1a; …

OpenCV书签 #直方图算法的原理与相似图片搜索实验

1. 介绍 直方图算法&#xff08;Image Histogram Algorithm&#xff09; 通过统计图像中各个颜色值的分布情况来提供关于图像颜色特征的信息&#xff0c;它可以用来衡量两张图片在颜色分布上的相似度&#xff0c;进而可以用来进行图像相似度的比较&#xff0c;因此&#xff0c…

【Java】--网络编程:基于TCP协议的网络通信

【Java】–网络编程&#xff1a;基于TCP协议的网络通信 文章目录 【Java】--网络编程&#xff1a;基于TCP协议的网络通信一、TCP协议1.1 概念1.2 三次握手1.2.1 文字描述1.2.2 画图演示 1.3 四次挥手1.3.1 文字描述1.3.2 画图演示 二、基于TCP的Socket网络编程2.1 概念2.2 服务…

Elasticsearch:介绍 kNN query,这是进行 kNN 搜索的专家方法

作者&#xff1a;来自 Elastic Mayya Sharipova, Benjamin Trent 当前状况&#xff1a;kNN 搜索作为顶层部分 Elasticsearch 中的 kNN 搜索被组织为搜索请求的顶层&#xff08;top level&#xff09;部分。 我们这样设计是为了&#xff1a; 无论分片数量多少&#xff0c;它总…

为什么 HTTPS 协议能保障数据传输的安全性?

HTTP 协议 在谈论 HTTPS 协议之前&#xff0c;先来回顾一下 HTTP 协议的概念。 HTTP 协议介绍 HTTP 协议是一种基于文本的传输协议&#xff0c;它位于 OSI 网络模型中的应用层。 HTTP 协议是通过客户端和服务器的请求应答来进行通讯&#xff0c;目前协议由之前的 RFC 2616 拆…

JS进阶-函数进阶(一)

• 函数提升 函数提升与变量提升比较类似&#xff0c;是指函数在声明之前即可被调用。 总结&#xff1a; 1. 函数提升能够使函数的声明调用更灵活 2. 函数表达式不存在提升的现象 3. 函数提升出现在相同作用域当中 • 函数参数 1. 动态参数 arguments 是函数内部内置的伪…

Jmeter 配置元件

Jmeter 配置元件 CSV 数据集配置HTTP Cookie 管理器HTTP Header 信息头管理器增加多个用户案列 使用Jmeter发送请求的时候&#xff0c;需要配置元件&#xff0c;配置请求Header、Cookie、数据集合等。可以模拟多个在线用户登录&#xff0c;修改请求头数据。 CSV 数据集配置 C…

java遍历(for和forEach)

1.dade文件 package model;public class dade {private int id;private String name;public dade() {}public dade(int id, String name) {this.id id;this.name name;}public int getId() {return id;}public void setId(int id) {this.id id;}public String getName() {r…

书法AI全自动切字+识别算法2.0版发布,草书篆书行书楷书识别准确率超过90%,覆盖书法单字30万张

我们开发的业界识别最准覆盖作品最全的书法AI小程序上线了 书法AI全自动切字识别算法2.0版发布&#xff0c;草书篆书行书楷书识别准确率超过90%&#xff0c;准确率甩百度OCR一条街&#xff0c;覆盖书法单字30万张&#xff0c;遥遥领先同行 我们还可为客户提供书法AI全自动切字a…

C# wpf利用Clip属性实现截屏框

wpf截屏系列 第一章 使用GDI实现截屏 第二章 制作截屏框&#xff08;本章&#xff09; ______第一节 使用DockPanel制作截屏框 ______第二节 利用Clip属性实现截屏框(本节) 第三章 实现截屏框热键截屏 第四章 实现截屏框实时截屏 第五章 使用ffmpeg命令行实现录屏 文章目录 wp…