SystemParametersInfoForDPI损坏内存

时间:2018-07-23 15:09:30

标签: windows delphi debugging highdpi

我正在尝试对High 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

怎么了?

1 个答案:

答案 0 :(得分:1)

崩溃的问题之一-在某些Windows版本中似乎是一个错误。

有问题的代码不正确。

仅当使用最新版本的结构时,SystemParametersInfoForDPI才能正常工作:它应为UNICODE,并应针对最新的OS版本进行定义(例如,必须显示iPaddedBorderWidth等字段)。换句话说,在所有可能的定义中,它都应具有最大大小。

这在文档中有概述,但有点怪异:

  • SystemParametersInfoForDpi的文档说:“此功能仅支持Unicode(LOGFONTW)字符串”
  • SystemParametersInfo文档说:“ pvParam参数必须指向包含新参数的NONCLIENTMETRICS结构”

这看上去似乎可以从旧版Windows(2000等)上的文档中清除-但是它确实告诉您绝对必须使用最新版本的结构。

最后,该错误是SystemParametersInfoForDpi看到不支持的缓冲区大小时不会因“缓冲区不足”或“参数无效”而失败-就像人们所期望的那样。取而代之的是,它将快乐而无声地执行缓冲区溢出。仅在某些Windows版本上会发生这种情况。

因此,如果在堆栈上分配了结构-缓冲区溢出将擦除返回地址。当您的代码尝试返回给调用者时,它将崩溃。