为什么SystemParametersInfo(SPI_SETNONCLIENTMETRICS,...)在Windows 7之前没有挂起?

Mat*_*ing 4 delphi winapi delphi-7

我有一些代码可以扩展触摸屏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;
Run Code Online (Sandbox Code Playgroud)

奇怪的是滚动条大小实际上是设置的,所以看起来SystemParametersInfo正在做它应该做的事情,但是在那之后似乎感到困惑.

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

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

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

在MSDN 问题上有一个类似的问题使用SystemParametersInfo(SPI_SETNONCLIENTMETRICS)从.NET角度改变滚动条的大小但是到目前为止还没有答案.


更多的信息

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

函数
ntdll!KiFastSystemCallRet uxtheme
!Ordinal45 + 25d uxtheme
!BeginBufferedAnimation + 25b
user32!SystemParametersInfoA + 40
programName
+ 13024f programName
+ 117c8d programName
+ 6ae72 programName
+ 727dc programName + 132645
kernel32!BaseThreadInitThunk + 12
ntdll!RtlInitializeExceptionChain + ef
ntdll!RtlInitializeExceptionChain + c2

因此看起来好像是在uxtheme中发生挂起!Ordinal45 + 25d - 可能是在某种系统调用中.

R. *_*oer 9

也许问题是由另一个窗口引起的.您正在SystemParametersInfo使用SPIF_SENDCHANGE-parameter 进行调用.这会导致WM_SETTINGSCHANGE消息被广播SendMessage.如果有一个窗口没有响应此消息,则呼叫SystemParametersInfo将挂起.请阅读The Old New Thing的这篇文章.

  • 感谢您的建议,但恐怕不是答案,因为即使我传递0而不是SPIF_SENDCHANGE,电话也会挂断。 (2认同)