我有一些代码可以扩展在触摸屏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中-大概是在某种系统调用中。

最佳答案

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

09-17 20:32