https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a9b77d89fb660802f9e8ee4497e56f5d576ecb42

commit a9b77d89fb660802f9e8ee4497e56f5d576ecb42
Author:     Marek Benc <benc.marek.elektr...@proton.me>
AuthorDate: Tue Aug 27 20:25:02 2024 +0200
Commit:     GitHub <nore...@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 <x86co...@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.elektr...@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 },

Reply via email to