https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a9b77d89fb660802f9e8e…
commit a9b77d89fb660802f9e8ee4497e56f5d576ecb42
Author: Marek Benc <benc.marek.elektro98(a)proton.me>
AuthorDate: Tue Aug 27 20:25:02 2024 +0200
Commit: GitHub <noreply(a)github.com>
CommitDate: Tue Aug 27 13:25:02 2024 -0500
[USER32_APITEST] Add scrollbar showing/hiding testcase (#7254)
Checks CORE-19669, making sure that CS_HREDRAW and CS_VREDRAW
are respected when the client area changes due to the scrollbar
disappearing or re-appearing.
ROSTESTS-397
Co-authored-by: Stanislav Motylkov <x86corez(a)gmail.com>
---
modules/rostests/apitests/user32/CMakeLists.txt | 1 +
modules/rostests/apitests/user32/ScrollBarRedraw.c | 727 +++++++++++++++++++++
modules/rostests/apitests/user32/testlist.c | 2 +
3 files changed, 730 insertions(+)
diff --git a/modules/rostests/apitests/user32/CMakeLists.txt
b/modules/rostests/apitests/user32/CMakeLists.txt
index 3e696def280..1a3c829dcea 100644
--- a/modules/rostests/apitests/user32/CMakeLists.txt
+++ b/modules/rostests/apitests/user32/CMakeLists.txt
@@ -41,6 +41,7 @@ list(APPEND SOURCE
RedrawWindow.c
RegisterClassEx.c
RegisterHotKey.c
+ ScrollBarRedraw.c
ScrollBarWndExtra.c
ScrollDC.c
ScrollWindowEx.c
diff --git a/modules/rostests/apitests/user32/ScrollBarRedraw.c
b/modules/rostests/apitests/user32/ScrollBarRedraw.c
new file mode 100644
index 00000000000..6cecaf50dbb
--- /dev/null
+++ b/modules/rostests/apitests/user32/ScrollBarRedraw.c
@@ -0,0 +1,727 @@
+/*
+ * PROJECT: ReactOS API tests
+ * LICENSE: MIT (
https://spdx.org/licenses/MIT)
+ * PURPOSE: Tests window redrawing when scrollbars appear or disappear
+ * COPYRIGHT: Copyright 2024 Marek Benc <benc.marek.elektro98(a)proton.me>
+ */
+
+#include "precomp.h"
+
+#define TEST_CLASS_NAME L"ScrollBarRedraw"
+#define TEST_WINDOW_TITLE L"ScrollBarRedraw"
+
+static LRESULT CALLBACK WindowProc(HWND Window, UINT Message, WPARAM wParam, LPARAM
lParam);
+
+#define TEST_COLOR_COUNT 16
+
+/* Standard Windows 16-Color VGA Color palette. */
+static COLORREF Colors[] =
+{
+ RGB(0x00, 0x00, 0x00), /* Black */
+ RGB(0x00, 0x00, 0x80), /* Dark Blue */
+ RGB(0x00, 0x80, 0x00), /* Dark Green */
+ RGB(0x00, 0x80, 0x80), /* Dark Cyan */
+ RGB(0x80, 0x00, 0x00), /* Dark Red */
+ RGB(0x80, 0x00, 0x80), /* Dark Magenta */
+ RGB(0x80, 0x80, 0x00), /* Dark Yellow */
+ RGB(0xC0, 0xC0, 0xC0), /* Light Gray */
+ RGB(0x80, 0x80, 0x80), /* Dark Gray */
+ RGB(0x00, 0x00, 0xFF), /* Blue */
+ RGB(0x00, 0xFF, 0x00), /* Green */
+ RGB(0x00, 0xFF, 0xFF), /* Cyan */
+ RGB(0xFF, 0x00, 0x00), /* Red */
+ RGB(0xFF, 0x00, 0xFF), /* Magenta */
+ RGB(0xFF, 0xFF, 0x00), /* Yellow */
+ RGB(0xFF, 0xFF, 0xFF) /* White */
+};
+static HBRUSH ColorBrushes[TEST_COLOR_COUNT] = { 0 };
+
+static BOOL HaveHRedraw = FALSE;
+static BOOL HaveVRedraw = FALSE;
+static BOOL WindowCreatedOk = FALSE;
+
+typedef enum _FSM_STATE
+{
+ FSM_STATE_START,
+ FSM_STATE_VSCR_SHOWN,
+ FSM_STATE_VSCR_HIDDEN,
+ FSM_STATE_HSCR_SHOWN,
+ FSM_STATE_HSCR_HIDDEN,
+ FSM_STATE_BSCR_SHOWN,
+ FSM_STATE_BSCR_HIDDEN,
+ FSM_STATE_WIDTH_SHRUNK,
+ FSM_STATE_WIDTH_EXPANDED,
+ FSM_STATE_HEIGHT_SHRUNK,
+ FSM_STATE_HEIGHT_EXPANDED,
+ FSM_STATE_BOTH_SHRUNK,
+ FSM_STATE_BOTH_EXPANDED,
+ FSM_STATE_END
+} FSM_STATE;
+
+#define FSM_STEP_PERIOD_MS 250
+
+static UINT_PTR FsmTimer = 0;
+static UINT CurrentColor = 0;
+static FSM_STATE FsmState = FSM_STATE_START;
+
+static int ClientWidth = 0;
+static int ClientHeight = 0;
+
+static int OrigWidth = 0;
+static int OrigHeight = 0;
+static int SmallWidth = 0;
+static int SmallHeight = 0;
+
+static void ColorsCleanup(void)
+{
+ UINT Iter;
+
+ for (Iter = 0; Iter < _countof(ColorBrushes); Iter++)
+ {
+ if (ColorBrushes[Iter] != NULL)
+ {
+ DeleteObject(ColorBrushes[Iter]);
+ ColorBrushes[Iter] = NULL;
+ }
+ }
+}
+
+static BOOL ColorsInit(void)
+{
+ UINT Iter;
+
+ assert(_countof(Colors) == _countof(ColorBrushes));
+
+ for (Iter = 0; Iter < _countof(ColorBrushes); Iter++)
+ {
+ ColorBrushes[Iter] = CreateSolidBrush(Colors[Iter]);
+ if (ColorBrushes[Iter] == NULL)
+ {
+ ColorsCleanup();
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static void RunTestWindow(PCWSTR ClassName, PCWSTR WindowTitle, UINT ClassStyle)
+{
+ WNDCLASSW Class = { 0 };
+ HWND Window;
+ MSG Message;
+ HINSTANCE hInst;
+
+ CurrentColor = 0;
+ hInst = GetModuleHandleW(NULL);
+
+ Class.style = ClassStyle;
+ Class.lpfnWndProc = WindowProc;
+ Class.cbClsExtra = 0;
+ Class.cbWndExtra = 0;
+ Class.hInstance = hInst;
+ Class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ Class.hCursor = LoadCursor(NULL, IDC_ARROW);
+ Class.hbrBackground = ColorBrushes[CurrentColor];
+ Class.lpszMenuName = NULL;
+ Class.lpszClassName = ClassName;
+
+ if (!RegisterClassW(&Class))
+ {
+ skip("Failed to register window class '%ls', code: %ld\n",
+ ClassName, GetLastError());
+ return;
+ }
+
+ Window = CreateWindowW(ClassName,
+ WindowTitle,
+ WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ NULL,
+ NULL,
+ hInst,
+ NULL);
+ if (Window == NULL)
+ {
+ skip("Failed to create window of class '%ls', code: %ld\n",
+ ClassName, GetLastError());
+ return;
+ }
+
+ ShowWindow(Window, SW_SHOWNORMAL);
+ UpdateWindow(Window);
+
+ while (GetMessageW(&Message, NULL, 0, 0))
+ {
+ TranslateMessage(&Message);
+ DispatchMessageW(&Message);
+ }
+}
+
+START_TEST(ScrollBarRedraw)
+{
+ if (!ColorsInit())
+ {
+ skip("Failed to initialize colors and solid color brushes\n");
+ return;
+ }
+
+ trace("Running test without specifying either CS_HREDRAW or
CS_HREDRAW\n");
+ HaveHRedraw = FALSE;
+ HaveVRedraw = FALSE;
+ RunTestWindow(TEST_CLASS_NAME L"NoRedraw",
+ TEST_WINDOW_TITLE L" (No Redraw Flags)",
+ 0);
+
+ trace("Running test with CS_HREDRAW\n");
+ HaveHRedraw = TRUE;
+ HaveVRedraw = FALSE;
+ RunTestWindow(TEST_CLASS_NAME L"HRedraw",
+ TEST_WINDOW_TITLE L" (CS_HREDRAW)",
+ CS_HREDRAW);
+
+ trace("Running test with CS_VREDRAW\n");
+ HaveHRedraw = FALSE;
+ HaveVRedraw = TRUE;
+ RunTestWindow(TEST_CLASS_NAME L"VRedraw",
+ TEST_WINDOW_TITLE L" (CS_VREDRAW)",
+ CS_VREDRAW);
+
+ trace("Running test with both CS_HREDRAW and CS_VREDRAW\n");
+ HaveHRedraw = TRUE;
+ HaveVRedraw = TRUE;
+ RunTestWindow(TEST_CLASS_NAME L"HRedrawVRedraw",
+ TEST_WINDOW_TITLE L" (CS_HREDRAW | CS_VREDRAW)",
+ CS_HREDRAW | CS_VREDRAW);
+
+ trace("Test complete\n");
+ ColorsCleanup();
+}
+
+static void HideVertScrollBar(HWND Window)
+{
+ SCROLLINFO ScrollInfo;
+
+ ScrollInfo.cbSize = sizeof(ScrollInfo);
+ ScrollInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+ ScrollInfo.nPage = ClientHeight;
+
+ ScrollInfo.nMin = 0;
+ ScrollInfo.nMax = ClientHeight - 1;
+ ScrollInfo.nPos = 0;
+
+ SetScrollInfo(Window, SB_VERT, &ScrollInfo, TRUE);
+}
+
+static void ShowVertScrollBar(HWND Window)
+{
+ SCROLLINFO ScrollInfo;
+
+ ScrollInfo.cbSize = sizeof(ScrollInfo);
+ ScrollInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+ ScrollInfo.nPage = ClientHeight;
+
+ ScrollInfo.nMin = 0;
+ ScrollInfo.nMax = (3 * ClientHeight) - 1;
+ ScrollInfo.nPos = 0;
+
+ SetScrollInfo(Window, SB_VERT, &ScrollInfo, TRUE);
+}
+
+static void HideHorzScrollBar(HWND Window)
+{
+ SCROLLINFO ScrollInfo;
+
+ ScrollInfo.cbSize = sizeof(ScrollInfo);
+ ScrollInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+ ScrollInfo.nPage = ClientWidth;
+
+ ScrollInfo.nMin = 0;
+ ScrollInfo.nMax = ClientWidth - 1;
+ ScrollInfo.nPos = 0;
+
+ SetScrollInfo(Window, SB_HORZ, &ScrollInfo, TRUE);
+}
+
+static void ShowHorzScrollBar(HWND Window)
+{
+ SCROLLINFO ScrollInfo;
+
+ ScrollInfo.cbSize = sizeof(ScrollInfo);
+ ScrollInfo.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+ ScrollInfo.nPage = ClientWidth;
+
+ ScrollInfo.nMin = 0;
+ ScrollInfo.nMax = (3 * ClientWidth) - 1;
+ ScrollInfo.nPos = 0;
+
+ SetScrollInfo(Window, SB_HORZ, &ScrollInfo, TRUE);
+}
+
+static int FsmStep(HWND Window)
+{
+ static COLORREF PrevColor = CLR_INVALID;
+ COLORREF Color = CLR_INVALID;
+ HDC hdc = NULL;
+
+ if (FsmState != FSM_STATE_END)
+ {
+ hdc = GetDC(Window);
+ if (hdc == NULL)
+ {
+ skip("Failed to get device context\n");
+
+ FsmState = FSM_STATE_END;
+ DestroyWindow(Window);
+
+ return 0;
+ }
+ Color = GetPixel(hdc, ClientWidth / 4, ClientHeight / 4);
+
+ ReleaseDC(Window, hdc);
+ hdc = NULL;
+
+ if (Color == CLR_INVALID)
+ {
+ skip("Failed to get window color\n");
+
+ FsmState = FSM_STATE_END;
+ DestroyWindow(Window);
+
+ return 0;
+ }
+ }
+
+ trace("FsmState: %d, Color: 0x%.8lX\n", FsmState, Color);
+
+ switch (FsmState)
+ {
+ case FSM_STATE_START:
+ ShowVertScrollBar(Window);
+ FsmState = FSM_STATE_VSCR_SHOWN;
+ break;
+
+ case FSM_STATE_VSCR_SHOWN:
+ if (HaveHRedraw)
+ {
+ ok(Color != PrevColor,
+ "CS_HREDRAW specified, but appearence of vertical scroll
bar"
+ " didn't trigger redraw, PrevColor: 0x%.8lX, Color:
0x%.8lX\n",
+ PrevColor, Color);
+ }
+ else
+ {
+ ok(Color == PrevColor,
+ "CS_HREDRAW not specified, but appearence of vertical scroll
bar"
+ " triggered unneccessary redraw, PrevColor: 0x%.8lX, Color:
0x%.8lX\n",
+ PrevColor, Color);
+ }
+
+ HideVertScrollBar(Window);
+ FsmState = FSM_STATE_VSCR_HIDDEN;
+ break;
+
+ case FSM_STATE_VSCR_HIDDEN:
+ if (HaveHRedraw)
+ {
+ ok(Color != PrevColor,
+ "CS_HREDRAW specified, but disappearence of vertical scroll
bar"
+ " didn't trigger redraw, PrevColor: 0x%.8lX, Color:
0x%.8lX\n",
+ PrevColor, Color);
+ }
+ else
+ {
+ ok(Color == PrevColor,
+ "CS_HREDRAW not specified, but disappearence of vertical scroll
bar"
+ " triggered unneccessary redraw, PrevColor: 0x%.8lX, Color:
0x%.8lX\n",
+ PrevColor, Color);
+ }
+
+ ShowHorzScrollBar(Window);
+ FsmState = FSM_STATE_HSCR_SHOWN;
+ break;
+
+ case FSM_STATE_HSCR_SHOWN:
+ if (HaveVRedraw)
+ {
+ ok(Color != PrevColor,
+ "CS_VREDRAW specified, but appearence of horizontal scroll
bar"
+ " didn't trigger redraw, PrevColor: 0x%.8lX, Color:
0x%.8lX\n",
+ PrevColor, Color);
+ }
+ else
+ {
+ ok(Color == PrevColor,
+ "CS_VREDRAW not specified, but appearence of horizontal scroll
bar"
+ " triggered unneccessary redraw, PrevColor: 0x%.8lX, Color:
0x%.8lX\n",
+ PrevColor, Color);
+ }
+
+ HideHorzScrollBar(Window);
+ FsmState = FSM_STATE_HSCR_HIDDEN;
+ break;
+
+ case FSM_STATE_HSCR_HIDDEN:
+ if (HaveVRedraw)
+ {
+ ok(Color != PrevColor,
+ "CS_VREDRAW specified, but disappearence of horizontal scroll
bar"
+ " didn't trigger redraw, PrevColor: 0x%.8lX, Color:
0x%.8lX\n",
+ PrevColor, Color);
+ }
+ else
+ {
+ ok(Color == PrevColor,
+ "CS_VREDRAW not specified, but disappearence of horizontal scroll
bar"
+ " triggered unneccessary redraw, PrevColor: 0x%.8lX, Color:
0x%.8lX\n",
+ PrevColor, Color);
+ }
+
+ ShowVertScrollBar(Window);
+ ShowHorzScrollBar(Window);
+
+ FsmState = FSM_STATE_BSCR_SHOWN;
+ break;
+
+ case FSM_STATE_BSCR_SHOWN:
+ if (HaveHRedraw || HaveVRedraw)
+ {
+ ok(Color != PrevColor,
+ "CS_HREDRAW or CS_VREDRAW specified, but appearence of both
scroll bars"
+ " didn't trigger redraw, PrevColor: 0x%.8lX, Color:
0x%.8lX\n",
+ PrevColor, Color);
+ }
+ else
+ {
+ ok(Color == PrevColor,
+ "Neither CS_HREDRAW nor CS_VREDRAW specified, but
appearence"
+ " of both scroll bars triggered unneccessary redraw,"
+ " PrevColor: 0x%.8lX, Color: 0x%.8lX\n",
+ PrevColor, Color);
+ }
+
+ HideVertScrollBar(Window);
+ HideHorzScrollBar(Window);
+
+ FsmState = FSM_STATE_BSCR_HIDDEN;
+ break;
+
+ case FSM_STATE_BSCR_HIDDEN:
+ if (HaveHRedraw || HaveVRedraw)
+ {
+ ok(Color != PrevColor,
+ "CS_HREDRAW or CS_VREDRAW specified, but disappearence of both
scroll bars"
+ " didn't trigger redraw, PrevColor: 0x%.8lX, Color:
0x%.8lX\n",
+ PrevColor, Color);
+ }
+ else
+ {
+ ok(Color == PrevColor,
+ "Neither CS_HREDRAW nor CS_VREDRAW specified, but
disappearence"
+ " of both scroll bars triggered unneccessary redraw,"
+ " PrevColor: 0x%.8lX, Color: 0x%.8lX\n",
+ PrevColor, Color);
+ }
+
+ SetWindowPos(Window, HWND_TOPMOST, 0, 0, SmallWidth, OrigHeight,
SWP_NOMOVE);
+ FsmState = FSM_STATE_WIDTH_SHRUNK;
+ break;
+
+ case FSM_STATE_WIDTH_SHRUNK:
+ if (HaveHRedraw)
+ {
+ ok(Color != PrevColor,
+ "CS_HREDRAW specified, but horizontal window shrinkage"
+ " didn't trigger redraw, PrevColor: 0x%.8lX, Color:
0x%.8lX\n",
+ PrevColor, Color);
+ }
+ else
+ {
+ ok(Color == PrevColor,
+ "CS_HREDRAW not specified, but horizontal window shrinkage"
+ " triggered unneccessary redraw, PrevColor: 0x%.8lX, Color:
0x%.8lX\n",
+ PrevColor, Color);
+ }
+
+ SetWindowPos(Window, HWND_TOPMOST, 0, 0, OrigWidth, OrigHeight, SWP_NOMOVE);
+ FsmState = FSM_STATE_WIDTH_EXPANDED;
+ break;
+
+ case FSM_STATE_WIDTH_EXPANDED:
+ if (HaveHRedraw)
+ {
+ ok(Color != PrevColor,
+ "CS_HREDRAW specified, but horizontal window expansion"
+ " didn't trigger redraw, PrevColor: 0x%.8lX, Color:
0x%.8lX\n",
+ PrevColor, Color);
+ }
+ else
+ {
+ ok(Color == PrevColor,
+ "CS_HREDRAW not specified, but horizontal window expansion"
+ " triggered unneccessary redraw, PrevColor: 0x%.8lX, Color:
0x%.8lX\n",
+ PrevColor, Color);
+ }
+
+ SetWindowPos(Window, HWND_TOPMOST, 0, 0, OrigWidth, SmallHeight,
SWP_NOMOVE);
+ FsmState = FSM_STATE_HEIGHT_SHRUNK;
+ break;
+
+ case FSM_STATE_HEIGHT_SHRUNK:
+ if (HaveVRedraw)
+ {
+ ok(Color != PrevColor,
+ "CS_VREDRAW specified, but vertical window shrinkage"
+ " didn't trigger redraw, PrevColor: 0x%.8lX, Color:
0x%.8lX\n",
+ PrevColor, Color);
+ }
+ else
+ {
+ ok(Color == PrevColor,
+ "CS_VREDRAW not specified, but vertical window shrinkage"
+ " triggered unneccessary redraw, PrevColor: 0x%.8lX, Color:
0x%.8lX\n",
+ PrevColor, Color);
+ }
+
+ SetWindowPos(Window, HWND_TOPMOST, 0, 0, OrigWidth, OrigHeight, SWP_NOMOVE);
+ FsmState = FSM_STATE_HEIGHT_EXPANDED;
+ break;
+
+ case FSM_STATE_HEIGHT_EXPANDED:
+ if (HaveVRedraw)
+ {
+ ok(Color != PrevColor,
+ "CS_VREDRAW specified, but vertical window expansion"
+ " didn't trigger redraw, PrevColor: 0x%.8lX, Color:
0x%.8lX\n",
+ PrevColor, Color);
+ }
+ else
+ {
+ ok(Color == PrevColor,
+ "CS_VREDRAW not specified, but vertical window expansion"
+ " triggered unneccessary redraw, PrevColor: 0x%.8lX, Color:
0x%.8lX\n",
+ PrevColor, Color);
+ }
+
+ SetWindowPos(Window, HWND_TOPMOST, 0, 0, SmallWidth, SmallHeight,
SWP_NOMOVE);
+
+ FsmState = FSM_STATE_BOTH_SHRUNK;
+ break;
+
+ case FSM_STATE_BOTH_SHRUNK:
+ if (HaveHRedraw || HaveVRedraw)
+ {
+ ok(Color != PrevColor,
+ "CS_HREDRAW or CS_VREDRAW specified, but combined"
+ " vertical/horizontal shrinkage didn't trigger redraw,"
+ " PrevColor: 0x%.8lX, Color: 0x%.8lX\n",
+ PrevColor, Color);
+ }
+ else
+ {
+ ok(Color == PrevColor,
+ "Neither CS_HREDRAW nor CS_VREDRAW specified, but combined"
+ " vertical/horizontal shrinkage triggered unneccessary
redraw,"
+ " PrevColor: 0x%.8lX, Color: 0x%.8lX\n",
+ PrevColor, Color);
+ }
+
+ SetWindowPos(Window, HWND_TOPMOST, 0, 0, OrigWidth, OrigHeight, SWP_NOMOVE);
+
+ FsmState = FSM_STATE_BOTH_EXPANDED;
+ break;
+
+ case FSM_STATE_BOTH_EXPANDED:
+ if (HaveHRedraw || HaveVRedraw)
+ {
+ ok(Color != PrevColor,
+ "CS_HREDRAW or CS_VREDRAW specified, but combined"
+ " vertical/horizontal expansion didn't trigger redraw,"
+ " PrevColor: 0x%.8lX, Color: 0x%.8lX\n",
+ PrevColor, Color);
+ }
+ else
+ {
+ ok(Color == PrevColor,
+ "Neither CS_HREDRAW nor CS_VREDRAW specified, but combined"
+ " vertical/horizontal expansion triggered unneccessary
redraw,"
+ " PrevColor: 0x%.8lX, Color: 0x%.8lX\n",
+ PrevColor, Color);
+ }
+
+ FsmState = FSM_STATE_END;
+ DestroyWindow(Window);
+ break;
+
+ case FSM_STATE_END:
+ break;
+ }
+
+ PrevColor = Color;
+ return 0;
+}
+
+static int OnPaint(HWND Window)
+{
+ HRGN Region;
+ HDC hdc;
+ PAINTSTRUCT ps;
+
+ hdc = BeginPaint(Window, &ps);
+ if (hdc == NULL)
+ {
+ skip("Failed to get device context\n");
+ DestroyWindow(Window);
+ return 0;
+ }
+
+ Region = CreateRectRgn(ps.rcPaint.left,
+ ps.rcPaint.top,
+ ps.rcPaint.right,
+ ps.rcPaint.bottom);
+ if (Region == NULL)
+ {
+ skip("Failed to create drawing region\n");
+ EndPaint(Window, &ps);
+ DestroyWindow(Window);
+ return 0;
+ }
+
+ if (!FillRgn(hdc, Region, ColorBrushes[CurrentColor]))
+ {
+ skip("Failed to paint the window\n");
+ DeleteObject(Region);
+ EndPaint(Window, &ps);
+ DestroyWindow(Window);
+ return 0;
+ }
+
+ DeleteObject(Region);
+ EndPaint(Window, &ps);
+
+ return 0;
+}
+
+static LRESULT CALLBACK WindowProc(HWND Window, UINT Message, WPARAM wParam, LPARAM
lParam)
+{
+ switch (Message)
+ {
+ case WM_CREATE:
+ {
+ RECT Rect;
+ WindowCreatedOk = FALSE;
+
+ /* It's important for the test that the entire Window is visible. */
+ if (!SetWindowPos(Window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE |
SWP_NOSIZE))
+ {
+ skip("Failed to set window as top-most, code: %ld\n",
GetLastError());
+ return -1;
+ }
+
+ if (!GetClientRect(Window, &Rect))
+ {
+ skip("Failed to retrieve client area dimensions, code: %ld\n",
GetLastError());
+ return -1;
+ }
+ ClientWidth = Rect.right;
+ ClientHeight = Rect.bottom;
+
+ if (!GetWindowRect(Window, &Rect))
+ {
+ skip("Failed to retrieve window dimensions, code: %ld\n",
GetLastError());
+ return -1;
+ }
+ OrigWidth = Rect.right - Rect.left;
+ OrigHeight = Rect.bottom - Rect.top;
+
+ SmallWidth = max((OrigWidth * 3) / 4, 1);
+ SmallHeight = max((OrigHeight * 3) / 4, 1);
+ OrigWidth = max(OrigWidth, SmallWidth + 1);
+ OrigHeight = max(OrigHeight, SmallHeight + 1);
+
+ trace("OrigWidth: %d, OrigHeight: %d, SmallWidth: %d, SmallHeight:
%d\n",
+ OrigWidth, OrigHeight, SmallWidth, SmallHeight);
+
+ HideVertScrollBar(Window);
+ HideHorzScrollBar(Window);
+
+ FsmState = FSM_STATE_START;
+ FsmTimer = 0;
+ WindowCreatedOk = TRUE;
+ return 0;
+ }
+
+ case WM_PAINT:
+ if (FsmTimer == 0 && WindowCreatedOk)
+ {
+ FsmTimer = SetTimer(Window, 1, FSM_STEP_PERIOD_MS, NULL);
+ if (FsmTimer == 0)
+ {
+ skip("Failed to initialize FSM timer, code: %ld\n",
GetLastError());
+ WindowCreatedOk = FALSE;
+ DestroyWindow(Window);
+ return 0;
+ }
+ }
+ return OnPaint(Window);
+
+ case WM_SIZE:
+ {
+ int NewWidth = LOWORD(lParam);
+ int NewHeight = HIWORD(lParam);
+
+ if (NewWidth != 0 && NewHeight != 0 &&
+ (NewWidth != ClientWidth || NewHeight != ClientHeight))
+ {
+ CurrentColor = (CurrentColor + 1) % TEST_COLOR_COUNT;
+ SetClassLongPtrW(Window,
+ GCLP_HBRBACKGROUND,
+ (LONG_PTR)ColorBrushes[CurrentColor]);
+
+ trace("New window size: %d x %d, new color: 0x%.8lX\n",
+ NewWidth, NewHeight, Colors[CurrentColor]);
+
+ ClientWidth = NewWidth;
+ ClientHeight = NewHeight;
+ }
+ return 0;
+ }
+
+ case WM_ERASEBKGND:
+ /* We use WM_PAINT instead, since WM_ERASEBKGND is issued before WM_SIZE. */
+ return 1;
+
+ case WM_TIMER:
+ if (wParam != 0 && wParam == FsmTimer)
+ {
+ return FsmStep(Window);
+ }
+ break;
+
+ case WM_NCDESTROY:
+ if (FsmTimer != 0)
+ {
+ KillTimer(Window, FsmTimer);
+ FsmTimer = 0;
+
+ if (FsmState != FSM_STATE_END)
+ {
+ skip("Window closed before test concluded, FsmState: %d,
FSM_STATE_END: %d.\n",
+ FsmState, FSM_STATE_END);
+ }
+ }
+ else if (WindowCreatedOk)
+ {
+ skip("Window closed before test began.\n");
+ }
+ return 0;
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+ }
+ return DefWindowProcW(Window, Message, wParam, lParam);
+}
diff --git a/modules/rostests/apitests/user32/testlist.c
b/modules/rostests/apitests/user32/testlist.c
index 5186c71c5d1..f8508301df0 100644
--- a/modules/rostests/apitests/user32/testlist.c
+++ b/modules/rostests/apitests/user32/testlist.c
@@ -42,6 +42,7 @@ extern void func_RealGetWindowClass(void);
extern void func_RedrawWindow(void);
extern void func_RegisterHotKey(void);
extern void func_RegisterClassEx(void);
+extern void func_ScrollBarRedraw(void);
extern void func_ScrollBarWndExtra(void);
extern void func_ScrollDC(void);
extern void func_ScrollWindowEx(void);
@@ -104,6 +105,7 @@ const struct test winetest_testlist[] =
{ "RedrawWindow", func_RedrawWindow },
{ "RegisterHotKey", func_RegisterHotKey },
{ "RegisterClassEx", func_RegisterClassEx },
+ { "ScrollBarRedraw", func_ScrollBarRedraw },
{ "ScrollBarWndExtra", func_ScrollBarWndExtra },
{ "ScrollDC", func_ScrollDC },
{ "ScrollWindowEx", func_ScrollWindowEx },