[PATCH] richedit: do not read actual scrollbar state for scrollbar update, use internal state instead.

Alex Villacís Lasso alex at karlalex.palosanto.com
Mon Jun 30 00:13:53 CDT 2008


Some applications have never heard of ES_DISABLENOSCROLL and attempt to force scrollbars to be always shown (with ShowScrollBar() or similar) when otherwise richedit would hide them. If richedit attempts to wrestle control back, a recursive loop of requests can result if app overrides WM_SIZE behavior. Apparently native never reads the scrollbar state, and operates from some sort of internal state, so that scrollbars can be modified externally without native trying to wrestle back control. This is confirmed by attached tests. An exception: EM_SCROLL will restore visibility to a scrollbar that was forcibly hidden.
---
 dlls/riched20/editor.c       |   21 ++
 dlls/riched20/editstr.h      |    3 +
 dlls/riched20/paint.c        |   36 ++-
 dlls/riched20/tests/editor.c |  794 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 844 insertions(+), 10 deletions(-)

diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c
index 28850f9..bff1642 100644
--- a/dlls/riched20/editor.c
+++ b/dlls/riched20/editor.c
@@ -1704,6 +1704,13 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) {
   
   ed->notified_cr.cpMin = ed->notified_cr.cpMax = 0;
 
+  /* Default vertical scrollbar information */
+  ed->vert_si.cbSize = sizeof(SCROLLINFO);
+  ed->vert_si.nMin = 0;
+  ed->vert_si.nMax = 0;
+  ed->vert_si.nPage = 0;
+  ed->vert_si.nPos = 0;
+
   return ed;
 }
 
@@ -2948,15 +2955,29 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
     return (wParam >= 0x40000) ? 0 : MAKELONG( pt.x, pt.y );
   }
   case WM_CREATE:
+  {
+    SCROLLINFO si;
+
     GetClientRect(hWnd, &editor->rcFormat);
     if (GetWindowLongW(hWnd, GWL_STYLE) & WS_HSCROLL)
     { /* Squelch the default horizontal scrollbar it would make */
       ShowScrollBar(editor->hWnd, SB_HORZ, FALSE);
     }
+
+    si.cbSize = sizeof(si);
+    si.fMask = SIF_PAGE | SIF_RANGE;
+    if (GetWindowLongW(hWnd, GWL_STYLE) & ES_DISABLENOSCROLL)
+      si.fMask |= SIF_DISABLENOSCROLL;
+    si.nMax = (si.fMask & SIF_DISABLENOSCROLL) ? 1 : 0;
+    si.nMin = 0;
+    si.nPage = 0;
+    SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
+
     ME_CommitUndo(editor);
     ME_WrapMarkedParagraphs(editor);
     ME_MoveCaret(editor);
     return 0;
+  }
   case WM_DESTROY:
     ME_DestroyEditor(editor);
     SetWindowLongPtrW(hWnd, 0, 0);
diff --git a/dlls/riched20/editstr.h b/dlls/riched20/editstr.h
index d54edbf..9aac087 100644
--- a/dlls/riched20/editstr.h
+++ b/dlls/riched20/editstr.h
@@ -335,6 +335,9 @@ typedef struct tagME_TextEditor
 
   /* Track previous notified selection */
   CHARRANGE notified_cr;
+  
+  /* Cache previously set vertical scrollbar info */
+  SCROLLINFO vert_si;
 } ME_TextEditor;
 
 typedef struct tagME_Context
diff --git a/dlls/riched20/paint.c b/dlls/riched20/paint.c
index 95befbc..f073aa7 100644
--- a/dlls/riched20/paint.c
+++ b/dlls/riched20/paint.c
@@ -640,6 +640,7 @@ void ME_Scroll(ME_TextEditor *editor, int value, int type)
     ME_Repaint(editor);
   }
   
+  editor->vert_si.nMax = 0;
   ME_UpdateScrollBar(editor);
 }
 
@@ -662,6 +663,14 @@ void ME_Scroll(ME_TextEditor *editor, int value, int type)
   bScrollBarWasVisible = ME_GetYScrollVisible(editor);
   bScrollBarWillBeVisible = editor->nHeight > editor->sizeWindow.cy;
   
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  if (GetWindowLongW(hWnd, GWL_STYLE) & ES_DISABLENOSCROLL)
+    si.fMask |= SIF_DISABLENOSCROLL;
+  if ((si.fMask & SIF_DISABLENOSCROLL)) 
+  {
+    bScrollBarWillBeVisible = TRUE;
+  }
+
   if (bScrollBarWasVisible != bScrollBarWillBeVisible)
   {
     ShowScrollBar(hWnd, SB_VERT, bScrollBarWillBeVisible);
@@ -669,17 +678,27 @@ void ME_Scroll(ME_TextEditor *editor, int value, int type)
     ME_WrapMarkedParagraphs(editor);
   }
   
-  si.fMask = SIF_PAGE | SIF_RANGE;
-  if (GetWindowLongW(hWnd, GWL_STYLE) & ES_DISABLENOSCROLL)
-    si.fMask |= SIF_DISABLENOSCROLL;
-  
   si.nMin = 0;  
   si.nMax = editor->nTotalLength;
 
   si.nPage = editor->sizeWindow.cy;
      
-  TRACE("min=%d max=%d page=%d\n", si.nMin, si.nMax, si.nPage);
-  SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
+  if (!(si.nMin == editor->vert_si.nMin && si.nMax == editor->vert_si.nMax && si.nPage == editor->vert_si.nPage))
+  {
+    TRACE("min=%d max=%d page=%d\n", si.nMin, si.nMax, si.nPage);
+    editor->vert_si.nMin = si.nMin;
+    editor->vert_si.nMax = si.nMax;
+    editor->vert_si.nPage = si.nPage;
+    if (bScrollBarWillBeVisible)
+    {
+      SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
+    }
+    else
+    {
+      if (bScrollBarWasVisible && !(si.fMask & SIF_DISABLENOSCROLL))
+        ShowScrollBar(hWnd, SB_VERT, FALSE);
+    }
+  }
 }
 
 int ME_GetYScrollPos(ME_TextEditor *editor)
@@ -692,10 +711,7 @@ int ME_GetYScrollPos(ME_TextEditor *editor)
 
 BOOL ME_GetYScrollVisible(ME_TextEditor *editor)
 { /* Returns true if the scrollbar is visible */
-  SCROLLBARINFO sbi;
-  sbi.cbSize = sizeof(sbi);
-  GetScrollBarInfo(editor->hWnd, OBJID_VSCROLL, &sbi);
-  return ((sbi.rgstate[0] & STATE_SYSTEM_INVISIBLE) == 0);
+  return (editor->vert_si.nMax - editor->vert_si.nMin >= max(editor->vert_si.nPage - 1, 0));
 }
 
 void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun)
diff --git a/dlls/riched20/tests/editor.c b/dlls/riched20/tests/editor.c
index 064e780..694b42f 100644
--- a/dlls/riched20/tests/editor.c
+++ b/dlls/riched20/tests/editor.c
@@ -2209,6 +2209,799 @@ static void test_EM_SCROLL(void)
   DestroyWindow(hwndRichEdit);
 }
 
+unsigned int recursionLevel = 0;
+unsigned int WM_SIZE_recursionLevel = 0;
+BOOL bailedOutOfRecursion = FALSE;
+LRESULT WINAPI (*richeditProc)(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+#if 0
+static void reportScrollRanges(const char * s, HWND hwndRichEdit)
+{
+  SCROLLBARINFO sbi;
+  SCROLLINFO si_v, si_h;
+  long currStyle = GetWindowLongA(hwndRichEdit, GWL_STYLE);
+
+  memset(&sbi, 0, sizeof(sbi));
+  sbi.cbSize = sizeof(sbi);
+  GetScrollBarInfo(hwndRichEdit, OBJID_VSCROLL, &sbi);
+  memset(&si_v, 0, sizeof(si_v));
+  si_v.cbSize = sizeof(si_v);
+  si_v.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si_v);
+  memset(&si_h, 0, sizeof(si_h));
+  si_h.cbSize = sizeof(si_h);
+  si_h.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_HORZ, &si_h);
+  trace("\t[%s] %s %s sbi.rgstate[0] == 0x%08x reported page/range is V(%d %d..%d) H(%d %d..%d)\n",
+        s,
+        (currStyle & WS_VSCROLL) ? "WS_VSCROLL" : "----------",
+        (currStyle & WS_HSCROLL) ? "WS_HSCROLL" : "----------",
+        sbi.rgstate[0],
+        si_v.nPage, si_v.nMin, si_v.nMax,
+        si_h.nPage, si_h.nMin, si_h.nMax
+       );
+}
+#endif
+static LRESULT WINAPI RicheditStupidOverrideProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    LRESULT r;
+
+    if (recursionLevel >= 32) {
+        trace("tired of calling myself, giving up...\n");
+        bailedOutOfRecursion = TRUE;
+        return 0;
+    }
+
+    recursionLevel++;
+    trace("[0x%08x] Entering recursion level %d\n", message, recursionLevel);
+    /*reportScrollRanges("on entry", hwnd);*/
+    switch (message) {
+    case WM_SIZE:
+        WM_SIZE_recursionLevel++;
+        trace("Processing WM_SIZE (recursion level %d, WM_SIZE recursion %d)\n",
+            recursionLevel, WM_SIZE_recursionLevel);
+        r = richeditProc(hwnd, message, wParam, lParam);
+        /*reportScrollRanges("before forced show", hwnd);*/
+        /* Because, uhhhh... I never heard of ES_DISABLENOSCROLL */
+        ShowScrollBar(hwnd, SB_VERT, TRUE);
+        /*reportScrollRanges("after forced show", hwnd);*/
+        WM_SIZE_recursionLevel--;
+        break;
+    default:
+        r = richeditProc(hwnd, message, wParam, lParam);
+        break;
+    }
+    /*reportScrollRanges("at exit", hwnd);*/
+    trace("Exiting recursion level %d\n", recursionLevel);
+    recursionLevel--;
+    return r;
+}
+
+static void test_scrollbar_visibility(void)
+{
+  HWND hwndRichEdit;
+  const char * text="a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n";
+  SCROLLINFO si;
+  WNDCLASSA cls;
+  BOOL r;
+
+  /* These tests show that richedit should temporarily refrain from automatically
+     hiding or showing its scrollbars (vertical at least) when an explicit request
+     is made via ShowScrollBar() or similar, outside of standard richedit logic.
+     Some applications depend on forced showing (when otherwise richedit would
+     hide the vertical scrollbar) and are thrown on an endless recursive loop
+     if richedit auto-hides the scrollbar again. Apparently they never heard of
+     the ES_DISABLENOSCROLL style... */
+
+  hwndRichEdit = new_richedit(NULL);
+
+  /* Test default scrollbar visibility behavior */
+  trace("testing default scrollbar behavior...\n");
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
+        "reported page/range is %d (%d..%d) expected all 0\n",
+        si.nPage, si.nMin, si.nMax);
+
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
+        "reported page/range is %d (%d..%d) expected all 0\n",
+        si.nPage, si.nMin, si.nMax);
+
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
+        si.nPage, si.nMin, si.nMax);
+
+  /* Oddly, setting text to NULL does *not* reset the scrollbar range,
+     even though it hides the scrollbar */
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
+        si.nPage, si.nMin, si.nMax);
+
+  /* Setting non-scrolling text again does *not* reset scrollbar range */
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
+        si.nPage, si.nMin, si.nMax);
+
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
+        si.nPage, si.nMin, si.nMax);
+
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
+        si.nPage, si.nMin, si.nMax);
+
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
+        si.nPage, si.nMin, si.nMax);
+
+  DestroyWindow(hwndRichEdit);
+
+  /* Test again, with ES_DISABLENOSCROLL style */
+  hwndRichEdit = new_window(RICHEDIT_CLASS, ES_MULTILINE|ES_DISABLENOSCROLL, NULL);
+
+  /* Test default scrollbar visibility behavior */
+  trace("testing default scrollbar behavior...\n");
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 1,
+        "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
+        si.nPage, si.nMin, si.nMax);
+
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 1,
+        "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
+        si.nPage, si.nMin, si.nMax);
+
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
+        "reported page/range is %d (%d..%d)\n",
+        si.nPage, si.nMin, si.nMax);
+
+  /* Oddly, setting text to NULL does *not* reset the scrollbar range */
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
+        "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
+        si.nPage, si.nMin, si.nMax);
+
+  /* Setting non-scrolling text again does *not* reset scrollbar range */
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
+        "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
+        si.nPage, si.nMin, si.nMax);
+
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
+        "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
+        si.nPage, si.nMin, si.nMax);
+
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
+        "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
+        si.nPage, si.nMin, si.nMax);
+
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
+        "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
+        si.nPage, si.nMin, si.nMax);
+
+  DestroyWindow(hwndRichEdit);
+
+  /* Test behavior with explicit visibility request, using ShowScrollBar() */
+  hwndRichEdit = new_richedit(NULL);
+
+  /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
+  trace("explicitly requesting visible scrollbar\n");
+  ShowScrollBar(hwndRichEdit, SB_VERT, TRUE);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  todo_wine {
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
+        "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
+        si.nPage, si.nMin, si.nMax);
+  }
+
+  /* Ditto, see above */
+  trace("depending on explicitly requested visible scrollbar\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  todo_wine {
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
+        "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
+        si.nPage, si.nMin, si.nMax);
+  }
+
+  /* Ditto, see above */
+  trace("depending on explicitly requested visible scrollbar\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  todo_wine {
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
+        "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
+        si.nPage, si.nMin, si.nMax);
+  }
+
+  /* Ditto, see above */
+  trace("depending on explicitly requested visible scrollbar\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\na");
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  todo_wine {
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
+        "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
+        si.nPage, si.nMin, si.nMax);
+  }
+
+  /* Ditto, see above */
+  trace("depending on explicitly requested visible scrollbar\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  todo_wine {
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
+        "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
+        si.nPage, si.nMin, si.nMax);
+  }
+
+  trace("resetting to default behavior\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  trace("reported page/range is %d (%d..%d)\n", si.nPage, si.nMin, si.nMax);
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
+        si.nPage, si.nMin, si.nMax);
+
+  DestroyWindow(hwndRichEdit);
+
+  hwndRichEdit = new_richedit(NULL);
+
+  trace("explicitly requesting invisible scrollbar\n");
+  ShowScrollBar(hwndRichEdit, SB_VERT, FALSE);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
+        "reported page/range is %d (%d..%d) expected all 0\n",
+        si.nPage, si.nMin, si.nMax);
+
+  trace("depending on explicitly requested invisible scrollbar\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
+        "reported page/range is %d (%d..%d) expected all 0\n",
+        si.nPage, si.nMin, si.nMax);
+
+  trace("depending on explicitly requested invisible scrollbar\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
+        "reported page/range is %d (%d..%d) expected all 0\n",
+        si.nPage, si.nMin, si.nMax);
+
+  trace("depending on explicitly requested invisible scrollbar\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
+        "reported page/range is %d (%d..%d) expected all 0\n",
+        si.nPage, si.nMin, si.nMax);
+
+  trace("resetting default behavior\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d)\n",
+        si.nPage, si.nMin, si.nMax);
+
+  /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
+  trace("explicitly requesting invisible scrollbar\n");
+  ShowScrollBar(hwndRichEdit, SB_VERT, FALSE);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d)\n",
+        si.nPage, si.nMin, si.nMax);
+
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d)\n",
+        si.nPage, si.nMin, si.nMax);
+
+  /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that 
+     EM_SCROLL will make visible any forcefully invisible scrollbar */
+  SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d)\n",
+        si.nPage, si.nMin, si.nMax);
+
+  trace("explicitly requesting invisible scrollbar\n");
+  ShowScrollBar(hwndRichEdit, SB_VERT, FALSE);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d)\n",
+        si.nPage, si.nMin, si.nMax);
+
+  /* Again, EM_SCROLL, with SB_LINEUP */
+  SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d)\n",
+        si.nPage, si.nMin, si.nMax);
+
+  trace("depending on explicitly requested invisible scrollbar\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  trace("reported page/range is %d (%d..%d)\n", si.nPage, si.nMin, si.nMax);
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
+        si.nPage, si.nMin, si.nMax);
+
+  trace("resetting default behavior\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d)\n",
+        si.nPage, si.nMin, si.nMax);
+
+  DestroyWindow(hwndRichEdit);
+
+
+  /* Test behavior with explicit visibility request, using SetWindowLong()() */
+  hwndRichEdit = new_richedit(NULL);
+
+#define ENABLE_WS_VSCROLL(hwnd) \
+    SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) | WS_VSCROLL)
+#define DISABLE_WS_VSCROLL(hwnd) \
+    SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~WS_VSCROLL)
+
+  /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
+  trace("explicitly requesting visible scrollbar\n");
+  ENABLE_WS_VSCROLL(hwndRichEdit);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
+        "reported page/range is %d (%d..%d) expected all 0\n",
+        si.nPage, si.nMin, si.nMax);
+
+  /* Ditto, see above */
+  trace("depending on explicitly requested visible scrollbar\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
+        "reported page/range is %d (%d..%d) expected all 0\n",
+        si.nPage, si.nMin, si.nMax);
+
+  /* Ditto, see above */
+  trace("depending on explicitly requested visible scrollbar\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
+        "reported page/range is %d (%d..%d) expected all 0\n",
+        si.nPage, si.nMin, si.nMax);
+
+  /* Ditto, see above */
+  trace("depending on explicitly requested visible scrollbar\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\na");
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
+        "reported page/range is %d (%d..%d) expected all 0\n",
+        si.nPage, si.nMin, si.nMax);
+
+  /* Ditto, see above */
+  trace("depending on explicitly requested visible scrollbar\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
+        "reported page/range is %d (%d..%d) expected all 0\n",
+        si.nPage, si.nMin, si.nMax);
+
+  trace("resetting to default behavior\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  trace("reported page/range is %d (%d..%d)\n", si.nPage, si.nMin, si.nMax);
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
+        si.nPage, si.nMin, si.nMax);
+
+  DestroyWindow(hwndRichEdit);
+
+  hwndRichEdit = new_richedit(NULL);
+
+  trace("explicitly requesting invisible scrollbar\n");
+  DISABLE_WS_VSCROLL(hwndRichEdit);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
+        "reported page/range is %d (%d..%d) expected all 0\n",
+        si.nPage, si.nMin, si.nMax);
+
+  trace("depending on explicitly requested invisible scrollbar\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
+        "reported page/range is %d (%d..%d) expected all 0\n",
+        si.nPage, si.nMin, si.nMax);
+
+  trace("depending on explicitly requested invisible scrollbar\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
+        "reported page/range is %d (%d..%d) expected all 0\n",
+        si.nPage, si.nMin, si.nMax);
+
+  trace("depending on explicitly requested invisible scrollbar\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 0,
+        "reported page/range is %d (%d..%d) expected all 0\n",
+        si.nPage, si.nMin, si.nMax);
+
+  trace("resetting default behavior\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d)\n",
+        si.nPage, si.nMin, si.nMax);
+
+  /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
+  trace("explicitly requesting invisible scrollbar\n");
+  DISABLE_WS_VSCROLL(hwndRichEdit);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d)\n",
+        si.nPage, si.nMin, si.nMax);
+
+  trace("depending on explicitly requested invisible scrollbar\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  trace("reported page/range is %d (%d..%d)\n", si.nPage, si.nMin, si.nMax);
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
+        si.nPage, si.nMin, si.nMax);
+
+  trace("resetting default behavior\n");
+  SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d)\n",
+        si.nPage, si.nMin, si.nMax);
+
+  trace("explicitly requesting invisible scrollbar\n");
+  DISABLE_WS_VSCROLL(hwndRichEdit);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d)\n",
+        si.nPage, si.nMin, si.nMax);
+
+  /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that 
+     EM_SCROLL will make visible any forcefully invisible scrollbar */
+  SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d)\n",
+        si.nPage, si.nMin, si.nMax);
+
+  trace("explicitly requesting invisible scrollbar\n");
+  DISABLE_WS_VSCROLL(hwndRichEdit);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0), 
+    "Vertical scrollbar is visible, should be invisible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d)\n",
+        si.nPage, si.nMin, si.nMax);
+
+  /* Again, EM_SCROLL, with SB_LINEUP */
+  SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0);
+  memset(&si, 0, sizeof(si));
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_PAGE | SIF_RANGE;
+  GetScrollInfo(hwndRichEdit, SB_VERT, &si);
+  ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0), 
+    "Vertical scrollbar is invisible, should be visible.\n");
+  ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
+        "reported page/range is %d (%d..%d)\n",
+        si.nPage, si.nMin, si.nMax);
+
+  DestroyWindow(hwndRichEdit);
+
+  /* This window proc models what is going on with Corman Lisp 3.0.
+     At WM_SIZE, this proc unconditionally calls ShowScrollBar() to
+     force the scrollbar into visibility. Recursion should NOT happen
+     as a result of this action.
+   */
+  r = GetClassInfoA(NULL, RICHEDIT_CLASS, &cls);
+  if (r) {
+    richeditProc = cls.lpfnWndProc;
+    cls.lpfnWndProc = RicheditStupidOverrideProcA;
+    cls.lpszClassName = "RicheditStupidOverride";
+    if(!RegisterClassA(&cls)) assert(0);
+    
+    recursionLevel = 0;
+    WM_SIZE_recursionLevel = 0;
+    bailedOutOfRecursion = FALSE;
+    hwndRichEdit = new_window(cls.lpszClassName, ES_MULTILINE, NULL);
+    ok(!bailedOutOfRecursion,
+        "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
+
+    recursionLevel = 0;
+    WM_SIZE_recursionLevel = 0;
+    bailedOutOfRecursion = FALSE;
+    MoveWindow(hwndRichEdit, 0, 0, 250, 100, TRUE);
+    ok(!bailedOutOfRecursion,
+        "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
+    
+    /* Unblock window in order to process WM_DESTROY */
+    recursionLevel = 0;
+    WM_SIZE_recursionLevel = 0;
+    DestroyWindow(hwndRichEdit);
+  }
+}
+
 static void test_EM_SETUNDOLIMIT(void)
 {
   /* cases we test for:
@@ -4569,6 +5362,7 @@ START_TEST( editor )
   test_EM_POSFROMCHAR();
   test_EM_SCROLLCARET();
   test_EM_SCROLL();
+  test_scrollbar_visibility();
   test_WM_SETTEXT();
   test_EM_LINELENGTH();
   test_EM_SETCHARFORMAT();
-- 
1.5.4.1


--------------010805090708040103060909--



More information about the wine-patches mailing list