SystemParametersInfoForDPI破坏了内存
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SystemParametersInfoForDPI破坏了内存相关的知识,希望对你有一定的参考价值。
我正在尝试为高DPI应用程序使用新的SystemParametersInfoForDPI函数。但是,当我返回调用者时,我的应用程序立即崩溃(致命错误)。
尝试执行00000000时异常是访问冲突。
我想要获取的参数是SPI_GETNONCLIENTMETRICS。
procedure TForm1.Button1Click(Sender: TObject);
var
SystemParametersInfoForDpi: function(uiAction, uiParam: UINT; pvParam: Pointer; fWinIni, DPI: UINT): BOOL; stdcall;
Metrics: TNonClientMetrics;
begin
SystemParametersInfoForDpi := GetProcAddress(GetModuleHandle(user32), 'SystemParametersInfoForDpi');
Win32Check(Assigned(SystemParametersInfoForDpi));
FillChar(Metrics, SizeOf(Metrics), 0);
Metrics.cbSize := SizeOf(Metrics);
if SystemParametersInfoForDPI(SPI_GETNONCLIENTMETRICS, Metrics.cbSize, @Metrics, 0, 120) then
Caption := 'OK'
else
Caption := 'FAIL';
end; // - crashes here; D2007; Win2016
怎么了?
答案
崩溃部分问题 - 它似乎是某些Windows版本中的错误。
有问题的代码不正确。
SystemParametersInfoForDPI仅在使用最新版本的结构时才能正常工作:它应该是UNICODE并且是为最新的OS版本定义的(例如,像iPaddedBorderWidth这样的字段 - 必须存在)。换句话说,它应该在所有可能的定义中具有最大大小。
这在文档中有概述,但有点奇怪:
- SystemParametersInfoForDpi的文档说:“此函数仅支持Unicode(LOGFONTW)字符串”
- SystemParametersInfo的文档说:“pvParam参数必须指向包含新参数的NONCLIENTMETRICS结构”
虽然这看起来像是从较旧的Windows版本(2000等)上的文档清理 - 但它确实告诉您绝对必须使用最新版本的结构。
最后,问题是当SystemParametersInfoForDpi看到不支持的缓冲区大小时,“缓冲区不足”或“无效参数”错误不会失败 - 正如人们所预料的那样。相反,它会愉快地,无声地执行缓冲区溢出。这仅在某些Windows版本上发生。
因此,如果在堆栈上分配结构 - 缓冲区溢出将擦除返回地址。当你的代码试图返回调用者时 - 它会崩溃。
以上是关于SystemParametersInfoForDPI破坏了内存的主要内容,如果未能解决你的问题,请参考以下文章