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() calls 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. If opening the clipboard still fails, trace who opened the clipboard, particularly the window class name to help identify the source of interference.
Signed-off-by: Francois Gouget fgouget@codeweavers.com --- This patchset should fix all the failures on cw-rx460 and cw-gtx560. It will also fix most failures in Wine + KDE. --- dlls/user32/tests/clipboard.c | 111 +++++++++++++++++++++------------- 1 file changed, 70 insertions(+), 41 deletions(-)
diff --git a/dlls/user32/tests/clipboard.c b/dlls/user32/tests/clipboard.c index d4389f40a46..b2075c128c2 100644 --- a/dlls/user32/tests/clipboard.c +++ b/dlls/user32/tests/clipboard.c @@ -33,10 +33,39 @@ static BOOL (WINAPI *pGetUpdatedClipboardFormats)( UINT *formats, UINT count, UI static int thread_from_line; static char *argv0;
+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 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 +81,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 +89,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 +155,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 +272,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 +287,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 +315,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 +328,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 +355,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 +368,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 +458,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 +640,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 +666,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 +708,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 +744,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 +787,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++) @@ -838,7 +867,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++) @@ -886,7 +915,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()); @@ -1005,7 +1034,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()); @@ -1101,7 +1130,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); @@ -1142,7 +1171,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); @@ -1172,7 +1201,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()); @@ -1180,7 +1209,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()); @@ -1191,7 +1220,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); @@ -1214,7 +1243,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); @@ -1237,7 +1266,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); @@ -1251,7 +1280,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()); @@ -1395,7 +1424,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() ); @@ -1513,7 +1542,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 */ @@ -1638,7 +1667,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 ); @@ -1693,7 +1722,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 ); @@ -1782,7 +1811,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 ); @@ -1811,7 +1840,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() ); @@ -1847,7 +1876,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 ); @@ -1891,7 +1920,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() ); @@ -1903,7 +1932,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(); @@ -1945,7 +1974,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() ); @@ -2062,7 +2091,7 @@ static void test_string_data(void) if (!test_data[i].strA[0] && test_data[i].len < sizeof(WCHAR)) continue; #endif winetest_push_context("%d", i); - r = OpenClipboard( 0 ); + r = open_clipboard( 0 ); ok( r, "gle %d\n", GetLastError() ); r = EmptyClipboard(); ok( r, "gle %d\n", GetLastError() ); @@ -2102,7 +2131,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]) {