Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does SystemParametersInfo(SPI_SETNONCLIENTMETRICS, ...) hang in Windows 7 when it didn't before?

I have some code that expands the size of the system scrollbars for an application running on a touchscreen PC. This code was written in Delphi 7 and has been running satisfactorily for several years, but I have found that there seems to be a problem when running it on Windows 7.

The code looks like this:

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;

The curious thing is that the scrollbar sizes are actually set, so it seems that SystemParametersInfo is doing what it is supposed to do, but then appears to get confused after that point.

Since there is a check in the function to see if the scrollbars are already expanded, the application runs fine the second time and thereafter (unless the scrollbars are reset by reverting the theme back to the original).

I was wondering if it could be something to do with the last parameter (fWinIni) and have tried all the various values for that including zero, but to no avail.

Perhaps Windows 7 does something different to earlier flavours of the OS after the settings have been changed? Having said that, I haven't tried it on Vista, so maybe the same thing happens there. It could be related to the addition of iPaddedBorderWidth for Windows Vista, Windows Server 2008 and subsequent versions - see NONCLIENTMETRICS Structure

There is a similar question on MSDN Problem Changing size of scrollbars using SystemParametersInfo(SPI_SETNONCLIENTMETRICS) regarding the same situation from a .NET perspective but no answer to it so far.


Further information

I have used DebugDiag to perform a hang analysis on the application concerned, and it shows the following stack trace:

Function
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

So it looks as if the hang is occurring in uxtheme!Ordinal45+25d - presumably in a system call of some kind.

like image 507
Matt Willing Avatar asked Jan 17 '23 08:01

Matt Willing


1 Answers

Perhaps the problem is caused by another window. You are calling SystemParametersInfo with the SPIF_SENDCHANGE-parameter. This causes a WM_SETTINGSCHANGE message to be broadcasted with SendMessage. When there is a window that does not respond to this message, the call to SystemParametersInfo will hang. Please read this entry of The Old New Thing.

like image 67
R. Beiboer Avatar answered Feb 10 '23 11:02

R. Beiboer