This series tries to fix WM_PASTE tests error on edit control (both user32 & comctl32).
The test failures where systematic on a local Win10 for comctl32 (yet very rare on user32, perhaps one in 20 runs).
Since the failures are not systematic, it ought to be a synchronisation / timing issue.
Flushing the msg queue before starting the paste test cycle seems to fix the issue. - 0 occurence on comctl32 and user32 in 50 run (local VM) - 0 occurence on Testbot (comctl32) in 1 run.
It's hard to be fully conclusive about bug resolution, but it's at least a step into the right direction.
-- v4: comctl32/tests: Fix failing WM_PASTE tests for edit control on Win10+. comctl32/tests: Retry when opening the clipboard. user32/tests: Fix failing WM_PASTE tests for edit control on Win10+. user32/tests: Retry when opening the clipboard.
From: Eric Pouech eric.pouech@gmail.com
As the clipboard is a shared resource, we cannot expect that no other app hasn't openeded it. So wrap clipboard access with a retry feature in case of failure.
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/user32/tests/edit.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-)
diff --git a/dlls/user32/tests/edit.c b/dlls/user32/tests/edit.c index 2afbbd5bea4..1918d1c10e9 100644 --- a/dlls/user32/tests/edit.c +++ b/dlls/user32/tests/edit.c @@ -32,6 +32,35 @@ #define ID_EDITTEST2 99 #define MAXLEN 200
+static BOOL open_clipboard(HWND hwnd) +{ + DWORD start = GetTickCount(); + while (1) + { + BOOL ret = OpenClipboard(hwnd); + if (ret || GetLastError() != ERROR_ACCESS_DENIED) + return ret; + if (GetTickCount() - start > 100) + { + char classname[256]; + DWORD le = GetLastError(); + HWND clipwnd = GetOpenClipboardWindow(); + /* Provide a hint as to the source of interference: + * - The class name would typically be CLIPBRDWNDCLASS if the + * clipboard was opened by a Windows application using the + * ole32 API. + * - And it would be __wine_clipboard_manager if it was opened in + * response to a native application. + */ + GetClassNameA(clipwnd, classname, ARRAY_SIZE(classname)); + trace("%p (%s) opened the clipboard\n", clipwnd, classname); + SetLastError(le); + return ret; + } + Sleep(15); + } +} + struct edit_notify { int en_change, en_maxtext, en_update; }; @@ -2192,7 +2221,7 @@ static void test_espassword(void) ok(r == strlen(password), "Expected: %s, got len %ld\n", password, r); ok(strcmp(buffer, password) == 0, "expected %s, got %s\n", password, buffer);
- r = OpenClipboard(hwEdit); + r = open_clipboard(hwEdit); ok(r == TRUE, "expected %d, got %ld le=%lu\n", TRUE, r, GetLastError()); r = EmptyClipboard(); ok(r == TRUE, "expected %d, got %ld\n", TRUE, r); @@ -3195,7 +3224,7 @@ static void test_paste(void) strcpy(buffer, str); GlobalUnlock(hmem);
- r = OpenClipboard(hEdit); + r = open_clipboard(hEdit); ok(r == TRUE, "expected %d, got %d le=%lu\n", TRUE, r, GetLastError()); r = EmptyClipboard(); ok(r == TRUE, "expected %d, got %d\n", TRUE, r); @@ -3218,7 +3247,7 @@ static void test_paste(void) strcpy(buffer, str2); GlobalUnlock(hmem);
- r = OpenClipboard(hEdit); + r = open_clipboard(hEdit); ok(r == TRUE, "expected %d, got %d le=%lu\n", TRUE, r, GetLastError()); r = EmptyClipboard(); ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
From: Eric Pouech eric.pouech@gmail.com
There are cases in Windows10+ where the WM_PASTE message doesn't paste the content of the clipboard.
This appeared in testing: - almost always just after (for a couple of milliseconds) setting new content into the clipboard and closing it. - in some unrelated rare occasions (like once for 400 runs).
It looks like another (installed) process had opened the clipboard and forbids the paste command. As WM_PASTE doesn't return success/error status, workaround it by wrapping the WM_PASTE command into a helper, and retry when the clipboard's content hasn't been pasted.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53276
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/user32/tests/edit.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-)
diff --git a/dlls/user32/tests/edit.c b/dlls/user32/tests/edit.c index 1918d1c10e9..b70cf2d6e06 100644 --- a/dlls/user32/tests/edit.c +++ b/dlls/user32/tests/edit.c @@ -3204,12 +3204,32 @@ static void test_EM_GETHANDLE(void) DestroyWindow(hEdit); }
+/* In Windows 10+, the WM_PASTE message isn't always successful. + * So retry in case of failure. + */ +#define check_paste(a, b) _check_paste(__LINE__, (a), (b)) +static void _check_paste(unsigned int line, HWND hedit, const char *content) +{ + /* only retry on windows platform */ + int tries = strcmp(winetest_platform, "wine") ? 3 : 1; + int len = 0; + + SendMessageA(hedit, WM_SETTEXT, 0, (LPARAM)""); + do + { + SendMessageA(hedit, WM_PASTE, 0, 0); + if ((len = SendMessageA(hedit, WM_GETTEXTLENGTH, 0, 0))) break; + Sleep(1); + } while (--tries > 0); + ok_(__FILE__, line)(len == strlen(content), "Unexpected len %u in edit\n", len); +} + static void test_paste(void) { HWND hEdit, hMultilineEdit; HANDLE hmem, hmem_ret; char *buffer; - int r, len; + int r; static const char *str = "this is a simple text"; static const char *str2 = "first line\r\nsecond line";
@@ -3234,10 +3254,7 @@ static void test_paste(void) ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
/* Paste single line */ - SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)""); - r = SendMessageA(hEdit, WM_PASTE, 0, 0); - len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0); - ok(strlen(str) == len, "got %d\n", len); + check_paste(hEdit, str);
/* Prepare clipboard data with multiline text */ hmem = GlobalAlloc(GMEM_MOVEABLE, 255); @@ -3257,16 +3274,10 @@ static void test_paste(void) ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
/* Paste multiline text in singleline edit - should be cut */ - SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)""); - r = SendMessageA(hEdit, WM_PASTE, 0, 0); - len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0); - ok(strlen("first line") == len, "got %d\n", len); + check_paste(hEdit, "first line");
/* Paste multiline text in multiline edit */ - SendMessageA(hMultilineEdit, WM_SETTEXT, 0, (LPARAM)""); - r = SendMessageA(hMultilineEdit, WM_PASTE, 0, 0); - len = SendMessageA(hMultilineEdit, WM_GETTEXTLENGTH, 0, 0); - ok(strlen(str2) == len, "got %d\n", len); + check_paste(hMultilineEdit, str2);
/* Cleanup */ DestroyWindow(hEdit);
From: Eric Pouech eric.pouech@gmail.com
As the clipboard is a shared resource, we cannot expect that no other app hasn't openeded it. So wrap clipboard access with a retry feature in case of failure.
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/comctl32/tests/edit.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-)
diff --git a/dlls/comctl32/tests/edit.c b/dlls/comctl32/tests/edit.c index 91d16e044a0..00ef54dea01 100644 --- a/dlls/comctl32/tests/edit.c +++ b/dlls/comctl32/tests/edit.c @@ -72,6 +72,35 @@ static void flush_events(void) } }
+static BOOL open_clipboard(HWND hwnd) +{ + DWORD start = GetTickCount(); + while (1) + { + BOOL ret = OpenClipboard(hwnd); + if (ret || GetLastError() != ERROR_ACCESS_DENIED) + return ret; + if (GetTickCount() - start > 100) + { + char classname[256]; + DWORD le = GetLastError(); + HWND clipwnd = GetOpenClipboardWindow(); + /* Provide a hint as to the source of interference: + * - The class name would typically be CLIPBRDWNDCLASS if the + * clipboard was opened by a Windows application using the + * ole32 API. + * - And it would be __wine_clipboard_manager if it was opened in + * response to a native application. + */ + GetClassNameA(clipwnd, classname, ARRAY_SIZE(classname)); + trace("%p (%s) opened the clipboard\n", clipwnd, classname); + SetLastError(le); + return ret; + } + Sleep(15); + } +} + static INT_PTR CALLBACK multi_edit_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam) { static int num_ok_commands = 0; @@ -2226,7 +2255,7 @@ static void test_espassword(void) ok(r == strlen(password), "Expected: %s, got len %ld\n", password, r); ok(strcmp(buffer, password) == 0, "expected %s, got %s\n", password, buffer);
- r = OpenClipboard(hwEdit); + r = open_clipboard(hwEdit); ok(r == TRUE, "expected %d, got %ld\n", TRUE, r); r = EmptyClipboard(); ok(r == TRUE, "expected %d, got %ld\n", TRUE, r); @@ -3199,7 +3228,7 @@ static void test_paste(void) strcpy(buffer, str); GlobalUnlock(hmem);
- r = OpenClipboard(hEdit); + r = open_clipboard(hEdit); ok(r == TRUE, "expected %d, got %d\n", TRUE, r); r = EmptyClipboard(); ok(r == TRUE, "expected %d, got %d\n", TRUE, r); @@ -3222,7 +3251,7 @@ static void test_paste(void) strcpy(buffer, str2); GlobalUnlock(hmem);
- r = OpenClipboard(hEdit); + r = open_clipboard(hEdit); ok(r == TRUE, "expected %d, got %d\n", TRUE, r); r = EmptyClipboard(); ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
From: Eric Pouech eric.pouech@gmail.com
There are cases in Windows10+ where the WM_PASTE message doesn't paste the content of the clipboard.
This appeared in testing: - almost always just after (for a couple of milliseconds) setting new content into the clipboard and closing it. - in some unrelated rare occasions (like once for 400 runs).
It looks like another (installed) process had opened the clipboard and forbids the paste command. As WM_PASTE doesn't return success/error status, workaround it by wrapping the WM_PASTE command into a helper, and retry when the clipboard's content hasn't been pasted.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53276 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53277
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/comctl32/tests/edit.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-)
diff --git a/dlls/comctl32/tests/edit.c b/dlls/comctl32/tests/edit.c index 00ef54dea01..9d90d14e2ec 100644 --- a/dlls/comctl32/tests/edit.c +++ b/dlls/comctl32/tests/edit.c @@ -3208,6 +3208,26 @@ static void test_EM_GETHANDLE(void) DestroyWindow(hEdit); }
+/* In Windows 10+, the WM_PASTE message isn't always successful. + * So retry in case of failure. + */ +#define check_paste(a, b) _check_paste(__LINE__, (a), (b)) +static void _check_paste(unsigned int line, HWND hedit, const char *content) +{ + /* only retry on windows platform */ + int tries = strcmp(winetest_platform, "wine") ? 3 : 1; + int len = 0; + + SendMessageA(hedit, WM_SETTEXT, 0, (LPARAM)""); + do + { + SendMessageA(hedit, WM_PASTE, 0, 0); + if ((len = SendMessageA(hedit, WM_GETTEXTLENGTH, 0, 0))) break; + Sleep(1); + } while (--tries > 0); + ok_(__FILE__, line)(len == strlen(content), "Unexpected len %u in edit\n", len); +} + static void test_paste(void) { static const char *str = "this is a simple text"; @@ -3215,7 +3235,7 @@ static void test_paste(void) HWND hEdit, hMultilineEdit; HANDLE hmem, hmem_ret; char *buffer; - int r, len; + int r;
hEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); hMultilineEdit = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE, 0); @@ -3238,10 +3258,7 @@ static void test_paste(void) ok(r == TRUE, "expected %d, got %d\n", TRUE, r);
/* Paste single line */ - SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)""); - r = SendMessageA(hEdit, WM_PASTE, 0, 0); - len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0); - ok(strlen(str) == len, "got %d\n", len); + check_paste(hEdit, str);
/* Prepare clipboard data with multiline text */ hmem = GlobalAlloc(GMEM_MOVEABLE, 255); @@ -3262,15 +3279,10 @@ static void test_paste(void)
/* Paste multiline text in singleline edit - should be cut */ SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)""); - r = SendMessageA(hEdit, WM_PASTE, 0, 0); - len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0); - ok(strlen("first line") == len, "got %d\n", len); + check_paste(hEdit, "first line");
/* Paste multiline text in multiline edit */ - SendMessageA(hMultilineEdit, WM_SETTEXT, 0, (LPARAM)""); - r = SendMessageA(hMultilineEdit, WM_PASTE, 0, 0); - len = SendMessageA(hMultilineEdit, WM_GETTEXTLENGTH, 0, 0); - ok(strlen(str2) == len, "got %d\n", len); + check_paste(hMultilineEdit, str2);
/* Cleanup */ DestroyWindow(hEdit);
This merge request was approved by Zhiyi Zhang.