From: Aaron Yourk <ayourk@gmail.com> The OLE clipboard caches a per-process window handle. When the STA thread that created this window terminates, the window is destroyed but the stale handle remains cached. Subsequent OleSetClipboard calls use this stale handle, causing OpenClipboard to fail with CLIPBRD_E_CANT_OPEN. Check whether the cached window is still valid using IsWindow() before returning it. If the window has been destroyed, clear the cache so a fresh window is created on the current thread. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59519 --- dlls/ole32/clipboard.c | 3 +++ dlls/ole32/tests/clipboard.c | 9 ++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/dlls/ole32/clipboard.c b/dlls/ole32/clipboard.c index c54608985fb..749dd03c3e6 100644 --- a/dlls/ole32/clipboard.c +++ b/dlls/ole32/clipboard.c @@ -1899,6 +1899,9 @@ static HWND create_clipbrd_window(void); */ static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd) { + if ( clipbrd->window && !IsWindow(clipbrd->window) ) + clipbrd->window = NULL; + if ( !clipbrd->window ) clipbrd->window = create_clipbrd_window(); diff --git a/dlls/ole32/tests/clipboard.c b/dlls/ole32/tests/clipboard.c index dedf23f629c..6b10400af5a 100644 --- a/dlls/ole32/tests/clipboard.c +++ b/dlls/ole32/tests/clipboard.c @@ -1990,9 +1990,8 @@ static void test_sta_clipboard_reuse(void) } CloseClipboard(); - /* Second STA thread sets clipboard to "second". The first thread's - OLE clipboard window has been destroyed, but Wine caches the stale - HWND and the second OleSetClipboard fails with CLIPBRD_E_CANT_OPEN. */ + /* Regression test: second STA thread should be able to set the + clipboard after the first thread's clipboard window is destroyed. */ data.text = "second"; data.hr_set = E_FAIL; thread = CreateThread(NULL, 0, sta_clipboard_set_thread, &data, 0, NULL); @@ -2000,7 +1999,7 @@ static void test_sta_clipboard_reuse(void) ret = WaitForSingleObject(thread, 5000); ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", ret); CloseHandle(thread); - todo_wine ok(data.hr_set == S_OK, "second OleSetClipboard returned %#lx\n", data.hr_set); + ok(data.hr_set == S_OK, "second OleSetClipboard returned %#lx\n", data.hr_set); ok(OpenClipboard(NULL), "OpenClipboard failed\n"); hdata = GetClipboardData(CF_TEXT); @@ -2008,7 +2007,7 @@ static void test_sta_clipboard_reuse(void) if (hdata) { text = GlobalLock(hdata); - todo_wine ok(!strcmp(text, "second"), "expected \"second\", got \"%s\"\n", text); + ok(!strcmp(text, "second"), "expected \"second\", got \"%s\"\n", text); GlobalUnlock(hdata); } CloseClipboard(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10889