This ensures all traces have the relevant context information, in particular the OpenClipboard() checks, and simplifies the ok() calls.
Signed-off-by: Francois Gouget fgouget@codeweavers.com --- dlls/user32/tests/clipboard.c | 36 +++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-)
diff --git a/dlls/user32/tests/clipboard.c b/dlls/user32/tests/clipboard.c index d75e8fc3c32..878b9c66427 100644 --- a/dlls/user32/tests/clipboard.c +++ b/dlls/user32/tests/clipboard.c @@ -2043,6 +2043,7 @@ static void test_string_data(void)
for (i = 0; i < ARRAY_SIZE(test_data); i++) { + winetest_push_context("%d", i); /* 1-byte Unicode strings crash on Win64 */ #ifdef _WIN64 if (!test_data[i].strA[0] && test_data[i].len < sizeof(WCHAR)) continue; @@ -2059,7 +2060,7 @@ static void test_string_data(void) memcpy( bufferA, test_data[i].strA, test_data[i].len ); bufferA[test_data[i].len - 1] = 0; ok( !memcmp( data, bufferA, test_data[i].len ), - "%u: wrong data %.*s\n", i, test_data[i].len, (char *)data ); + "wrong data %.*s\n", test_data[i].len, (char *)data ); } else { @@ -2068,12 +2069,13 @@ static void test_string_data(void) memcpy( bufferW, test_data[i].strW, test_data[i].len ); bufferW[(test_data[i].len + 1) / sizeof(WCHAR) - 1] = 0; ok( !memcmp( data, bufferW, test_data[i].len ), - "%u: wrong data %s\n", i, wine_dbgstr_wn( data, (test_data[i].len + 1) / sizeof(WCHAR) )); + "wrong data %s\n", wine_dbgstr_wn( data, (test_data[i].len + 1) / sizeof(WCHAR) )); } r = CloseClipboard(); ok( r, "gle %d\n", GetLastError() ); sprintf( cmd, "string_data %u", i ); run_process( cmd ); + winetest_pop_context(); } }
@@ -2085,53 +2087,55 @@ static void test_string_data_process( int i ) char bufferA[12]; WCHAR bufferW[12];
+ winetest_push_context("%d", i); r = OpenClipboard( 0 ); ok( r, "gle %d\n", GetLastError() ); if (test_data[i].strA[0]) { data = GetClipboardData( CF_TEXT ); - ok( data != 0, "%u: could not get data\n", i ); + ok( data != 0, "could not get data\n" ); len = GlobalSize( data ); - ok( len == test_data[i].len, "%u: wrong size %u / %u\n", i, len, test_data[i].len ); + ok( len == test_data[i].len, "wrong size %u / %u\n", len, test_data[i].len ); memcpy( bufferA, test_data[i].strA, test_data[i].len ); bufferA[test_data[i].len - 1] = 0; - ok( !memcmp( data, bufferA, len ), "%u: wrong data %.*s\n", i, len, (char *)data ); + ok( !memcmp( data, bufferA, len ), "wrong data %.*s\n", len, (char *)data ); data = GetClipboardData( CF_UNICODETEXT ); - ok( data != 0, "%u: could not get data\n", i ); + ok( data != 0, "could not get data\n" ); len = GlobalSize( data ); len2 = MultiByteToWideChar( CP_ACP, 0, bufferA, test_data[i].len, bufferW, ARRAY_SIZE(bufferW) ); - ok( len == len2 * sizeof(WCHAR), "%u: wrong size %u / %u\n", i, len, len2 ); - ok( !memcmp( data, bufferW, len ), "%u: wrong data %s\n", i, wine_dbgstr_wn( data, len2 )); + ok( len == len2 * sizeof(WCHAR), "wrong size %u / %u\n", len, len2 ); + ok( !memcmp( data, bufferW, len ), "wrong data %s\n", wine_dbgstr_wn( data, len2 )); } else { data = GetClipboardData( CF_UNICODETEXT ); - ok( data != 0, "%u: could not get data\n", i ); + ok( data != 0, "could not get data\n" ); len = GlobalSize( data ); - ok( len == test_data[i].len, "%u: wrong size %u / %u\n", i, len, test_data[i].len ); + ok( len == test_data[i].len, "wrong size %u / %u\n", len, test_data[i].len ); memcpy( bufferW, test_data[i].strW, test_data[i].len ); bufferW[(test_data[i].len + 1) / sizeof(WCHAR) - 1] = 0; ok( !memcmp( data, bufferW, len ), - "%u: wrong data %s\n", i, wine_dbgstr_wn( data, (len + 1) / sizeof(WCHAR) )); + "wrong data %s\n", wine_dbgstr_wn( data, (len + 1) / sizeof(WCHAR) )); data = GetClipboardData( CF_TEXT ); if (test_data[i].len >= sizeof(WCHAR)) { - ok( data != 0, "%u: could not get data\n", i ); + ok( data != 0, "could not get data\n" ); len = GlobalSize( data ); len2 = WideCharToMultiByte( CP_ACP, 0, bufferW, test_data[i].len / sizeof(WCHAR), bufferA, ARRAY_SIZE(bufferA), NULL, NULL ); bufferA[len2 - 1] = 0; - ok( len == len2, "%u: wrong size %u / %u\n", i, len, len2 ); - ok( !memcmp( data, bufferA, len ), "%u: wrong data %.*s\n", i, len, (char *)data ); + ok( len == len2, "wrong size %u / %u\n", len, len2 ); + ok( !memcmp( data, bufferA, len ), "wrong data %.*s\n", len, (char *)data ); } else { - ok( !data, "%u: got data for empty string\n", i ); - ok( IsClipboardFormatAvailable( CF_TEXT ), "%u: text not available\n", i ); + ok( !data, "got data for empty string\n" ); + ok( IsClipboardFormatAvailable( CF_TEXT ), "text not available\n" ); } } r = CloseClipboard(); ok( r, "gle %d\n", GetLastError() ); + winetest_pop_context(); }
START_TEST(clipboard)
Signed-off-by: Francois Gouget fgouget@codeweavers.com --- dlls/user32/tests/clipboard.c | 76 +++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 35 deletions(-)
diff --git a/dlls/user32/tests/clipboard.c b/dlls/user32/tests/clipboard.c index 878b9c66427..46fd8059805 100644 --- a/dlls/user32/tests/clipboard.c +++ b/dlls/user32/tests/clipboard.c @@ -714,10 +714,11 @@ static void test_synthesized(void)
for (i = 0; i < ARRAY_SIZE(tests); i++) { + winetest_push_context("%d", i); r = OpenClipboard(NULL); - ok(r, "%u: gle %d\n", i, GetLastError()); + ok(r, "gle %d\n", GetLastError()); r = EmptyClipboard(); - ok(r, "%u: gle %d\n", i, GetLastError()); + ok(r, "gle %d\n", GetLastError());
switch (tests[i].format) { @@ -744,45 +745,46 @@ static void test_synthesized(void) }
count = CountClipboardFormats(); - ok( count == 1, "%u: count %u\n", i, count ); + ok( count == 1, "count %u\n", count );
r = CloseClipboard(); - ok(r, "%u: gle %d\n", i, GetLastError()); + ok(r, "gle %d\n", GetLastError());
count = CountClipboardFormats(); for (j = 0; tests[i].expected[j]; j++) { r = IsClipboardFormatAvailable( tests[i].expected[j] ); - ok( r, "%u: %04x not available\n", i, tests[i].expected[j] ); + ok( r, "%04x not available\n", tests[i].expected[j] ); } - ok( count == j, "%u: count %u instead of %u\n", i, count, j ); + ok( count == j, "count %u instead of %u\n", count, j );
r = OpenClipboard( hwnd ); - ok(r, "%u: gle %d\n", i, GetLastError()); + ok(r, "gle %d\n", GetLastError()); cf = 0; for (j = 0; tests[i].expected[j]; j++) { + winetest_push_context("%d", j); cf = EnumClipboardFormats( cf ); - ok(cf == tests[i].expected[j], "%u.%u: got %04x instead of %04x\n", - i, j, cf, tests[i].expected[j] ); + ok(cf == tests[i].expected[j], "got %04x instead of %04x\n", + cf, tests[i].expected[j] ); if (cf != tests[i].expected[j]) break; old_seq = GetClipboardSequenceNumber(); data = GetClipboardData( cf ); ok(data != NULL || broken( tests[i].format == CF_DIBV5 && cf == CF_DIB ), /* >= Vista */ - "%u: couldn't get data, cf %04x err %d\n", i, cf, GetLastError()); + "couldn't get data, cf %04x err %d\n", cf, GetLastError()); seq = GetClipboardSequenceNumber(); - ok(seq == old_seq, "sequence changed (test %d %d)\n", i, cf); + ok(seq == old_seq, "sequence changed (test %d)\n", cf); switch (cf) { case CF_LOCALE: { UINT *ptr = GlobalLock( data ); DWORD layout = LOWORD( GetKeyboardLayout(0) ); - ok( GlobalSize( data ) == sizeof(*ptr), "%u: size %lu\n", i, GlobalSize( data )); + ok( GlobalSize( data ) == sizeof(*ptr), "size %lu\n", GlobalSize( data )); ok( *ptr == layout || broken( *ptr == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )), - "%u: CF_LOCALE %04x/%04x\n", i, *ptr, layout ); + "CF_LOCALE %04x/%04x\n", *ptr, layout ); GlobalUnlock( data ); break; } @@ -794,82 +796,86 @@ static void test_synthesized(void) ok( GlobalSize( data ) == 10 * sizeof(WCHAR), "wrong len %ld\n", GlobalSize( data )); break; } + winetest_pop_context(); } if (!tests[i].expected[j]) { cf = EnumClipboardFormats( cf ); - ok(cf == 0, "%u: cf %04x\n", i, cf); + ok(cf == 0, "cf %04x\n", cf); }
/* now with delayed rendering */
r = EmptyClipboard(); - ok(r, "%u: gle %d\n", i, GetLastError()); + ok(r, "gle %d\n", GetLastError());
rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); - ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered ); + ok( !rendered, "formats %08x have been rendered\n", rendered );
SetClipboardData( tests[i].format, 0 ); rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); - ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered ); + ok( !rendered, "formats %08x have been rendered\n", rendered );
count = CountClipboardFormats(); - ok( count == 1, "%u: count %u\n", i, count ); + ok( count == 1, "count %u\n", count );
r = CloseClipboard(); - ok(r, "%u: gle %d\n", i, GetLastError()); + ok(r, "gle %d\n", GetLastError()); rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); - ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered ); + ok( !rendered, "formats %08x have been rendered\n", rendered );
count = CountClipboardFormats(); for (j = 0; tests[i].expected[j]; j++) { r = IsClipboardFormatAvailable( tests[i].expected[j] ); - ok( r, "%u: %04x not available\n", i, tests[i].expected[j] ); + ok( r, "%04x not available\n", tests[i].expected[j] ); } - ok( count == j, "%u: count %u instead of %u\n", i, count, j ); + ok( count == j, "count %u instead of %u\n", count, j ); rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); - ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered ); + ok( !rendered, "formats %08x have been rendered\n", rendered );
r = OpenClipboard(NULL); - ok(r, "%u: gle %d\n", i, GetLastError()); + ok(r, "gle %d\n", GetLastError()); cf = 0; for (j = 0; tests[i].expected[j]; j++) { + winetest_push_context("%d", j); cf = EnumClipboardFormats( cf ); - ok(cf == tests[i].expected[j], "%u.%u: got %04x instead of %04x\n", - i, j, cf, tests[i].expected[j] ); + ok(cf == tests[i].expected[j], "got %04x instead of %04x\n", + cf, tests[i].expected[j] ); if (cf != tests[i].expected[j]) break; rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); - ok( !rendered, "%u.%u: formats %08x have been rendered\n", i, j, rendered ); + ok( !rendered, "formats %08x have been rendered\n", rendered ); data = GetClipboardData( cf ); rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); if (cf == CF_LOCALE) { - ok(data != NULL, "%u: CF_LOCALE no data\n", i); - ok( !rendered, "%u.%u: formats %08x have been rendered\n", i, j, rendered ); + ok(data != NULL, "CF_LOCALE no data\n"); + ok( !rendered, "formats %08x have been rendered\n", rendered ); } else { - ok(!data, "%u: format %04x got data %p\n", i, cf, data); + ok(!data, "format %04x got data %p\n", cf, data); ok( rendered == (1 << tests[i].format), - "%u.%u: formats %08x have been rendered\n", i, j, rendered ); + "formats %08x have been rendered\n", rendered ); /* try to render a second time */ data = GetClipboardData( cf ); rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); ok( rendered == (1 << tests[i].format), - "%u.%u: formats %08x have been rendered\n", i, j, rendered ); + "formats %08x have been rendered\n", rendered ); } + winetest_pop_context(); } if (!tests[i].expected[j]) { cf = EnumClipboardFormats( cf ); - ok(cf == 0, "%u: cf %04x\n", i, cf); + ok(cf == 0, "cf %04x\n", cf); } r = CloseClipboard(); - ok(r, "%u: gle %d\n", i, GetLastError()); + ok(r, "gle %d\n", GetLastError()); rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); - ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered ); + ok( !rendered, "formats %08x have been rendered\n", rendered ); + winetest_pop_context(); }
r = OpenClipboard(NULL);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=91762
Your paranoid android.
=== debiant2 (32 bit Arabic:Morocco report) ===
user32: clipboard.c:773: Test failed: 0: 2: couldn't get data, cf 0007 err 87 clipboard.c:793: Test failed: 0: 2: wrong len 0 clipboard.c:773: Test failed: 1: 2: couldn't get data, cf 0001 err 87 clipboard.c:793: Test failed: 1: 2: wrong len 0 clipboard.c:773: Test failed: 1: 3: couldn't get data, cf 000d err 87 clipboard.c:796: Test failed: 1: 3: wrong len 0 clipboard.c:773: Test failed: 2: 3: couldn't get data, cf 0007 err 87 clipboard.c:793: Test failed: 2: 3: wrong len 0
On 6/3/21 4:27 PM, Francois Gouget wrote:
@@ -744,45 +745,46 @@ static void test_synthesized(void) }
count = CountClipboardFormats();
ok( count == 1, "%u: count %u\n", i, count );
ok( count == 1, "count %u\n", count ); r = CloseClipboard();
ok(r, "%u: gle %d\n", i, GetLastError());
ok(r, "gle %d\n", GetLastError());
Not directly related, but I was thinking could maybe winetest call and print GetLastError automatically and consistently on failing tests?
It's done a lot, maybe not everywhere but sometimes it's missing and could be a useful information (although sometimes it's not, but it probably won't hurt?).
On 6/4/21 9:55 AM, Rémi Bernon wrote:
On 6/3/21 4:27 PM, Francois Gouget wrote:
@@ -744,45 +745,46 @@ static void test_synthesized(void) } count = CountClipboardFormats(); - ok( count == 1, "%u: count %u\n", i, count ); + ok( count == 1, "count %u\n", count ); r = CloseClipboard(); - ok(r, "%u: gle %d\n", i, GetLastError()); + ok(r, "gle %d\n", GetLastError());
Not directly related, but I was thinking could maybe winetest call and print GetLastError automatically and consistently on failing tests?
It's done a lot, maybe not everywhere but sometimes it's missing and could be a useful information (although sometimes it's not, but it probably won't hurt?).
And/or RtlGetLastNtStatus, if that's useful as well.
Applications using ole32's clipboard API (e.g. Radeon / QT5) end up monitoring the content of the clipboard and calling OpenClipboard() while user32:clipboard runs. This causes the test's own OpenClipboard() to fail. Similarly the KDE clipboard manager may query the Wine clipboard content while the test runs, causing winex11.drv to call OpenClipboard() with the same effect. So call OpenClipboard() again when it fails due to the clipboard already being open in another application.
Signed-off-by: Francois Gouget fgouget@codeweavers.com --- open_clipboard() traces the class of the window that opened the clipboard so one can confirm the interference comes from ole32 (CLIPBRDWNDCLASS) or winex11.drv (__wine_clipboard_manager). It would be even better to trace the corresponding executable name (and it's quite simple) but maybe that's taking it too far. Let me know of any adjustments there. I started with a loop of a mere 5x 10 ms but on my box in Wine that was sometimes insufficient. These settings seem to work ok. I guess the loop count and delays can be adjusted as long as other threads have about 300 ms to release the clipboard. --- dlls/user32/tests/clipboard.c | 104 ++++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 41 deletions(-)
diff --git a/dlls/user32/tests/clipboard.c b/dlls/user32/tests/clipboard.c index 46fd8059805..6c500e361ab 100644 --- a/dlls/user32/tests/clipboard.c +++ b/dlls/user32/tests/clipboard.c @@ -33,10 +33,32 @@ static BOOL (WINAPI *pGetUpdatedClipboardFormats)( UINT *formats, UINT count, UI static int thread_from_line; static char *argv0;
+static BOOL open_clipboard(HWND hwnd) +{ + int i = 20; + while (1) + { + BOOL ret = OpenClipboard(hwnd); + if (ret || GetLastError() != ERROR_ACCESS_DENIED) + return ret; + if (!--i) + { + char classname[256]; + DWORD le = GetLastError(); + HWND clipwnd = GetOpenClipboardWindow(); + GetClassNameA(clipwnd, classname, ARRAY_SIZE(classname)); + trace("%p (%s) opened the clipboard\n", clipwnd, classname); + SetLastError(le); + return ret; + } + Sleep(15); + } +} + static DWORD WINAPI open_clipboard_thread(LPVOID arg) { HWND hWnd = arg; - ok(OpenClipboard(hWnd), "%u: OpenClipboard failed\n", thread_from_line); + ok(open_clipboard(hWnd), "%u: OpenClipboard failed\n", thread_from_line); return 0; }
@@ -52,7 +74,7 @@ static DWORD WINAPI empty_clipboard_thread(LPVOID arg) static DWORD WINAPI open_and_empty_clipboard_thread(LPVOID arg) { HWND hWnd = arg; - ok(OpenClipboard(hWnd), "%u: OpenClipboard failed\n", thread_from_line); + ok(open_clipboard(hWnd), "%u: OpenClipboard failed\n", thread_from_line); ok(EmptyClipboard(), "%u: EmptyClipboard failed\n", thread_from_line ); return 0; } @@ -60,7 +82,7 @@ static DWORD WINAPI open_and_empty_clipboard_thread(LPVOID arg) static DWORD WINAPI open_and_empty_clipboard_win_thread(LPVOID arg) { HWND hwnd = CreateWindowA( "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL ); - ok(OpenClipboard(hwnd), "%u: OpenClipboard failed\n", thread_from_line); + ok(open_clipboard(hwnd), "%u: OpenClipboard failed\n", thread_from_line); ok(EmptyClipboard(), "%u: EmptyClipboard failed\n", thread_from_line ); return 0; } @@ -126,7 +148,7 @@ static void grab_clipboard_process( int arg ) BOOL ret;
SetLastError( 0xdeadbeef ); - ret = OpenClipboard( 0 ); + ret = open_clipboard( 0 ); ok( ret, "OpenClipboard failed\n" ); ret = EmptyClipboard(); ok( ret, "EmptyClipboard failed\n" ); @@ -243,14 +265,14 @@ static void test_ClipboardOwner(void) ok(GetLastError() == ERROR_CLIPBOARD_NOT_OPEN || broken(GetLastError() == 0xdeadbeef), /* wow64 */ "wrong error %u\n", GetLastError());
- ok(OpenClipboard(0), "OpenClipboard failed\n"); + ok(open_clipboard(0), "OpenClipboard failed\n"); ok(!GetClipboardOwner(), "clipboard should still be not owned\n"); ok(!OpenClipboard(hWnd1), "OpenClipboard should fail since clipboard already opened\n"); - ok(OpenClipboard(0), "OpenClipboard again failed\n"); + ok(open_clipboard(0), "OpenClipboard again failed\n"); ret = CloseClipboard(); ok( ret, "CloseClipboard error %d\n", GetLastError());
- ok(OpenClipboard(hWnd1), "OpenClipboard failed\n"); + ok(open_clipboard(hWnd1), "OpenClipboard failed\n"); run_thread( open_clipboard_thread, hWnd1, __LINE__ ); run_thread( empty_clipboard_thread, 0, __LINE__ ); run_thread( set_clipboard_data_thread, hWnd1, __LINE__ ); @@ -258,7 +280,7 @@ static void test_ClipboardOwner(void) ok( !GetClipboardData( CF_WAVE ), "CF_WAVE data available\n" ); run_process( "set_clipboard_data 0" ); ok(!CloseClipboard(), "CloseClipboard should fail if clipboard wasn't open\n"); - ok(OpenClipboard(hWnd1), "OpenClipboard failed\n"); + ok(open_clipboard(hWnd1), "OpenClipboard failed\n");
SetLastError(0xdeadbeef); ret = OpenClipboard(hWnd2); @@ -286,7 +308,7 @@ static void test_ClipboardOwner(void) ok(GetClipboardOwner() == hWnd1, "clipboard should still be owned\n");
/* any window will do, even from a different process */ - ret = OpenClipboard( GetDesktopWindow() ); + ret = open_clipboard( GetDesktopWindow() ); ok( ret, "OpenClipboard error %d\n", GetLastError()); ret = EmptyClipboard(); ok( ret, "EmptyClipboard error %d\n", GetLastError()); @@ -299,7 +321,7 @@ static void test_ClipboardOwner(void) ret = CloseClipboard(); ok( ret, "CloseClipboard error %d\n", GetLastError());
- ret = OpenClipboard( hWnd1 ); + ret = open_clipboard( hWnd1 ); ok( ret, "OpenClipboard error %d\n", GetLastError()); ret = EmptyClipboard(); ok( ret, "EmptyClipboard error %d\n", GetLastError()); @@ -326,7 +348,7 @@ static void test_ClipboardOwner(void) ok( !ret, "CloseClipboard succeeded\n" ); ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "wrong error %u\n", GetLastError() );
- ret = OpenClipboard( 0 ); + ret = open_clipboard( 0 ); ok( ret, "OpenClipboard error %d\n", GetLastError()); run_thread( set_clipboard_data_thread, 0, __LINE__ ); ok( IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE not available\n" ); @@ -339,7 +361,7 @@ static void test_ClipboardOwner(void) ok( !GetOpenClipboardWindow(), "wrong open window %p\n", GetOpenClipboardWindow() ); ok( !GetClipboardOwner(), "wrong owner window %p\n", GetClipboardOwner() );
- ret = OpenClipboard( 0 ); + ret = open_clipboard( 0 ); ok( ret, "OpenClipboard error %d\n", GetLastError()); run_thread( set_clipboard_data_thread, 0, __LINE__ ); ok( IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE not available\n" ); @@ -429,7 +451,7 @@ static void test_RegisterClipboardFormatA(void) trace("%04x: %s\n", format_id, len ? buf : ""); }
- ret = OpenClipboard(0); + ret = open_clipboard(0); ok( ret, "OpenClipboard error %d\n", GetLastError());
/* try some invalid/unregistered formats */ @@ -611,7 +633,7 @@ static void test_synthesized(void) htext = create_textA(); emf = create_emf();
- r = OpenClipboard(NULL); + r = open_clipboard(NULL); ok(r, "gle %d\n", GetLastError()); r = EmptyClipboard(); ok(r, "gle %d\n", GetLastError()); @@ -637,7 +659,7 @@ static void test_synthesized(void) r = IsClipboardFormatAvailable( CF_METAFILEPICT ); ok( r, "CF_METAFILEPICT not available err %d\n", GetLastError());
- r = OpenClipboard(NULL); + r = open_clipboard(NULL); ok(r, "gle %d\n", GetLastError()); cf = EnumClipboardFormats(0); ok(cf == CF_TEXT, "cf %08x\n", cf); @@ -679,7 +701,7 @@ static void test_synthesized(void) r = CloseClipboard(); ok(r, "gle %d\n", GetLastError());
- r = OpenClipboard( NULL ); + r = open_clipboard( NULL ); ok(r, "gle %d\n", GetLastError()); SetLastError( 0xdeadbeef ); cf = EnumClipboardFormats(0); @@ -715,7 +737,7 @@ static void test_synthesized(void) for (i = 0; i < ARRAY_SIZE(tests); i++) { winetest_push_context("%d", i); - r = OpenClipboard(NULL); + r = open_clipboard(NULL); ok(r, "gle %d\n", GetLastError()); r = EmptyClipboard(); ok(r, "gle %d\n", GetLastError()); @@ -758,7 +780,7 @@ static void test_synthesized(void) } ok( count == j, "count %u instead of %u\n", count, j );
- r = OpenClipboard( hwnd ); + r = open_clipboard( hwnd ); ok(r, "gle %d\n", GetLastError()); cf = 0; for (j = 0; tests[i].expected[j]; j++) @@ -834,7 +856,7 @@ static void test_synthesized(void) rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); ok( !rendered, "formats %08x have been rendered\n", rendered );
- r = OpenClipboard(NULL); + r = open_clipboard(NULL); ok(r, "gle %d\n", GetLastError()); cf = 0; for (j = 0; tests[i].expected[j]; j++) @@ -878,7 +900,7 @@ static void test_synthesized(void) winetest_pop_context(); }
- r = OpenClipboard(NULL); + r = open_clipboard(NULL); ok(r, "gle %d\n", GetLastError()); r = EmptyClipboard(); ok(r, "gle %d\n", GetLastError()); @@ -997,7 +1019,7 @@ static void get_clipboard_data_process(void) HANDLE data; BOOL r;
- r = OpenClipboard(0); + r = open_clipboard(0); ok(r, "OpenClipboard failed: %d\n", GetLastError()); data = GetClipboardData( CF_UNICODETEXT ); ok( data != NULL, "GetClipboardData failed: %d\n", GetLastError()); @@ -1093,7 +1115,7 @@ static DWORD WINAPI clipboard_thread(void *param) ok( !r, "OpenClipboard succeeded\n" ); ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() );
- r = OpenClipboard(win); + r = open_clipboard(win); ok(r, "OpenClipboard failed: %d\n", GetLastError());
check_messages(win, 0, 0, 0, 0, 0); @@ -1134,7 +1156,7 @@ static DWORD WINAPI clipboard_thread(void *param)
check_messages(win, 2, 1, 1, 0, 0);
- r = OpenClipboard(win); + r = open_clipboard(win); ok(r, "OpenClipboard failed: %d\n", GetLastError());
check_messages(win, 0, 0, 0, 0, 0); @@ -1164,7 +1186,7 @@ static DWORD WINAPI clipboard_thread(void *param) /* no synthesized format, so CloseClipboard doesn't change the sequence */ check_messages(win, 0, 1, 1, 0, 0);
- r = OpenClipboard(win); + r = open_clipboard(win); ok(r, "OpenClipboard failed: %d\n", GetLastError()); r = CloseClipboard(); ok(r, "CloseClipboard failed: %d\n", GetLastError()); @@ -1172,7 +1194,7 @@ static DWORD WINAPI clipboard_thread(void *param) check_messages(win, 0, 0, 0, 0, 0);
formats = CountClipboardFormats(); - r = OpenClipboard(0); + r = open_clipboard(0); ok(r, "OpenClipboard failed: %d\n", GetLastError()); r = EmptyClipboard(); ok(r, "EmptyClipboard failed: %d\n", GetLastError()); @@ -1183,7 +1205,7 @@ static DWORD WINAPI clipboard_thread(void *param) count = SendMessageA( win, WM_USER+5, 0, 0 ); ok( count == formats, "wrong format count %u on WM_DESTROYCLIPBOARD\n", count );
- r = OpenClipboard(win); + r = open_clipboard(win); ok(r, "OpenClipboard failed: %d\n", GetLastError()); SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_FIXED, 1 )); check_messages(win, 1, 0, 0, 0, 0); @@ -1206,7 +1228,7 @@ static DWORD WINAPI clipboard_thread(void *param) } check_messages(win, 1, 1, 1, 0, 0);
- r = OpenClipboard(0); + r = open_clipboard(0); ok(r, "OpenClipboard failed: %d\n", GetLastError()); SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_FIXED, 1 )); check_messages(win, 1, 0, 0, 0, 0); @@ -1229,7 +1251,7 @@ static DWORD WINAPI clipboard_thread(void *param) } check_messages(win, 2, 1, 1, 0, 0);
- r = OpenClipboard(0); + r = open_clipboard(0); ok(r, "OpenClipboard failed: %d\n", GetLastError()); SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_FIXED, 1 )); check_messages(win, 1, 0, 0, 0, 0); @@ -1243,7 +1265,7 @@ static DWORD WINAPI clipboard_thread(void *param)
if (cross_thread) { - r = OpenClipboard( win ); + r = open_clipboard( win ); ok(r, "OpenClipboard failed: %d\n", GetLastError()); r = EmptyClipboard(); ok(r, "EmptyClipboard failed: %d\n", GetLastError()); @@ -1387,7 +1409,7 @@ static void test_handles( HWND hwnd ) /* discarded handles can't be GlobalLock'ed */ ok( is_freed( empty_moveable ), "expected free mem %p\n", empty_moveable );
- r = OpenClipboard( hwnd ); + r = open_clipboard( hwnd ); ok( r, "gle %d\n", GetLastError() ); r = EmptyClipboard(); ok( r, "gle %d\n", GetLastError() ); @@ -1505,7 +1527,7 @@ static void test_handles( HWND hwnd ) ok( is_moveable( hmoveable ), "expected moveable mem %p\n", hmoveable ); ok( is_fixed( empty_fixed ), "expected fixed mem %p\n", empty_fixed );
- r = OpenClipboard( hwnd ); + r = open_clipboard( hwnd ); ok( r, "gle %d\n", GetLastError() );
/* and now they are freed, unless we are the owner */ @@ -1630,7 +1652,7 @@ static DWORD WINAPI test_handles_thread2( void *arg ) HANDLE h; char *ptr;
- r = OpenClipboard( 0 ); + r = open_clipboard( 0 ); ok( r, "gle %d\n", GetLastError() ); h = GetClipboardData( CF_TEXT ); ok( is_moveable( h ), "expected moveable mem %p\n", h ); @@ -1685,7 +1707,7 @@ static void test_handles_process( const char *str ) BYTE buffer[1024];
format_id = RegisterClipboardFormatA( "my_cool_clipboard_format" ); - r = OpenClipboard( 0 ); + r = open_clipboard( 0 ); ok( r, "gle %d\n", GetLastError() ); h = GetClipboardData( CF_TEXT ); ok( is_fixed( h ), "expected fixed mem %p\n", h ); @@ -1774,7 +1796,7 @@ static void test_handles_process_dib( const char *str ) BOOL r; HANDLE h;
- r = OpenClipboard( 0 ); + r = open_clipboard( 0 ); ok( r, "gle %d\n", GetLastError() ); h = GetClipboardData( CF_BITMAP ); ok( !GetObjectType( h ), "expected invalid object %p\n", h ); @@ -1803,7 +1825,7 @@ static void test_data_handles(void) bitmap2 = CreateBitmap( 10, 10, 1, 1, NULL ); palette = CreatePalette( &logpalette );
- r = OpenClipboard( hwnd ); + r = open_clipboard( hwnd ); ok( r, "gle %d\n", GetLastError() ); r = EmptyClipboard(); ok( r, "gle %d\n", GetLastError() ); @@ -1839,7 +1861,7 @@ static void test_data_handles(void) run_thread( test_handles_thread2, 0, __LINE__ ); run_process( "handles test" );
- r = OpenClipboard( hwnd ); + r = open_clipboard( hwnd ); ok( r, "gle %d\n", GetLastError() ); h = GetClipboardData( CF_TEXT ); ok( is_moveable( h ), "expected moveable mem %p\n", h ); @@ -1883,7 +1905,7 @@ static void test_data_handles(void) bmi.bmiHeader.biBitCount = 32; bitmap = CreateDIBSection( 0, &bmi, DIB_RGB_COLORS, &bits, 0, 0 );
- r = OpenClipboard( hwnd ); + r = open_clipboard( hwnd ); ok( r, "gle %d\n", GetLastError() ); r = EmptyClipboard(); ok( r, "gle %d\n", GetLastError() ); @@ -1895,7 +1917,7 @@ static void test_data_handles(void)
run_process( "handles_dib dummy" );
- r = OpenClipboard( hwnd ); + r = open_clipboard( hwnd ); ok( r, "gle %d\n", GetLastError() ); ok( GetObjectType( bitmap ) == OBJ_BITMAP, "expected bitmap %p\n", bitmap ); r = EmptyClipboard(); @@ -1937,7 +1959,7 @@ static void test_GetUpdatedClipboardFormats(void) ok( r, "gle %d\n", GetLastError() ); ok( !count, "wrong count %u\n", count );
- r = OpenClipboard( 0 ); + r = open_clipboard( 0 ); ok( r, "gle %d\n", GetLastError() ); r = EmptyClipboard(); ok( r, "gle %d\n", GetLastError() ); @@ -2054,7 +2076,7 @@ static void test_string_data(void) #ifdef _WIN64 if (!test_data[i].strA[0] && test_data[i].len < sizeof(WCHAR)) continue; #endif - r = OpenClipboard( 0 ); + r = open_clipboard( 0 ); ok( r, "gle %d\n", GetLastError() ); r = EmptyClipboard(); ok( r, "gle %d\n", GetLastError() ); @@ -2094,7 +2116,7 @@ static void test_string_data_process( int i ) WCHAR bufferW[12];
winetest_push_context("%d", i); - r = OpenClipboard( 0 ); + r = open_clipboard( 0 ); ok( r, "gle %d\n", GetLastError() ); if (test_data[i].strA[0]) {
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=91763
Your paranoid android.
=== debiant2 (32 bit Arabic:Morocco report) ===
user32: clipboard.c:795: Test failed: 0: 2: couldn't get data, cf 0007 err 87 clipboard.c:815: Test failed: 0: 2: wrong len 0 clipboard.c:795: Test failed: 1: 2: couldn't get data, cf 0001 err 87 clipboard.c:815: Test failed: 1: 2: wrong len 0 clipboard.c:795: Test failed: 1: 3: couldn't get data, cf 000d err 87 clipboard.c:818: Test failed: 1: 3: wrong len 0 clipboard.c:795: Test failed: 2: 3: couldn't get data, cf 0007 err 87 clipboard.c:815: Test failed: 2: 3: wrong len 0
On Thu, 3 Jun 2021, Francois Gouget wrote: [...]
I started with a loop of a mere 5x 10 ms but on my box in Wine that was sometimes insufficient. These settings seem to work ok. I guess the loop count and delays can be adjusted as long as other threads have about 300 ms to release the clipboard.
Actually there is a race condition that can lead to a deadlock so there is no point increasing the loop count.
Here is what happens:
1. test: - test_synthesized() calls OpenClipboard(temp hwnd) (l760) - Places some data in the clipboard for delayed rendering - CloseClipboard()
2. winex11: - Receives: request for selection "CLIPBOARD" target "TARGETS" prop "_QT_SELECTION" - X11DRV_SelectionRequest() calls export_selection() - Which calls OpenClipboard() - And then GetClipboardData() which sends a WM_RENDERFORMAT message to the test window.
3. test: - Calls OpenClipboard()
So: - The test is stuck in OpenClipboard() not processing the window messages. - winex11.drv will only release the clipboard once it has received a WM_RENDERFORMAT reply.
This just does not happen on Windows (even with Radeon).
But I think there are more issues with this test. For instance:
# set up delayed rendering 806 r = EmptyClipboard(); 812 SetClipboardData( tests[i].format, 0 );
819 r = CloseClipboard(); 821 rendered = SendMessageA( hwnd, WM_USER, 0, 0 ); 822 ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered );
I think there is no garantee that winex11.drv will not send a WM_RENDERFORMAT message between lines 819 and 821 which would cause rendered to be true.
Just like OpenClipboard(), GetOpenClipboardWindow() can get interference from other applications.
Signed-off-by: Francois Gouget fgouget@codeweavers.com --- dlls/user32/tests/clipboard.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/dlls/user32/tests/clipboard.c b/dlls/user32/tests/clipboard.c index 6c500e361ab..9568694596f 100644 --- a/dlls/user32/tests/clipboard.c +++ b/dlls/user32/tests/clipboard.c @@ -55,6 +55,26 @@ static BOOL open_clipboard(HWND hwnd) } }
+static BOOL has_no_open_wnd(void) +{ + int i = 20; + while (1) + { + HWND clipwnd = GetOpenClipboardWindow(); + if (!clipwnd) return TRUE; + if (!--i) + { + char classname[256]; + DWORD le = GetLastError(); + GetClassNameA(clipwnd, classname, ARRAY_SIZE(classname)); + trace("%p (%s) opened the clipboard\n", clipwnd, classname); + SetLastError(le); + return FALSE; + } + Sleep(15); + } +} + static DWORD WINAPI open_clipboard_thread(LPVOID arg) { HWND hWnd = arg; @@ -340,7 +360,7 @@ static void test_ClipboardOwner(void) SetLastError(0xdeadbeef); ok(!GetClipboardOwner() && GetLastError() == 0xdeadbeef, "clipboard should not be owned\n"); ok(!GetClipboardViewer() && GetLastError() == 0xdeadbeef, "viewer still exists\n"); - ok(!GetOpenClipboardWindow() && GetLastError() == 0xdeadbeef, "clipboard should not be open\n"); + ok( has_no_open_wnd() && GetLastError() == 0xdeadbeef, "clipboard should not be open\n"); ok( !IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE available\n" );
SetLastError( 0xdeadbeef ); @@ -358,7 +378,7 @@ static void test_ClipboardOwner(void) ok( ret, "CloseClipboard error %d\n", GetLastError());
run_thread( open_and_empty_clipboard_thread, 0, __LINE__ ); - ok( !GetOpenClipboardWindow(), "wrong open window %p\n", GetOpenClipboardWindow() ); + ok( has_no_open_wnd(), "wrong open window\n" ); ok( !GetClipboardOwner(), "wrong owner window %p\n", GetClipboardOwner() );
ret = open_clipboard( 0 ); @@ -379,12 +399,12 @@ static void test_ClipboardOwner(void) ok( !IsClipboardFormatAvailable( CF_WAVE ), "SetClipboardData succeeded\n" );
run_thread( open_and_empty_clipboard_thread, GetDesktopWindow(), __LINE__ ); - ok( !GetOpenClipboardWindow(), "wrong open window %p\n", GetOpenClipboardWindow() ); + ok( has_no_open_wnd(), "wrong open window\n" ); ok( GetClipboardOwner() == GetDesktopWindow(), "wrong owner window %p / %p\n", GetClipboardOwner(), GetDesktopWindow() );
run_thread( open_and_empty_clipboard_win_thread, 0, __LINE__ ); - ok( !GetOpenClipboardWindow(), "wrong open window %p\n", GetOpenClipboardWindow() ); + ok( has_no_open_wnd(), "wrong open window\n" ); ok( !GetClipboardOwner(), "wrong owner window %p\n", GetClipboardOwner() ); }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=91764
Your paranoid android.
=== debiant2 (32 bit Arabic:Morocco report) ===
user32: clipboard.c:815: Test failed: 0: 2: couldn't get data, cf 0007 err 87 clipboard.c:835: Test failed: 0: 2: wrong len 0 clipboard.c:815: Test failed: 1: 2: couldn't get data, cf 0001 err 87 clipboard.c:835: Test failed: 1: 2: wrong len 0 clipboard.c:815: Test failed: 1: 3: couldn't get data, cf 000d err 87 clipboard.c:838: Test failed: 1: 3: wrong len 0 clipboard.c:815: Test failed: 2: 3: couldn't get data, cf 0007 err 87 clipboard.c:835: Test failed: 2: 3: wrong len 0
Patches 1 and 2 are wrong because the tests use break and continue in the loops :-(
I'll resubmit the series.