开源项目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.hqwc.cn/news/423469.html

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

相关文章

Databend 开源周报第 129 期

Databend 是一款现代云数仓。专为弹性和高效设计&#xff0c;为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务&#xff1a;https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend 。 支持标准流 标…

智慧工厂视频监控平台EasyCVR公网收流后内网设备无法播放是什么原因?

安防视频监控平台EasyCVR采用了开放式的网络结构&#xff0c;支持高清视频的接入和传输、分发&#xff0c;平台提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级联、磁盘阵列存储、视频集中存储、云存储等丰富的视频能力&#xff0c;此外&am…

如何在WordPress网站中添加多语言搜索(2种简单方法)

您想在WordPress网站中添加多语言搜索吗&#xff1f; 如果您有一个多语言 WordPress 网站&#xff0c;那么添加多语言搜索功能可以帮助用户通过使用自己的语言进行搜索来更快地找到信息。 在本文中&#xff0c;我们将向您展示如何在 WordPress 中轻松添加多语言搜索&#xff…

云风网(www.niech.cn)个人网站搭建(四)navicat 连接mongodb数据库

navicat安装破解 第一步&#xff0c;启动MongoDB服务 具体操作请移步&#xff1a;MongoDB安装配置教程 第二步&#xff1a;创建新连接&#xff0c;创建数据库 文件–新建连接–MongoDB 双击打开连接&#xff08;也可右键打开连接&#xff09;&#xff0c;右键新建数据库&…

《移动通信原理与应用》实验一——QPSK调制与解调实验(实验箱)

目录 一、实验目的 二、实验主要内容及原理 2.1、主要内容 2.2、基本原理 三、实验器材 3.1、移动通信原理实验箱&#xff1a; 3.2、实验框图及电路说明 四、实验步骤 五、实验过程原始记录(数据、图表、计算等) 六、实验结果及分析 1、结果分析&#xff1a; 2、思…

【Java IO】设计模式 (装饰者模式)

Java I/O 使用了装饰者模式来实现。 装饰者模式 请参考装饰者模式详解 装饰者(Decorator)和具体组件(ConcreteComponent)都继承自组件(Component)&#xff0c;具体组件的方法实现不需要依赖于其它对象&#xff0c;而装饰者组合了一个组件&#xff0c;这样它可以装饰其它装饰者…

如何通过系统命令排查账号安全?

如何通过系统命令排查账号安全 query user 查看当前登录账号 logoff id 注销用户id net user 查看用户 net user username 查看用户登录情况 lusrmgr.msc 查看隐藏账号 winR打开regedit注册表 找到计算机\HEKY_LOCAL_MACHINE\SAM\SAM\右键给与用户读写权限 刷新打开 HKEY…

工业搅拌机内流场仿真APP

工业用搅拌机主要是用于搅拌水泥、沙石、各类干粉砂浆等建筑材料。工业搅拌机内流场仿真APP展示的是针对双级折叶涡轮搅拌器&#xff0c;应用多重参考系模型模拟搅拌罐内旋转流动的过程及结果。用户可根据输入参数界面修改桨叶的尺寸、数量&#xff0c;流体物性以及运行工况等条…

黑马axios案例之地区查询

查询某个省内某个城市的所有地区 接口&#xff1a;http://hmajax.itheima.net/api/area 参数名: pname:省份名字或直辖市名字&#xff0c;比如北京、福建省、辽宁省… cname:城市名字&#xff0c;比如北京市、厦门市、大连市… <!DOCTYPE html> <html lang"en&q…

transdata笔记:手机数据处理

1 mobile_stay_duration 每个停留点白天和夜间的持续时间 transbigdata.mobile_stay_duration(staydata, col[stime, etime], start_hour8, end_hour20) 1.1 主要参数 staydata停留数据&#xff08;每一行是一条数据&#xff09;col 列名&#xff0c;顺序为[‘starttime’,…

仓储管理系统——软件工程报告(总体设计)③

总体设计 一、需求规定 软件工程仓库存储管理系统的需求规定是确保系统能够满足用户期望、提高工作效率、确保数据安全性和系统可维护性的基石。其涵盖了功能性、性能、数据管理、用户界面和系统可维护性等多个方面。通过严格的验收标准&#xff0c;可以确保系统在实际应用中…

4小时精通MyBatisPlus框架

目录 1.介绍 2.快速入门 2.1.环境准备 2.2.快速开始 2.2.1引入依赖 2.2.2.定义Mapper ​编辑 2.2.3.测试 2.3.常见注解 ​编辑 2.3.1.TableName 2.3.2.TableId 2.3.3.TableField 2.4.常见配置 3.核心功能 3.1.条件构造器 3.1.1.QueryWrapper 3.1.2.UpdateWra…