From 12e78aab8490e26a514779c64d07f2c5d5ef6c96 Mon Sep 17 00:00:00 2001 From: narzoul Date: Sun, 25 Nov 2018 11:46:43 +0100 Subject: [PATCH] Moved presentation windows to dedicated thread --- DDrawCompat/Gdi/Gdi.cpp | 2 + DDrawCompat/Gdi/WinProc.cpp | 11 +--- DDrawCompat/Gdi/Window.cpp | 114 +++++++++++++++++++++++++++++------- DDrawCompat/Gdi/Window.h | 3 + 4 files changed, 101 insertions(+), 29 deletions(-) diff --git a/DDrawCompat/Gdi/Gdi.cpp b/DDrawCompat/Gdi/Gdi.cpp index 670f17b..586d4ab 100644 --- a/DDrawCompat/Gdi/Gdi.cpp +++ b/DDrawCompat/Gdi/Gdi.cpp @@ -51,6 +51,7 @@ namespace Gdi DcFunctions::installHooks(); PaintHandlers::installHooks(); ScrollFunctions::installHooks(); + Window::installHooks(); WinProc::installHooks(); Caret::installHooks(); } @@ -93,6 +94,7 @@ namespace Gdi { Caret::uninstallHooks(); WinProc::uninstallHooks(); + Window::uninstallHooks(); Dc::dllProcessDetach(); DcCache::dllProcessDetach(); ReleaseDC(nullptr, g_screenDc); diff --git a/DDrawCompat/Gdi/WinProc.cpp b/DDrawCompat/Gdi/WinProc.cpp index cab1b18..676dd2e 100644 --- a/DDrawCompat/Gdi/WinProc.cpp +++ b/DDrawCompat/Gdi/WinProc.cpp @@ -91,16 +91,9 @@ namespace { DWORD windowPid = 0; GetWindowThreadProcessId(hwnd, &windowPid); - if (GetCurrentProcessId() != windowPid) + if (GetCurrentProcessId() == windowPid) { - return TRUE; - } - - onCreateWindow(hwnd); - if (!(GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED)) - { - RedrawWindow(hwnd, nullptr, nullptr, - RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN | RDW_UPDATENOW); + onCreateWindow(hwnd); } return TRUE; } diff --git a/DDrawCompat/Gdi/Window.cpp b/DDrawCompat/Gdi/Window.cpp index 6b77537..d7ffbac 100644 --- a/DDrawCompat/Gdi/Window.cpp +++ b/DDrawCompat/Gdi/Window.cpp @@ -1,4 +1,5 @@ #include "Common/Hook.h" +#include "Common/Log.h" #include "DDraw/ScopedThreadLock.h" #include "Gdi/Gdi.h" #include "Gdi/Window.h" @@ -7,8 +8,12 @@ extern "C" IMAGE_DOS_HEADER __ImageBase; namespace { - ATOM registerPresentationWindowClass(); + const UINT WM_CREATEPRESENTATIONWINDOW = WM_USER; + HANDLE g_presentationWindowThread = nullptr; + DWORD g_presentationWindowThreadId = 0; + HWND g_messageWindow = nullptr; + ATOM getComboLBoxAtom() { WNDCLASS wc = {}; @@ -16,24 +21,65 @@ namespace return comboLBoxAtom; } - ATOM getPresentationWindowClassAtom() + LRESULT CALLBACK messageWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - static ATOM atom = registerPresentationWindowClass(); - return atom; + LOG_FUNC("messageWindowProc", hwnd, Compat::hex(uMsg), Compat::hex(wParam), Compat::hex(lParam)); + switch (uMsg) + { + case WM_CREATEPRESENTATIONWINDOW: + { + HWND presentationWindow = CreateWindowEx( + WS_EX_LAYERED | WS_EX_TRANSPARENT, + "DDrawCompatPresentationWindow", + nullptr, + WS_DISABLED | WS_POPUP, + 0, 0, 1, 1, + reinterpret_cast(wParam), + nullptr, + nullptr, + nullptr); + SetLayeredWindowAttributes(presentationWindow, 0, 255, LWA_ALPHA); + return reinterpret_cast(presentationWindow); + } + + case WM_DESTROY: + PostQuitMessage(0); + return 0; + + default: + return CALL_ORIG_FUNC(DefWindowProc)(hwnd, uMsg, wParam, lParam); + } } LRESULT CALLBACK presentationWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + LOG_FUNC("presentationWindowProc", hwnd, Compat::hex(uMsg), Compat::hex(wParam), Compat::hex(lParam)); return CALL_ORIG_FUNC(DefWindowProc)(hwnd, uMsg, wParam, lParam); } - ATOM registerPresentationWindowClass() + DWORD WINAPI presentationWindowThreadProc(LPVOID /*lpParameter*/) { WNDCLASS wc = {}; - wc.lpfnWndProc = &presentationWindowProc; + wc.lpfnWndProc = &messageWindowProc; wc.hInstance = reinterpret_cast(&__ImageBase); - wc.lpszClassName = "DDrawCompatPresentationWindow"; - return RegisterClass(&wc); + wc.lpszClassName = "DDrawCompatMessageWindow"; + RegisterClass(&wc); + + g_messageWindow = CreateWindow( + "DDrawCompatMessageWindow", nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr); + if (!g_messageWindow) + { + return 0; + } + + MSG msg = {}; + while (GetMessage(&msg, nullptr, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return 0; } } @@ -48,17 +94,8 @@ namespace Gdi const ATOM atom = static_cast(GetClassLong(hwnd, GCW_ATOM)); if (MENU_ATOM != atom && getComboLBoxAtom() != atom) { - m_presentationWindow = CreateWindowEx( - WS_EX_LAYERED | WS_EX_TRANSPARENT, - reinterpret_cast(getPresentationWindowClassAtom()), - nullptr, - WS_DISABLED | WS_POPUP, - 0, 0, 1, 1, - m_hwnd, - nullptr, - nullptr, - nullptr); - SetLayeredWindowAttributes(m_presentationWindow, 0, 255, LWA_ALPHA); + m_presentationWindow = reinterpret_cast(SendMessage( + g_messageWindow, WM_CREATEPRESENTATIONWINDOW, reinterpret_cast(hwnd), 0)); } update(); @@ -137,9 +174,33 @@ namespace Gdi return s_windows; } + void Window::installHooks() + { + WNDCLASS wc = {}; + wc.lpfnWndProc = &presentationWindowProc; + wc.hInstance = reinterpret_cast(&__ImageBase); + wc.lpszClassName = "DDrawCompatPresentationWindow"; + RegisterClass(&wc); + + g_presentationWindowThread = CreateThread( + nullptr, 0, &presentationWindowThreadProc, nullptr, 0, &g_presentationWindowThreadId); + + int i = 0; + while (!g_messageWindow && i < 1000) + { + Sleep(1); + ++i; + } + + if (!g_messageWindow) + { + Compat::Log() << "Failed to create a message-only window"; + } + } + bool Window::isPresentationWindow(HWND hwnd) { - return IsWindow(hwnd) && GetClassLong(hwnd, GCW_ATOM) == getPresentationWindowClassAtom(); + return IsWindow(hwnd) && g_presentationWindowThreadId == GetWindowThreadProcessId(hwnd, nullptr); } bool Window::isTopLevelNonLayeredWindow(HWND hwnd) @@ -155,6 +216,19 @@ namespace Gdi s_windows.erase(hwnd); } + void Window::uninstallHooks() + { + if (g_presentationWindowThread) + { + SendMessage(g_messageWindow, WM_CLOSE, 0, 0); + if (WAIT_OBJECT_0 != WaitForSingleObject(g_presentationWindowThread, 1000)) + { + TerminateThread(g_presentationWindowThread, 0); + Compat::Log() << "The presentation window thread was terminated forcefully"; + } + } + } + void Window::update() { DDraw::ScopedThreadLock lock; diff --git a/DDrawCompat/Gdi/Window.h b/DDrawCompat/Gdi/Window.h index 593182c..a282a9c 100644 --- a/DDrawCompat/Gdi/Window.h +++ b/DDrawCompat/Gdi/Window.h @@ -32,6 +32,9 @@ namespace Gdi static bool isTopLevelNonLayeredWindow(HWND hwnd); static void updateAll(); + static void installHooks(); + static void uninstallHooks(); + private: void calcInvalidatedRegion(const RECT& oldWindowRect, const Region& oldVisibleRegion); void update();