vcl/inc/win/salinst.h       |    9 +++++++++
 vcl/win/app/salinst.cxx     |   28 +++++++++++++++++++++++-----
 vcl/win/window/salframe.cxx |   32 ++++++++++++++++----------------
 3 files changed, 48 insertions(+), 21 deletions(-)

New commits:
commit 1c78cb0673e117136212fea7b51adcf898ff94f5
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Thu Sep 18 21:04:00 2025 +0500
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Fri Sep 19 11:08:26 2025 +0200

    tdf#168431: Release solar mutex when sending window message to main thread
    
    It started after commit 1e2e51607a163021ef1fb1fb0d217266bd448173 for some
    reason, but the problem is, that the caller code from some thread holds
    the solar mutex, and the code that handles the message in main VCL thread
    tries to lock solar mutex; and that didn't change.
    
    This change introduces some methods in WinSalInstance, that wrap calls to
    SendMessageW, and release solar mutex if the functions are not in the main
    thread.
    
    Change-Id: Iac8690acbd306273c92534c6d319cbdf4b799860
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191147
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Tested-by: Jenkins
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191183

diff --git a/vcl/inc/win/salinst.h b/vcl/inc/win/salinst.h
index dc7f2eb61a0f..ccb44de360e1 100644
--- a/vcl/inc/win/salinst.h
+++ b/vcl/inc/win/salinst.h
@@ -87,6 +87,15 @@ public:
     ImplCreateDragSource(const SystemEnvData*) override;
     virtual css::uno::Reference<css::datatransfer::dnd::XDropTarget>
     ImplCreateDropTarget(const SystemEnvData*) override;
+
+    // Sends a message to a window, making sure to unlock solar mutex if 
necessary
+    static LRESULT SendWndMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM 
lParam);
+    // Sends a message to mhComWnd, making sure to unlock solar mutex if 
necessary
+    LRESULT SendComWndMessage(UINT Msg, WPARAM wParam, LPARAM lParam) const;
+
+private:
+    // Sends a message to a window, making sure to unlock solar mutex if 
necessary
+    LRESULT SendWndMessage_impl(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM 
lParam) const;
 };
 
 SalFrame* ImplSalCreateFrame( WinSalInstance* pInst, HWND hWndParent, 
SalFrameStyleFlags nSalFrameStyle );
diff --git a/vcl/win/app/salinst.cxx b/vcl/win/app/salinst.cxx
index 16e3206f4878..26f373a392be 100644
--- a/vcl/win/app/salinst.cxx
+++ b/vcl/win/app/salinst.cxx
@@ -773,10 +773,28 @@ bool WinSalInstance::AnyInput( VclInputFlags nType )
     return false;
 }
 
+LRESULT WinSalInstance::SendWndMessage_impl(HWND hWnd, UINT Msg, WPARAM 
wParam, LPARAM lParam) const
+{
+    std::optional<SolarMutexReleaser> oReleaser;
+    if (!IsMainThread())
+        oReleaser.emplace();
+    return SendMessageW(hWnd, Msg, wParam, lParam);
+}
+
+LRESULT WinSalInstance::SendWndMessage(HWND hWnd, UINT Msg, WPARAM wParam, 
LPARAM lParam)
+{
+    return GetSalData()->mpInstance->SendWndMessage_impl(hWnd, Msg, wParam, 
lParam);
+}
+
+LRESULT WinSalInstance::SendComWndMessage(UINT Msg, WPARAM wParam, LPARAM 
lParam) const
+{
+    return SendWndMessage_impl(mhComWnd, Msg, wParam, lParam);
+}
+
 SalFrame* WinSalInstance::CreateChildFrame( SystemParentData* 
pSystemParentData, SalFrameStyleFlags nSalFrameStyle )
 {
     // to switch to Main-Thread
-    return reinterpret_cast<SalFrame*>(static_cast<sal_IntPtr>(SendMessageW( 
mhComWnd, SAL_MSG_CREATEFRAME, static_cast<WPARAM>(nSalFrameStyle), 
reinterpret_cast<LPARAM>(pSystemParentData->hWnd) )));
+    return 
reinterpret_cast<SalFrame*>(static_cast<sal_IntPtr>(SendComWndMessage( 
SAL_MSG_CREATEFRAME, static_cast<WPARAM>(nSalFrameStyle), 
reinterpret_cast<LPARAM>(pSystemParentData->hWnd) )));
 }
 
 SalFrame* WinSalInstance::CreateFrame( SalFrame* pParent, SalFrameStyleFlags 
nSalFrameStyle )
@@ -787,13 +805,13 @@ SalFrame* WinSalInstance::CreateFrame( SalFrame* pParent, 
SalFrameStyleFlags nSa
         hWndParent = static_cast<WinSalFrame*>(pParent)->mhWnd;
     else
         hWndParent = nullptr;
-    return reinterpret_cast<SalFrame*>(static_cast<sal_IntPtr>(SendMessageW( 
mhComWnd, SAL_MSG_CREATEFRAME, static_cast<WPARAM>(nSalFrameStyle), 
reinterpret_cast<LPARAM>(hWndParent) )));
+    return 
reinterpret_cast<SalFrame*>(static_cast<sal_IntPtr>(SendComWndMessage( 
SAL_MSG_CREATEFRAME, static_cast<WPARAM>(nSalFrameStyle), 
reinterpret_cast<LPARAM>(hWndParent) )));
 }
 
 void WinSalInstance::DestroyFrame( SalFrame* pFrame )
 {
     OpenGLContext::prepareForYield();
-    SendMessageW( mhComWnd, SAL_MSG_DESTROYFRAME, 0, 
reinterpret_cast<LPARAM>(pFrame) );
+    SendComWndMessage(SAL_MSG_DESTROYFRAME, 0, 
reinterpret_cast<LPARAM>(pFrame));
 }
 
 SalObject* WinSalInstance::CreateObject( SalFrame* pParent,
@@ -801,12 +819,12 @@ SalObject* WinSalInstance::CreateObject( SalFrame* 
pParent,
                                          bool /*bShow*/ )
 {
     // to switch to Main-Thread
-    return reinterpret_cast<SalObject*>(static_cast<sal_IntPtr>(SendMessageW( 
mhComWnd, SAL_MSG_CREATEOBJECT, 0, 
reinterpret_cast<LPARAM>(static_cast<WinSalFrame*>(pParent)) )));
+    return 
reinterpret_cast<SalObject*>(static_cast<sal_IntPtr>(SendComWndMessage( 
SAL_MSG_CREATEOBJECT, 0, 
reinterpret_cast<LPARAM>(static_cast<WinSalFrame*>(pParent)) )));
 }
 
 void WinSalInstance::DestroyObject( SalObject* pObject )
 {
-    SendMessageW( mhComWnd, SAL_MSG_DESTROYOBJECT, 0, 
reinterpret_cast<LPARAM>(pObject) );
+    SendComWndMessage(SAL_MSG_DESTROYOBJECT, 0, 
reinterpret_cast<LPARAM>(pObject));
 }
 
 OUString WinSalInstance::GetConnectionIdentifier()
diff --git a/vcl/win/window/salframe.cxx b/vcl/win/window/salframe.cxx
index e5a3a38bb4fb..76572eb4fa08 100644
--- a/vcl/win/window/salframe.cxx
+++ b/vcl/win/window/salframe.cxx
@@ -958,7 +958,7 @@ WinSalFrame::~WinSalFrame()
         if (hDC)
         {
             mpThreadGraphics->setHDC(nullptr);
-            SendMessageW( pSalData->mpInstance->mhComWnd, SAL_MSG_RELEASEDC,
+            pSalData->mpInstance->SendComWndMessage(SAL_MSG_RELEASEDC,
                 reinterpret_cast<WPARAM>(mhWnd), reinterpret_cast<LPARAM>(hDC) 
);
         }
         delete mpThreadGraphics;
@@ -1012,7 +1012,7 @@ SalGraphics* WinSalFrame::AcquireGraphics()
     // WM_ERASEBACKGROUND message
     if ( !pSalData->mpInstance->IsMainThread() )
     {
-        HDC hDC = reinterpret_cast<HDC>(static_cast<sal_IntPtr>(SendMessageW( 
pSalData->mpInstance->mhComWnd,
+        HDC hDC = 
reinterpret_cast<HDC>(static_cast<sal_IntPtr>(pSalData->mpInstance->SendComWndMessage(
                                     SAL_MSG_GETCACHEDDC, 
reinterpret_cast<WPARAM>(mhWnd), 0 )));
         if ( !hDC )
             return nullptr;
@@ -1049,7 +1049,7 @@ void WinSalFrame::ReleaseGraphics( SalGraphics* pGraphics 
)
         HDC hDC = mpThreadGraphics->getHDC();
         assert(hDC);
         mpThreadGraphics->setHDC(nullptr);
-        SendMessageW( pSalData->mpInstance->mhComWnd, SAL_MSG_RELEASEDC,
+        pSalData->mpInstance->SendComWndMessage(SAL_MSG_RELEASEDC,
             reinterpret_cast<WPARAM>(mhWnd), reinterpret_cast<LPARAM>(hDC) );
     }
     mbGraphicsAcquired = false;
@@ -1068,7 +1068,7 @@ void WinSalFrame::SetTitle( const OUString& rTitle )
 {
     static_assert( sizeof( WCHAR ) == sizeof( sal_Unicode ), "must be the same 
size" );
 
-    SetWindowTextW( mhWnd, o3tl::toW(rTitle.getStr()) );
+    WinSalInstance::SendWndMessage(mhWnd, WM_SETTEXT, 0, 
reinterpret_cast<LPARAM>(rTitle.getStr()));
 }
 
 void WinSalFrame::SetIcon( sal_uInt16 nIcon )
@@ -1087,8 +1087,8 @@ void WinSalFrame::SetIcon( sal_uInt16 nIcon )
     SAL_WARN_IF( !hIcon , "vcl",   "WinSalFrame::SetIcon(): Could not load 
large icon !" );
     SAL_WARN_IF( !hSmIcon , "vcl", "WinSalFrame::SetIcon(): Could not load 
small icon !" );
 
-    SendMessageW( mhWnd, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(hIcon) 
);
-    SendMessageW( mhWnd, WM_SETICON, ICON_SMALL, 
reinterpret_cast<LPARAM>(hSmIcon) );
+    WinSalInstance::SendWndMessage(mhWnd, WM_SETICON, ICON_BIG, 
reinterpret_cast<LPARAM>(hIcon));
+    WinSalInstance::SendWndMessage(mhWnd, WM_SETICON, ICON_SMALL, 
reinterpret_cast<LPARAM>(hSmIcon));
 }
 
 void WinSalFrame::SetMenu( SalMenu* pSalMenu )
@@ -1495,7 +1495,7 @@ void WinSalFrame::ImplSetParentFrame( HWND hNewParentWnd, 
bool bAsChild )
             hBrush = static_cast<HBRUSH>(GetCurrentObject( hDC, OBJ_BRUSH ));
 
             mpThreadGraphics->setHDC(nullptr);
-            SendMessageW( pSalData->mpInstance->mhComWnd, SAL_MSG_RELEASEDC,
+            pSalData->mpInstance->SendComWndMessage(SAL_MSG_RELEASEDC,
                 reinterpret_cast<WPARAM>(mhWnd), reinterpret_cast<LPARAM>(hDC) 
);
 
             bHadThreadGraphics = true;
@@ -1514,7 +1514,7 @@ void WinSalFrame::ImplSetParentFrame( HWND hNewParentWnd, 
bool bAsChild )
     // create a new hwnd with the same styles
     HWND hWndParent = hNewParentWnd;
     // forward to main thread
-    HWND hWnd = reinterpret_cast<HWND>(static_cast<sal_IntPtr>(SendMessageW( 
pSalData->mpInstance->mhComWnd,
+    HWND hWnd = 
reinterpret_cast<HWND>(static_cast<sal_IntPtr>(pSalData->mpInstance->SendComWndMessage(
                                         bAsChild ? SAL_MSG_RECREATECHILDHWND : 
SAL_MSG_RECREATEHWND,
                                         reinterpret_cast<WPARAM>(hWndParent), 
reinterpret_cast<LPARAM>(mhWnd) )));
 
@@ -1526,7 +1526,7 @@ void WinSalFrame::ImplSetParentFrame( HWND hNewParentWnd, 
bool bAsChild )
     {
         mpThreadGraphics->setHWND( hWnd );
         HDC hDC = reinterpret_cast<HDC>(static_cast<sal_IntPtr>(
-                    SendMessageW( pSalData->mpInstance->mhComWnd,
+                    pSalData->mpInstance->SendComWndMessage(
                         SAL_MSG_GETCACHEDDC, reinterpret_cast<WPARAM>(hWnd), 0 
)));
         if ( hDC )
         {
@@ -1561,7 +1561,7 @@ void WinSalFrame::ImplSetParentFrame( HWND hNewParentWnd, 
bool bAsChild )
     systemChildren.clear();
 
     // Now destroy original HWND in the thread where it was created.
-    SendMessageW( GetSalData()->mpInstance->mhComWnd,
+    pSalData->mpInstance->SendComWndMessage(
                      SAL_MSG_DESTROYHWND, WPARAM(0), 
reinterpret_cast<LPARAM>(hWndOld));
 }
 
@@ -2163,7 +2163,7 @@ void WinSalFrame::CaptureMouse( bool bCapture )
         nMsg = SAL_MSG_CAPTUREMOUSE;
     else
         nMsg = SAL_MSG_RELEASEMOUSE;
-    SendMessageW( mhWnd, nMsg, 0, 0 );
+    WinSalInstance::SendWndMessage(mhWnd, nMsg, 0, 0);
 }
 
 void WinSalFrame::SetPointerPos( tools::Long nX, tools::Long nY )
@@ -2253,7 +2253,7 @@ static void ImplSalFrameSetInputContext( HWND hWnd, const 
SalInputContext* pCont
 void WinSalFrame::SetInputContext( SalInputContext* pContext )
 {
     // Must be called in the main thread!
-    SendMessageW( mhWnd, SAL_MSG_SETINPUTCONTEXT, 0, 
reinterpret_cast<LPARAM>(pContext) );
+    WinSalInstance::SendWndMessage(mhWnd, SAL_MSG_SETINPUTCONTEXT, 0, 
reinterpret_cast<LPARAM>(pContext));
 }
 
 static void ImplSalFrameEndExtTextInput( HWND hWnd, EndExtTextInputFlags 
nFlags )
@@ -2275,7 +2275,7 @@ static void ImplSalFrameEndExtTextInput( HWND hWnd, 
EndExtTextInputFlags nFlags
 void WinSalFrame::EndExtTextInput( EndExtTextInputFlags nFlags )
 {
     // Must be called in the main thread!
-    SendMessageW( mhWnd, SAL_MSG_ENDEXTTEXTINPUT, static_cast<WPARAM>(nFlags), 
0 );
+    WinSalInstance::SendWndMessage(mhWnd, SAL_MSG_ENDEXTTEXTINPUT, 
static_cast<WPARAM>(nFlags), 0);
 }
 
 static void ImplGetKeyNameText(UINT lParam, OUStringBuffer& rBuf, const char* 
pReplace)
@@ -3300,7 +3300,7 @@ static bool ImplHandleMouseMsg( HWND hWnd, UINT nMsg,
             SalData* pSalData = GetSalData();
             // Test for MouseLeave
             if ( pSalData->mhWantLeaveMsg && (pSalData->mhWantLeaveMsg != 
hWnd) )
-                SendMessageW( pSalData->mhWantLeaveMsg, SAL_MSG_MOUSELEAVE, 0, 
GetMessagePos() );
+                WinSalInstance::SendWndMessage(pSalData->mhWantLeaveMsg, 
SAL_MSG_MOUSELEAVE, 0, GetMessagePos());
 
             pSalData->mhWantLeaveMsg = hWnd;
             aMouseEvt.mnButton = 0;
@@ -5697,7 +5697,7 @@ void SalTestMouseLeave()
         cachedPoint = aPt;
 
         if ( pSalData->mhWantLeaveMsg != WindowFromPoint( aPt ) )
-            SendMessageW( pSalData->mhWantLeaveMsg, SAL_MSG_MOUSELEAVE, 0, 
MAKELPARAM( aPt.x, aPt.y ) );
+            WinSalInstance::SendWndMessage(pSalData->mhWantLeaveMsg, 
SAL_MSG_MOUSELEAVE, 0, MAKELPARAM(aPt.x, aPt.y));
     }
 }
 
@@ -5722,7 +5722,7 @@ static bool ImplSalWheelMousePos( HWND hWnd, UINT nMsg, 
WPARAM wParam, LPARAM lP
     if ( hWheelWnd && (hWheelWnd != hWnd) &&
          (hWheelWnd != ::GetFocus()) && IsWindowEnabled( hWheelWnd ) )
     {
-        rResult = SendMessageW( hWheelWnd, nMsg, wParam, lParam );
+        rResult = WinSalInstance::SendWndMessage(hWheelWnd, nMsg, wParam, 
lParam);
         return false;
     }
 

Reply via email to