Consider a window with WS_HSCROLL
and/or WS_VSCROLL
scroll bars. Normally, Windows automatically makes these scroll bars invisible if the scroll range it too small (nMax <= nPage
).
If the window is currently in this state where the scroll bars are invisible due to the scroll range being too small, and SetScrollInfo
with the SIF_DISABLENOSCROLL
flag is used to force the scroll bars to be visible, but disabled, then the call does not seem to have any effect.
If SIF_DISABLENOSCROLL
is set while the scroll bars are currently visible (due to the scroll range being big enough), then it works as expected.
Here is a simple toggle to demonstrate the issue:
SCROLLINFO ScrollInfo = {};
ScrollInfo.cbSize = sizeof(ScrollInfo);
if (WantScrollBarsVisible)
{
ScrollInfo.fMask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_RANGE;
ScrollInfo.nPage = 100;
ScrollInfo.nMax = 1; // Smaller value than nPage, so that the scroll bars should be disabled
// NOTE: If nMax is bigger than nPage, the scroll bars do become visible as expected.
SetScrollInfo(hWnd, SB_VERT, &ScrollInfo, true);
SetScrollInfo(hWnd, SB_HORZ, &ScrollInfo, true);
// Bugged!! Scroll bars are still invisible.
// They *happen* to become visible as soon as the window is being resized.
}
else
{
ScrollInfo.fMask = SIF_PAGE | SIF_RANGE;
// This makes the scroll bars effectively invisible (nMin == nMax == nPage == 0)
SetScrollInfo(hWnd, SB_VERT, &ScrollInfo, true);
SetScrollInfo(hWnd, SB_HORZ, &ScrollInfo, true);
}
Calling ShowScrollBar(..., true)
after SetScrollInfo
doesn't work either. Neither does InvalidateRect
or UpdateWindow
.
Interestingly, there is no WM_SIZE
message either, as you would normally expect after a SetScrollInfo
call because the client area shrinks if scroll bars appear (or disappear).
It appears to be a bug in Windows.
https://microsoft.public.vc.mfc.narkive.com/7gXZ62cm/sif-disablenoscroll
As it turns out, if a scroll bar is currently not visible for whatever reason(1), using SetScrollInfo
with SIF_DISABLENOSCROLL
will never make it visible.
The reason why it works initially is because upon window creation, the scroll bars happen to have some default values that will make it visible. Resizing the window also happens to make the scroll bars visible if they erroneously weren't. Probably part of the system updating a bunch of scroll parameters and then suddenly realising that the scroll bars should be visible after all.
The article above contains a workaround: Before using SetScrollInfo
with SIF_DISABLENOSCROLL
, first set some scroll parameters (with SetScrollInfo
and without SIF_DISABLENOSCROLL
) that definitely cause the scroll bar to be shown. You need to do that every time you think that the scroll bars might currently not be visible.
I found that rather awkward and came up with this:
SCROLLINFO ScrollInfo = {};
ScrollInfo.cbSize = sizeof(ScrollInfo);
if (WantScrollBarsVisible)
{
// ======================================================================
// Use ShowScrollBar to ensure that the scroll bars are visible *BEFORE*
// calling SetScrollInfo with SIF_DISABLENOSCROLL.
ShowScrollBar(hWnd, SB_VERT, true);
ShowScrollBar(hWnd, SB_HORZ, true);
// ======================================================================
ScrollInfo.fMask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_RANGE;
ScrollInfo.nPage = 100;
ScrollInfo.nMax = 1; // Smaller value than nPage, so that the scroll bars should be disabled
SetScrollInfo(hWnd, SB_VERT, &ScrollInfo, true);
SetScrollInfo(hWnd, SB_HORZ, &ScrollInfo, true);
}
else
{
ScrollInfo.fMask = SIF_PAGE | SIF_RANGE;
// This makes the scroll bars effectively invisible (nMin == nMax == nPage == 0)
SetScrollInfo(hWnd, SB_VERT, &ScrollInfo, true);
SetScrollInfo(hWnd, SB_HORZ, &ScrollInfo, true);
}
Normally, ShowScrollBar
is not very useful because its effects are volatile - they get overridden whenever the scroll parameters change using SetScrollInfo
. However, in this case, it's just enough to make sure the scroll bars are visible before SIF_DISABLENOSCROLL
comes around.
If it was possible to directly interact with the scroll bars, there might even be a nicer way (like telling them to update themselves right now).
(1) The possible reasons I have tested include: Window styles WS_VSCROLL
/WS_HSCROLL
being removed from the window after creation; previously nMax-nMin<=nPage
(scroll range too small) without SIF_DISABLENOSCROLL
; ShowScrollBar(..., false)
.