Perl Win32::API调用GetWindowPlacement报缓冲区溢出错误
问题原因
核心错误是自定义的WINDOWPLACEMENT结构体多定义了Windows平台不存在的rcDevice字段:
rcDevice是Win32 API为旧Mac平台兼容保留的专属成员,Windows系统下的WINDOWPLACEMENT结构不包含该字段- 多余字段导致计算出的结构体大小为60字节,不符合Windows系统要求的44字节固定大小,触发Win32::API层的缓冲区溢出校验,同时
GetWindowPlacement接口本身也会因传入的length字段不合法直接调用失败
修复方案
- 删除
WINDOWPLACEMENT结构体定义中的RECT rcDevice;行,使用Windows平台标准的结构定义 - 确认结构体初始化时
length字段值为44(删除多余字段后Win32::API::Struct::sizeof会自动算出正确值,若计算异常可直接手动赋值44)
修正后可运行代码
#!/usr/bin/perl use strict; use warnings; use Win32::API; my $wpl; # WINDOWPLACEMENT structure my $hwnd; my $rv; Win32::API->Import("user32", "FindWindow", "PP", "N"); Win32::API->Import("user32", "GetWindowPlacement", "NP", "I"); Win32::API::Struct->typedef( 'POINT', qw( LONG x; LONG y; )); Win32::API::Struct->typedef( 'RECT', qw( LONG left; LONG top; LONG right; LONG bottom; )); # 已删除Mac专属的rcDevice字段 Win32::API::Struct->typedef( 'WINDOWPLACEMENT', qw( UINT length; UINT flags; UINT showCmd; POINT ptMinPosition; POINT ptMaxPosition; RECT rcNormalPosition; )); $hwnd = FindWindow('SciCalc', 0); print("window handle: $hwnd\n"); $wpl = Win32::API::Struct->new( 'WINDOWPLACEMENT' ); $wpl->{length} = Win32::API::Struct::sizeof($wpl); # 若上述sizeof计算结果不是44,可直接替换为下行手动赋值 # $wpl->{length} = 44; print("pointer: $wpl\n"); print("length: $wpl->{length}\n"); $rv = GetWindowPlacement($hwnd, $wpl); print("return value: $rv\n"); # 调用成功后可正常读取结构成员,例: # print("showCmd: $wpl->{showCmd}\n"); # print("window rect: left=$wpl->{rcNormalPosition}{left}, top=$wpl->{rcNormalPosition}{top}, right=$wpl->{rcNormalPosition}{right}, bottom=$wpl->{rcNormalPosition}{bottom}\n"); exit(0); __END__
验证说明
修正后代码运行不会再报缓冲区溢出错误,GetWindowPlacement返回值为1(调用成功),可正常读取窗口位置、显示状态等信息,与AutoIt3返回结果一致。
注意:若使用64位Perl环境仍出现调用异常,可将
GetWindowPlacement导入时的参数列表调整为"QP"(第一个参数Q对应64位句柄类型),32位环境下保持"NP"即可。
内容的提问来源于stack exchange,提问作者user19255186
相关产品推荐
相关产品推荐

