Why does SystemParametersInfo(SPI_SETNONCLIENTMETRICS, ...) hang in Windows 7 when it didn't before?
delphi, delphi-7, winapi
Solution
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.
Problem
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.