【问题标题】:Why does SystemParametersInfo(SPI_SETNONCLIENTMETRICS, ...) hang in Windows 7 when it didn't before?为什么 SystemParametersInfo(SPI_SETNONCLIENTMETRICS, ...) 以前没有挂在 Windows 7 中?
【发布时间】:2012-06-20 15:52:21
【问题描述】:

我有一些代码可以扩展在触摸屏 PC 上运行的应用程序的系统滚动条的大小。这段代码是用Delphi 7编写的,已经运行了好几年了,但我发现在Windows 7上运行时似乎出现了问题。

代码如下:

procedure SetLargeScrollBars();
type
    // Extended NONCLIENTMETRICS structure not defined in Delphi 7's Windows.pas
    tagNONCLIENTMETRICSXA = packed record
        cbSize: UINT;
        iBorderWidth: Integer;
        iScrollWidth: Integer;
        iScrollHeight: Integer;
        iCaptionWidth: Integer;
        iCaptionHeight: Integer;
        lfCaptionFont: TLogFontA;
        iSmCaptionWidth: Integer;
        iSmCaptionHeight: Integer;
        lfSmCaptionFont: TLogFontA;
        iMenuWidth: Integer;
        iMenuHeight: Integer;
        lfMenuFont: TLogFontA;
        lfStatusFont: TLogFontA;
        lfMessageFont: TLogFontA;
        // This member not supported for Windows Server 2003 and Windows XP/2000
        iPaddedBorderWidth: Integer;
    end;
    NONCLIENTMETRICSX = tagNONCLIENTMETRICSXA;
var
    ncm: NONCLIENTMETRICSX;
    osvi: OSVERSIONINFO;
const
    LARGE_SCROLL_DIM = 48;
begin
    // Zero the NONCLIENTMETRICS type and fill in its size
    ZeroMemory(@ncm, Sizeof(ncm));
    ncm.cbSize := SizeOf(ncm);

    // This is necessary because SystemParametersInfo works differently for 
    // Windows Server 2008, Windows Vista and after.
    ZeroMemory(@osvi, SizeOf(osvi));
    osvi.dwOSVersionInfoSize := SizeOf(osvi);
    GetVersionEx(osvi);

    if (osvi.dwMajorVersion < 6) then
    begin
        ncm.cbSize := ncm.cbSize - SizeOf(ncm.iPaddedBorderWidth);
    end;

    // Seems to return true all the time.
    SystemParametersInfo(
        SPI_GETNONCLIENTMETRICS,
        Sizeof(ncm),
        @ncm,
        0);

    if (ncm.iScrollWidth <> LARGE_SCROLL_DIM) then
    begin
        // Save the scrollbar width and height for restoration when the application closes.
        m_ScrollWidth := ncm.iScrollWidth;
        m_ScrollHeight := ncm.iScrollHeight;

        ncm.iScrollWidth := LARGE_SCROLL_DIM;
        ncm.iScrollHeight := LARGE_SCROLL_DIM;

        // This call never returns...
        SystemParametersInfo(
            SPI_SETNONCLIENTMETRICS,
            Sizeof(ncm),
            @ncm,
            SPIF_SENDCHANGE);
    end;
end;

奇怪的是滚动条的大小实际上是设置的,所以看起来 SystemParametersInfo 正在做它应该做的事情,但在那之后似乎变得混乱了。

由于在函数中检查滚动条是否已展开,因此应用程序第二次及之后运行良好(除非通过将主题恢复为原始主题来重置滚动条)。

我想知道它是否与最后一个参数(fWinIni)有关,并尝试了所有各种值,包括零,但无济于事。

也许在更改设置后,Windows 7 与早期版本的操作系统有所不同?话虽如此,我还没有在 Vista 上尝试过,所以也许同样的事情也会发生在那里。这可能与为 Windows Vista、Windows Server 2008 和后续版本添加 iPaddedBorderWidth 有关 - 请参阅NONCLIENTMETRICS Structure

在 MSDN Problem Changing size of scrollbars using SystemParametersInfo(SPI_SETNONCLIENTMETRICS) 上有一个类似的问题,从 .NET 的角度来看同样的情况,但到目前为止还没有答案。


更多信息

我已使用 DebugDiag 对相关应用程序执行挂起分析,它显示以下堆栈跟踪:

功能
ntdll!KiFastSystemCallRet
uxtheme!Ordinal45+25d
uxtheme!BeginBufferedAnimation+25b
user32!SystemParametersInfoA+40
程序名+13024f
程序名+117c8d
程序名+6ae72
程序名+727dc
程序名+132645
kernel32!BaseThreadInitThunk+12
ntdll!RtlInitializeExceptionChain+ef
ntdll!RtlInitializeExceptionChain+c2

所以看起来好像挂起发生在 uxtheme!Ordinal45+25d - 大概是在某种系统调用中。

【问题讨论】:

  • 所以你的问题(这里没有)类似于 How to make a proper SystemParametersInfo call ?我不想相信SystemParametersInfo 会冻结应用程序,但也许我错了。
  • @TLama - 感谢您的回复 - 似乎我太忙于描述我忘了问这个问题的症状。我认为隐含的问题是为什么 SystemParametersInfo 以前没有挂在 Windows 7 中?
  • @MattWilling 嗨,马特,您找到问题的答案了吗?我也有同样的...
  • 尝试从您的 tagNONCLIENTMETRICSXA 声明中删除 packed
  • @TOndrej 感谢您的回复,我重新审视了这个问题并尝试了您的建议,但恐怕无济于事。

标签: delphi delphi-7 winapi


【解决方案1】:

也许问题是由另一个窗口引起的。您正在使用 SPIF_SENDCHANGE 参数调用 SystemParametersInfo。这会导致WM_SETTINGSCHANGE 消息与SendMessage 一起广播。当有窗口不响应此消息时,对SystemParametersInfo 的调用将挂起。请阅读旧新事物的this entry

【讨论】:

  • 感谢您的建议,但恐怕这不是答案,因为即使我传递 0 而不是 SPIF_SENDCHANGE,呼叫也会挂起。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-25
  • 1970-01-01
  • 2016-06-20
  • 2016-02-16
  • 1970-01-01
相关资源
最近更新 更多