diff options
-rw-r--r-- | dtrans/source/win32/clipb/MtaOleClipb.cxx | 102 | ||||
-rw-r--r-- | dtrans/source/win32/clipb/MtaOleClipb.hxx | 1 |
2 files changed, 90 insertions, 13 deletions
diff --git a/dtrans/source/win32/clipb/MtaOleClipb.cxx b/dtrans/source/win32/clipb/MtaOleClipb.cxx index 02a5f309aa14..ac3dc68083e1 100644 --- a/dtrans/source/win32/clipb/MtaOleClipb.cxx +++ b/dtrans/source/win32/clipb/MtaOleClipb.cxx @@ -62,11 +62,72 @@ namespace /* private */ const sal_uInt32 MAX_WAITTIME = 10000; // msec const sal_uInt32 MAX_WAIT_SHUTDOWN = 10000; // msec - const bool MANUAL_RESET = true; - const bool INIT_NONSIGNALED = false; + const BOOL MANUAL_RESET = TRUE; + const BOOL INIT_NONSIGNALED = FALSE; + + /* Cannot use osl conditions because they are blocking + without waking up on messages sent by another thread + this leads to deadlocks because we are blocking the + communication between inter-thread marshalled COM + pointers. + COM Proxy-Stub communication uses SendMessages for + synchronization purposes. + */ + class Win32Condition + { + public: + Win32Condition() = default; + + ~Win32Condition() { CloseHandle(m_hEvent); } + + // wait infinite for own event (or abort event) be signaled + // leave messages sent through + bool wait(HANDLE hEvtAbort) + { + const HANDLE hWaitArray[2] = { m_hEvent, hEvtAbort }; + while (true) + { + DWORD dwResult + = MsgWaitForMultipleObjects(2, hWaitArray, FALSE, INFINITE, QS_SENDMESSAGE); + + switch (dwResult) + { + case WAIT_OBJECT_0: // wait successful + return true; + + case WAIT_OBJECT_0 + 1: // wait aborted + return false; + + case WAIT_OBJECT_0 + 2: + { + /* PeekMessage processes all messages in the SendMessage + queue that's what we want, messages from the PostMessage + queue stay untouched */ + MSG msg; + PeekMessageW(&msg, nullptr, 0, 0, PM_NOREMOVE); + + break; + } + } + } + } + + // set the event + void set() { SetEvent(m_hEvent); } + + private: + HANDLE m_hEvent = CreateEventW(nullptr, MANUAL_RESET, INIT_NONSIGNALED, nullptr); + + // prevent copy/assignment + Win32Condition(const Win32Condition&) = delete; + Win32Condition& operator=(const Win32Condition&) = delete; + }; + + // we use one condition for every request struct MsgCtx { + Win32Condition aCondition; HRESULT hr; }; @@ -159,6 +220,8 @@ CMtaOleClipboard::CMtaOleClipboard( ) : m_uOleThreadId( 0 ), m_hEvtThrdReady( nullptr ), m_hwndMtaOleReqWnd( nullptr ), + // signals that the window is destroyed - to stop waiting any winproc result + m_hEvtWndDisposed(CreateEventW(nullptr, MANUAL_RESET, INIT_NONSIGNALED, nullptr)), m_MtaOleReqWndClassAtom( 0 ), m_pfncClipViewerCallback( nullptr ), m_bRunClipboardNotifierThread( true ), @@ -170,6 +233,7 @@ CMtaOleClipboard::CMtaOleClipboard( ) : m_hEvtThrdReady = CreateEventW( nullptr, MANUAL_RESET, INIT_NONSIGNALED, nullptr ); OSL_ASSERT( nullptr != m_hEvtThrdReady ); + SAL_WARN_IF(!m_hEvtWndDisposed, "dtrans", "CreateEventW failed: m_hEvtWndDisposed is nullptr"); s_theMtaOleClipboardInst = this; @@ -253,11 +317,10 @@ HRESULT CMtaOleClipboard::flushClipboard( ) MsgCtx aMsgCtx; - sendMessage( MSG_FLUSHCLIPBOARD, - static_cast< WPARAM >( 0 ), - reinterpret_cast< LPARAM >( &aMsgCtx ) ); + const bool bWaitSuccess = postMessage(MSG_FLUSHCLIPBOARD, 0, reinterpret_cast<LPARAM>(&aMsgCtx)) + && aMsgCtx.aCondition.wait(m_hEvtWndDisposed); - return aMsgCtx.hr; + return bWaitSuccess ? aMsgCtx.hr : E_ABORT; } HRESULT CMtaOleClipboard::getClipboard( IDataObject** ppIDataObject ) @@ -279,11 +342,11 @@ HRESULT CMtaOleClipboard::getClipboard( IDataObject** ppIDataObject ) MsgCtx aMsgCtx; - sendMessage( MSG_GETCLIPBOARD, - reinterpret_cast< WPARAM >( &lpStream ), - reinterpret_cast< LPARAM >( &aMsgCtx ) ); + const bool bWaitSuccess = postMessage(MSG_GETCLIPBOARD, reinterpret_cast<WPARAM>(&lpStream), + reinterpret_cast<LPARAM>(&aMsgCtx)) + && aMsgCtx.aCondition.wait(m_hEvtWndDisposed); - HRESULT hr = aMsgCtx.hr; + HRESULT hr = bWaitSuccess ? aMsgCtx.hr : E_ABORT; if ( SUCCEEDED( hr ) ) { @@ -342,7 +405,11 @@ bool CMtaOleClipboard::registerClipViewer( LPFNC_CLIPVIEWER_CALLBACK_t pfncClipV OSL_ENSURE( GetCurrentThreadId( ) != m_uOleThreadId, "registerClipViewer from within the OleThread called" ); - sendMessage(MSG_REGCLIPVIEWER, reinterpret_cast<WPARAM>(pfncClipViewerCallback), 0); + MsgCtx aMsgCtx; + + if (postMessage(MSG_REGCLIPVIEWER, reinterpret_cast<WPARAM>(pfncClipViewerCallback), + reinterpret_cast<LPARAM>(&aMsgCtx))) + aMsgCtx.aCondition.wait(m_hEvtWndDisposed); return false; } @@ -481,6 +548,7 @@ LRESULT CALLBACK CMtaOleClipboard::mtaOleReqWndProc( HWND hWnd, UINT uMsg, WPARA OSL_ASSERT( aMsgCtx ); aMsgCtx->hr = CMtaOleClipboard::onGetClipboard( reinterpret_cast< LPSTREAM* >(wParam) ); + aMsgCtx->aCondition.set( ); } break; @@ -490,12 +558,19 @@ LRESULT CALLBACK CMtaOleClipboard::mtaOleReqWndProc( HWND hWnd, UINT uMsg, WPARA OSL_ASSERT( aMsgCtx ); aMsgCtx->hr = CMtaOleClipboard::onFlushClipboard( ); + aMsgCtx->aCondition.set( ); } break; case MSG_REGCLIPVIEWER: - pImpl->onRegisterClipViewer( - reinterpret_cast<CMtaOleClipboard::LPFNC_CLIPVIEWER_CALLBACK_t>(wParam)); + { + MsgCtx* pMsgCtx = reinterpret_cast<MsgCtx*>(lParam); + SAL_WARN_IF(!pMsgCtx, "dtrans", "pMsgCtx is nullptr"); + + pImpl->onRegisterClipViewer( + reinterpret_cast<CMtaOleClipboard::LPFNC_CLIPVIEWER_CALLBACK_t>(wParam)); + pMsgCtx->aCondition.set(); + } break; case WM_CLIPBOARDUPDATE: @@ -508,6 +583,7 @@ LRESULT CALLBACK CMtaOleClipboard::mtaOleReqWndProc( HWND hWnd, UINT uMsg, WPARA // force the sta thread to end case WM_DESTROY: + SetEvent(pImpl->m_hEvtWndDisposed); // stop waiting for conditions set by this wndproc PostQuitMessage( 0 ); break; diff --git a/dtrans/source/win32/clipb/MtaOleClipb.hxx b/dtrans/source/win32/clipb/MtaOleClipb.hxx index fdd00088dbe8..f25019d0784c 100644 --- a/dtrans/source/win32/clipb/MtaOleClipb.hxx +++ b/dtrans/source/win32/clipb/MtaOleClipb.hxx @@ -87,6 +87,7 @@ private: unsigned m_uOleThreadId; HANDLE m_hEvtThrdReady; HWND m_hwndMtaOleReqWnd; + HANDLE m_hEvtWndDisposed; ATOM m_MtaOleReqWndClassAtom; LPFNC_CLIPVIEWER_CALLBACK_t m_pfncClipViewerCallback; bool m_bInRegisterClipViewer; |