在64位程序中调用SetWindowLong指定窗口处理过程失效问题排查(附C++编译器数据模型)

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        将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宏的值是一样的(都是-4),所以不管是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修改后的代码如下所示:

// 创建消息接收窗口
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>( GetWindowLongPtr(m_hRecvMsgWnd, GWLP_WNDPROC) );
    SetWindowLongPtr(m_hRecvMsgWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WndProc) );
} 
else
{
    m_wndprocOld = NULL;
}

       为什么参数要换成LONG_PTR呢?可以go到SetWindowLongPtr的定义处查看该函数的参数类型,如下所示:

也可以go到LONG_PTR定义处:

在64位下,LONG_PTR被定义为64位整型__int64,这和64位环境是一致的。


       在这里,给大家重点推荐一下我的几个热门畅销专栏,欢迎订阅:(博客主页还有其他专栏,可以去查看)

专栏1:(该精品技术专栏的订阅量已达到430多个,专栏中包含大量项目实战分析案例,有很强的实战参考价值,广受好评!专栏文章持续更新中,预计更新到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/C++及网络方面的常见笔试面试题,并详细讲述Visual Studio常用调试手段与技巧!

专栏3: 

VC++常用功能开发汇总icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585

专栏将10多年C++开发实践中常用的功能,以高质量的代码展现出来,并对相关功能的实现细节进行了详细的说明。这些常用的代码,其质量与稳定性是有保证的,可以直接拿过去使用,可以有效地解决C++软件开发过程中遇到的问题。


       下面给出常见的int、long和Pointer指针在常见的C++编译器数据模型下的长度说明

大家可以参考一下。

这些编译器数据模型大家可能没关注过,同一类型在不同的编译器数据模型下占的字节长度可能是不同的,可以适当了解一下!特别是从32位转到64位编程时需要关注一下!

  • 129
    点赞
  • 89
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 86
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 86
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dvlinker

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值