本文主要是介绍在64位程序中调用SetWindowLong指定窗口处理过程失效问题排查(附C++编译器数据模型),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/125529931C/C++基础与进阶(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_11931267.htmlVC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/124272585C++软件分析工具从入门到精通案例集锦(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/article/details/131405795开源组件及数据库技术(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_12458859.html网络编程与网络问题分享(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_2276111.html
将32位程序升级到64位后,遇到了使用API函数SetWindowLong设置窗口窗口处理过程WindowProc失效的问题,需要替换成SetWindowLongPtr,能同时兼容32位和64程序。下面讲一下这个小问题的分析解决过程。
有如下一段代码:
// 创建消息接收窗口
m_hRecvMsgWnd = ::CreateWindowEx( 0, _T("Static"), _T("MsgReciever"), WS_DISABLED, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, 0, 0 );if (m_hRecvMsgWnd != NULL )
{m_wndprocOld = reinterpret_cast<WNDPROC>( GetWindowLong(m_hRecvMsgWnd, GWL_WNDPROC) );SetWindowLong(m_hRecvMsgWnd, GWL_WNDPROC, reinterpret_cast<int>(WndProc) );
}
else
{m_wndprocOld = NULL;
}
代码中创建了一个掩藏的窗口,该窗口用于接收其他代码抛过来的消息。因为业务需要,我们需要在代码中拦截该窗口的消息,于是调用API函数SetWindowLong重新给窗口指定新的窗口消息处理函数,然后我们在新的窗口处理函数中拦截窗口消息,如下所示:
LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{// 拦截发给窗口的消息if (uMsg == CMainLogic::SYS_INNERMSG_COMING ){// ...}return 0;
}
上述代码在x64下编译时会报错:
即找不到GWL_WNDPROC宏的定义,这个就奇怪了,明明在Win32下编译是没问题的,
于是go到GWL_WNDPROC宏的定义处:
GWL_WNDPROC宏的定义在x64下被取消了,定义了新的宏GWLP_WNDPROC(多了一个P),其实GWLP_WNDPROC和GWL_WNDPROC宏的值是一模一样的,所以不管是32位还是64位,直接使用GWLP_WNDPROC就好了!于是将代码修改成:
m_wndprocOld = reinterpret_cast<WNDPROC>( GetWindowLongPtr(m_hRecvMsgWnd, GWLP_WNDPROC) );
这段代码在Win32下编译运行是正常的,但拿到x64下编译后运行就出问题了,好像失效了,在新的窗口消息处理函数中拦截不到消息。
于是以“SetWindowLong msdn”为关键字去搜索,找到MSDN上对API函数SetWindowLong的说明:
msdn上明确说了,为了兼容32位和64位程序,应使用SetWindowLongPtr函数。言下之意,SetWindowLong在x64下是有问题的,应该使用SetWindowLongPtr。
于是直接将上述代码中的GetWindowLong替换成GetWindowLongPtr、将SetWindowLong替换成SetWindowLongPtr。同时,在调用SetWindowLongPtr时,将第三个参数换成LONG_PTR。为什么要换成LONG_PTR呢?可以go到SetWindowLongPtr的定义处查看该函数的参数类型,如下所示:
也可以go到LONG_PTR定义处:
在64位下,LONG_PTR被定义为64位整型__int64,这和64位环境是一致的。
在这里,给大家重点推荐一下我的几个热门畅销专栏,欢迎订阅:(博客主页还有其他专栏,可以去查看)
专栏1:(该精品技术专栏的订阅量已达到430多个,专栏中包含大量项目实战分析案例,有很强的实战参考价值,广受好评!专栏文章持续更新中,预计更新到200篇以上!欢迎订阅!)
C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/125529931
本专栏根据多年C++软件异常排查的项目实践,系统地总结了引发C++软件异常的常见原因以及排查C++软件异常的常用思路与方法,详细讲述了C++软件的调试方法与手段,以图文并茂的方式给出具体的项目问题实战分析实例(很有实战参考价值),带领大家逐步掌握C++软件调试与异常排查的相关技术,适合基础进阶和想做技术提升的相关C++开发人员!
考察一个开发人员的水平,一是看其编码及设计能力,二是要看其软件调试能力!所以软件调试能力(排查软件异常的能力)很重要,必须重视起来!能解决一般人解决不了的问题,既能提升个人能力及价值,也能体现对团队及公司的贡献!
专栏中的文章都是通过项目实战总结出来的,包含大量项目问题实战分析案例,有很强的实战参考价值!专栏文章还在持续更新中,预计文章篇数能更新到200篇以上!
专栏2:
C/C++基础与进阶(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_11931267.html
以多年的开发实战经验为基础,总结并讲解一些的C/C++基础与进阶内容,以图文并茂的方式对C++相关知识点进行详细地展开与剖析!专栏涉及了C/C++开发领域多个方面的内容,同时给出C/C++及网络方面的常见笔试面试题,并详细讲述Visual Studio常用调试手段与技巧!
专栏3:
VC++常用功能开发汇总https://blog.csdn.net/chenlycly/article/details/124272585
专栏将10多年C++开发实践中常用的功能,以高质量的代码展现出来,并对相关功能的实现细节进行了详细的说明。这些常用的代码,其质量与稳定性是有保证的,可以直接拿过去使用,可以有效地解决C++软件开发过程中遇到的问题。
下面给出常见的int、long和Pointer指针在常见的编译器模型下的长度说明:
大家可以参考一下。
这篇关于在64位程序中调用SetWindowLong指定窗口处理过程失效问题排查(附C++编译器数据模型)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!