From a442239ac1bc8f334b48e104345ee0fbb9b8fec3 Mon Sep 17 00:00:00 2001 From: narzoul Date: Sat, 29 Jun 2024 23:22:07 +0200 Subject: [PATCH] Fixed a potential deadlock in resetMouseHook Fixes a sporadic deadlock when alt-tabbing in Star Trek: Armada with the config overlay open. --- DDrawCompat/Gdi/GuiThread.cpp | 12 ++++++++ DDrawCompat/Gdi/GuiThread.h | 1 + DDrawCompat/Input/Input.cpp | 52 ++++++++++++++++++----------------- 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/DDrawCompat/Gdi/GuiThread.cpp b/DDrawCompat/Gdi/GuiThread.cpp index eae3d1a..a7c1974 100644 --- a/DDrawCompat/Gdi/GuiThread.cpp +++ b/DDrawCompat/Gdi/GuiThread.cpp @@ -20,6 +20,7 @@ namespace { const UINT WM_USER_EXECUTE = WM_USER; + const UINT WM_USER_EXECUTE_ASYNC = WM_USER + 1; struct EnumWindowsArgs { @@ -185,6 +186,12 @@ namespace func(); return 0; } + if (WM_USER_EXECUTE_ASYNC == uMsg) + { + auto func = reinterpret_cast(lParam); + func(); + return 0; + } return CALL_ORIG_FUNC(DefWindowProc)(hwnd, uMsg, wParam, lParam); } @@ -277,6 +284,11 @@ namespace Gdi PostMessage(hwnd, WM_CLOSE, 0, 0); } + void executeAsyncFunc(void(*func)()) + { + PostMessage(g_messageWindow, WM_USER_EXECUTE_ASYNC, 0, reinterpret_cast(func)); + } + void executeFunc(const std::function& func) { DWORD_PTR result = 0; diff --git a/DDrawCompat/Gdi/GuiThread.h b/DDrawCompat/Gdi/GuiThread.h index 67489bb..9220007 100644 --- a/DDrawCompat/Gdi/GuiThread.h +++ b/DDrawCompat/Gdi/GuiThread.h @@ -27,6 +27,7 @@ namespace Gdi template void execute(const Func& func) { executeFunc(std::cref(func)); } + void executeAsyncFunc(void(*func)()); void executeFunc(const std::function& func); bool isGuiThreadWindow(HWND hwnd); diff --git a/DDrawCompat/Input/Input.cpp b/DDrawCompat/Input/Input.cpp index f46c117..2bb5fad 100644 --- a/DDrawCompat/Input/Input.cpp +++ b/DDrawCompat/Input/Input.cpp @@ -268,33 +268,35 @@ namespace }); } + void resetMouseHookFunc() + { + if (g_mouseHook) + { + UnhookWindowsHookEx(g_mouseHook); + } + + g_origCursorPos = { MAXLONG, MAXLONG }; + g_mouseHook = CALL_ORIG_FUNC(SetWindowsHookExA)( + WH_MOUSE_LL, &lowLevelMouseProc, Dll::g_origDDrawModule, 0); + + if (g_mouseHook) + { + INPUT inputs[2] = {}; + inputs[0].mi.dy = 1; + inputs[0].mi.dwFlags = MOUSEEVENTF_MOVE; + inputs[1].mi.dx = 1; + inputs[1].mi.dwFlags = MOUSEEVENTF_MOVE; + SendInput(2, inputs, sizeof(INPUT)); + } + else + { + LOG_ONCE("ERROR: Failed to install low level mouse hook, error code: " << GetLastError()); + } + } + void resetMouseHook() { - Gdi::GuiThread::execute([]() - { - if (g_mouseHook) - { - UnhookWindowsHookEx(g_mouseHook); - } - - g_origCursorPos = { MAXLONG, MAXLONG }; - g_mouseHook = CALL_ORIG_FUNC(SetWindowsHookExA)( - WH_MOUSE_LL, &lowLevelMouseProc, Dll::g_origDDrawModule, 0); - - if (g_mouseHook) - { - INPUT inputs[2] = {}; - inputs[0].mi.dy = 1; - inputs[0].mi.dwFlags = MOUSEEVENTF_MOVE; - inputs[1].mi.dx = 1; - inputs[1].mi.dwFlags = MOUSEEVENTF_MOVE; - SendInput(2, inputs, sizeof(INPUT)); - } - else - { - LOG_ONCE("ERROR: Failed to install low level mouse hook, error code: " << GetLastError()); - } - }); + Gdi::GuiThread::executeAsyncFunc(resetMouseHookFunc); } BOOL WINAPI setCursorPos(int X, int Y)