diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index c44216c..0884e32 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -301,6 +301,7 @@ + @@ -401,6 +402,7 @@ + @@ -454,4 +456,4 @@ - + \ No newline at end of file diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 35f0bda..845994c 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -513,6 +513,9 @@ Header Files\Common + + Header Files\Gdi + @@ -809,6 +812,9 @@ Source Files\Common + + Source Files\Gdi + diff --git a/DDrawCompat/Dll/DllMain.cpp b/DDrawCompat/Dll/DllMain.cpp index f705a95..1eb6508 100644 --- a/DDrawCompat/Dll/DllMain.cpp +++ b/DDrawCompat/Dll/DllMain.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -113,7 +114,7 @@ namespace Compat::Log() << "Installing GDI hooks"; Gdi::installHooks(); Compat::closeDbgEng(); - Gdi::PresentationWindow::startThread(); + Gdi::GuiThread::start(); Compat::Log() << "Finished installing hooks"; isAlreadyInstalled = true; } diff --git a/DDrawCompat/Gdi/Gdi.cpp b/DDrawCompat/Gdi/Gdi.cpp index 700e6a1..fc1732f 100644 --- a/DDrawCompat/Gdi/Gdi.cpp +++ b/DDrawCompat/Gdi/Gdi.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -74,6 +75,7 @@ namespace Gdi Caret::installHooks(); Cursor::installHooks(); Font::installHooks(); + WinProc::installHooks(); } bool isDisplayDc(HDC dc) @@ -90,7 +92,7 @@ namespace Gdi void redrawWindow(HWND hwnd, HRGN rgn) { - if (!IsWindowVisible(hwnd) || IsIconic(hwnd) || PresentationWindow::isPresentationWindow(hwnd)) + if (!IsWindowVisible(hwnd) || IsIconic(hwnd) || GuiThread::isGuiThreadWindow(hwnd)) { return; } diff --git a/DDrawCompat/Gdi/GuiThread.cpp b/DDrawCompat/Gdi/GuiThread.cpp new file mode 100644 index 0000000..37952a9 --- /dev/null +++ b/DDrawCompat/Gdi/GuiThread.cpp @@ -0,0 +1,157 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + const UINT WM_USER_EXECUTE = WM_USER; + + unsigned g_threadId = 0; + Overlay::ConfigWindow* g_configWindow = nullptr; + HWND g_messageWindow = nullptr; + bool g_isReady = false; + + BOOL CALLBACK initChildWindow(HWND hwnd, LPARAM /*lParam*/) + { + Gdi::WinProc::onCreateWindow(hwnd); + return TRUE; + } + + BOOL CALLBACK initTopLevelWindow(HWND hwnd, LPARAM /*lParam*/) + { + DWORD windowPid = 0; + GetWindowThreadProcessId(hwnd, &windowPid); + if (GetCurrentProcessId() == windowPid) + { + Gdi::WinProc::onCreateWindow(hwnd); + EnumChildWindows(hwnd, &initChildWindow, 0); + if (8 == Win32::DisplayMode::getBpp()) + { + PostMessage(hwnd, WM_PALETTECHANGED, reinterpret_cast(GetDesktopWindow()), 0); + } + } + return TRUE; + } + + LRESULT CALLBACK messageWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) + { + LOG_FUNC("messageWindowProc", Compat::WindowMessageStruct(hwnd, uMsg, wParam, lParam)); + + if (WM_USER_EXECUTE == uMsg) + { + auto& func = *reinterpret_cast*>(lParam); + func(); + return LOG_RESULT(0); + } + + return LOG_RESULT(CALL_ORIG_FUNC(DefWindowProc)(hwnd, uMsg, wParam, lParam)); + } + + unsigned WINAPI messageWindowThreadProc(LPVOID /*lpParameter*/) + { + WNDCLASS wc = {}; + wc.lpfnWndProc = &messageWindowProc; + wc.hInstance = Dll::g_currentModule; + wc.lpszClassName = "DDrawCompatMessageWindow"; + CALL_ORIG_FUNC(RegisterClassA)(&wc); + + g_messageWindow = CreateWindow( + "DDrawCompatMessageWindow", nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr); + if (!g_messageWindow) + { + Compat::Log() << "ERROR: Failed to create a message-only window"; + return 0; + } + + Overlay::ConfigWindow configWindow; + g_configWindow = &configWindow; + + { + D3dDdi::ScopedCriticalSection lock; + g_isReady = true; + EnumWindows(initTopLevelWindow, 0); + } + + MSG msg = {}; + while (GetMessage(&msg, nullptr, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return 0; + } +} + +namespace Gdi +{ + namespace GuiThread + { + HWND createWindow(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, + int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam) + { + // Workaround for ForceSimpleWindow shim + static auto createWindowExA = reinterpret_cast( + Compat::getProcAddress(GetModuleHandle("user32"), "CreateWindowExA")); + + HWND hwnd = nullptr; + execute([&]() + { + hwnd = createWindowExA(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, + hWndParent, hMenu, hInstance, lpParam); + }); + return hwnd; + } + + void destroyWindow(HWND hwnd) + { + execute([&]() { DestroyWindow(hwnd); }); + } + + void executeFunc(const std::function& func) + { + DWORD_PTR result = 0; + SendMessageTimeout(g_messageWindow, WM_USER_EXECUTE, 0, reinterpret_cast(&func), + SMTO_BLOCK | SMTO_NOTIMEOUTIFNOTHUNG, 0, &result); + } + + Overlay::ConfigWindow* getConfigWindow() + { + return g_configWindow; + } + + bool isGuiThreadWindow(HWND hwnd) + { + return GetWindowThreadProcessId(hwnd, nullptr) == g_threadId; + } + + bool isReady() + { + return g_isReady; + } + + void setWindowRgn(HWND hwnd, Gdi::Region rgn) + { + execute([&]() + { + if (SetWindowRgn(hwnd, rgn, FALSE)) + { + rgn.release(); + } + }); + } + + void start() + { + Dll::createThread(messageWindowThreadProc, &g_threadId, THREAD_PRIORITY_TIME_CRITICAL, 0); + } + } +} diff --git a/DDrawCompat/Gdi/GuiThread.h b/DDrawCompat/Gdi/GuiThread.h new file mode 100644 index 0000000..cd9c02a --- /dev/null +++ b/DDrawCompat/Gdi/GuiThread.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include + +#include + +namespace Overlay +{ + class ConfigWindow; +} + +namespace Gdi +{ + namespace GuiThread + { + HWND createWindow(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, + int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam); + void destroyWindow(HWND hwnd); + void setWindowRgn(HWND hwnd, Gdi::Region rgn); + + Overlay::ConfigWindow* getConfigWindow(); + + template + void execute(const Func& func) { executeFunc(std::cref(func)); } + void executeFunc(const std::function& func); + + bool isGuiThreadWindow(HWND hwnd); + bool isReady(); + + void start(); + } +} diff --git a/DDrawCompat/Gdi/Palette.cpp b/DDrawCompat/Gdi/Palette.cpp index 7d234ea..f5050ff 100644 --- a/DDrawCompat/Gdi/Palette.cpp +++ b/DDrawCompat/Gdi/Palette.cpp @@ -196,7 +196,7 @@ namespace if (result && !bForceBackground) { HWND dcWindow = CALL_ORIG_FUNC(WindowFromDC)(hdc); - if (dcWindow && !(GetWindowLong(dcWindow, GWL_EXSTYLE) & WS_EX_TOOLWINDOW)) + if (dcWindow && !(CALL_ORIG_FUNC(GetWindowLongA)(dcWindow, GWL_EXSTYLE) & WS_EX_TOOLWINDOW)) { HWND activeWindow = GetActiveWindow(); if (activeWindow == dcWindow || IsChild(activeWindow, dcWindow)) diff --git a/DDrawCompat/Gdi/PresentationWindow.cpp b/DDrawCompat/Gdi/PresentationWindow.cpp index c7c1324..fbc7253 100644 --- a/DDrawCompat/Gdi/PresentationWindow.cpp +++ b/DDrawCompat/Gdi/PresentationWindow.cpp @@ -1,160 +1,17 @@ #include #include -#include #include +#include #include -#include -#include -#include namespace { - const UINT WM_CREATEPRESENTATIONWINDOW = WM_USER; - const UINT WM_SETPRESENTATIONWINDOWPOS = WM_USER + 1; - const UINT WM_SETPRESENTATIONWINDOWRGN = WM_USER + 2; - - HANDLE g_presentationWindowThread = nullptr; - unsigned g_presentationWindowThreadId = 0; - Overlay::ConfigWindow* g_configWindow = nullptr; - HWND g_messageWindow = nullptr; - bool g_isThreadReady = false; - - BOOL CALLBACK initChildWindow(HWND hwnd, LPARAM /*lParam*/) - { - Gdi::WinProc::onCreateWindow(hwnd); - return TRUE; - } - - BOOL CALLBACK initTopLevelWindow(HWND hwnd, LPARAM /*lParam*/) - { - DWORD windowPid = 0; - GetWindowThreadProcessId(hwnd, &windowPid); - if (GetCurrentProcessId() == windowPid) - { - Gdi::WinProc::onCreateWindow(hwnd); - EnumChildWindows(hwnd, &initChildWindow, 0); - if (8 == Win32::DisplayMode::getBpp()) - { - PostMessage(hwnd, WM_PALETTECHANGED, reinterpret_cast(GetDesktopWindow()), 0); - } - } - return TRUE; - } - - LRESULT CALLBACK messageWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) - { - LOG_FUNC("messageWindowProc", Compat::WindowMessageStruct(hwnd, uMsg, wParam, lParam)); - - switch (uMsg) - { - case WM_CREATEPRESENTATIONWINDOW: - { - // Workaround for ForceSimpleWindow shim - static auto origCreateWindowExA = reinterpret_cast( - Compat::getProcAddress(GetModuleHandle("user32"), "CreateWindowExA")); - - HWND owner = reinterpret_cast(wParam); - HWND presentationWindow = origCreateWindowExA( - WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_NOPARENTNOTIFY | WS_EX_TOOLWINDOW, - "DDrawCompatPresentationWindow", - nullptr, - WS_DISABLED | WS_POPUP, - 0, 0, 1, 1, - owner, - nullptr, - nullptr, - nullptr); - - if (presentationWindow) - { - if (lParam) - { - CALL_ORIG_FUNC(SetWindowLongA)(presentationWindow, GWL_WNDPROC, lParam); - } - CALL_ORIG_FUNC(SetLayeredWindowAttributes)(presentationWindow, 0, 255, LWA_ALPHA); - } - - return LOG_RESULT(reinterpret_cast(presentationWindow)); - } - - case WM_DESTROY: - PostQuitMessage(0); - return LOG_RESULT(0); - } - - return LOG_RESULT(CALL_ORIG_FUNC(DefWindowProc)(hwnd, uMsg, wParam, lParam)); - } + ATOM g_classAtom = 0; LRESULT CALLBACK presentationWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LOG_FUNC("presentationWindowProc", Compat::WindowMessageStruct(hwnd, uMsg, wParam, lParam)); - - switch (uMsg) - { - case WM_SETPRESENTATIONWINDOWPOS: - { - const auto& wp = *reinterpret_cast(lParam); - return SetWindowPos(hwnd, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags); - } - - case WM_SETPRESENTATIONWINDOWRGN: - { - HRGN rgn = nullptr; - if (wParam) - { - rgn = CreateRectRgn(0, 0, 0, 0); - CombineRgn(rgn, reinterpret_cast(wParam), nullptr, RGN_COPY); - } - return SetWindowRgn(hwnd, rgn, FALSE); - } - } - - return CALL_ORIG_FUNC(DefWindowProc)(hwnd, uMsg, wParam, lParam); - } - - unsigned WINAPI presentationWindowThreadProc(LPVOID /*lpParameter*/) - { - WNDCLASS wc = {}; - wc.lpfnWndProc = &messageWindowProc; - wc.hInstance = Dll::g_currentModule; - wc.lpszClassName = "DDrawCompatMessageWindow"; - CALL_ORIG_FUNC(RegisterClassA)(&wc); - - g_messageWindow = CreateWindow( - "DDrawCompatMessageWindow", nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr); - if (!g_messageWindow) - { - Compat::Log() << "ERROR: Failed to create a message-only window"; - return 0; - } - - { - D3dDdi::ScopedCriticalSection lock; - Gdi::WinProc::installHooks(); - g_isThreadReady = true; - EnumWindows(initTopLevelWindow, 0); - } - - Compat::closeDbgEng(); - - Overlay::ConfigWindow configWindow; - g_configWindow = &configWindow; - - MSG msg = {}; - while (GetMessage(&msg, nullptr, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - return 0; - } - - LRESULT sendMessageBlocking(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) - { - DWORD_PTR result = 0; - SendMessageTimeout(hwnd, msg, wParam, lParam, SMTO_BLOCK | SMTO_NOTIMEOUTIFNOTHUNG, 0, &result); - return result; + return CALL_ORIG_FUNC(DefWindowProcA)(hwnd, uMsg, wParam, lParam); } } @@ -162,20 +19,28 @@ namespace Gdi { namespace PresentationWindow { - HWND create(HWND owner, WNDPROC wndProc) + HWND create(HWND owner) { - return reinterpret_cast(sendMessageBlocking(g_messageWindow, WM_CREATEPRESENTATIONWINDOW, - reinterpret_cast(owner), reinterpret_cast(wndProc))); - } + HWND presentationWindow = nullptr; + GuiThread::execute([&]() + { + presentationWindow = GuiThread::createWindow( + WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_NOPARENTNOTIFY | WS_EX_TOOLWINDOW, + reinterpret_cast(g_classAtom), + nullptr, + WS_DISABLED | WS_POPUP, + 0, 0, 1, 1, + owner, + nullptr, + nullptr, + nullptr); - void destroy(HWND hwnd) - { - PostMessage(hwnd, WM_CLOSE, 0, 0); - } - - Overlay::ConfigWindow* getConfigWindow() - { - return g_configWindow; + if (presentationWindow) + { + CALL_ORIG_FUNC(SetLayeredWindowAttributes)(presentationWindow, 0, 255, LWA_ALPHA); + } + }); + return presentationWindow; } void installHooks() @@ -184,35 +49,7 @@ namespace Gdi wc.lpfnWndProc = &presentationWindowProc; wc.hInstance = Dll::g_currentModule; wc.lpszClassName = "DDrawCompatPresentationWindow"; - CALL_ORIG_FUNC(RegisterClassA)(&wc); - - g_presentationWindowThread = Dll::createThread(presentationWindowThreadProc, &g_presentationWindowThreadId, - THREAD_PRIORITY_TIME_CRITICAL, CREATE_SUSPENDED); - } - - bool isPresentationWindow(HWND hwnd) - { - return GetWindowThreadProcessId(hwnd, nullptr) == g_presentationWindowThreadId; - } - - bool isThreadReady() - { - return g_isThreadReady; - } - - void setWindowPos(HWND hwnd, const WINDOWPOS& wp) - { - sendMessageBlocking(hwnd, WM_SETPRESENTATIONWINDOWPOS, 0, reinterpret_cast(&wp)); - } - - void setWindowRgn(HWND hwnd, HRGN rgn) - { - sendMessageBlocking(hwnd, WM_SETPRESENTATIONWINDOWRGN, reinterpret_cast(rgn), 0); - } - - void startThread() - { - ResumeThread(g_presentationWindowThread); + g_classAtom = CALL_ORIG_FUNC(RegisterClassA)(&wc); } } } diff --git a/DDrawCompat/Gdi/PresentationWindow.h b/DDrawCompat/Gdi/PresentationWindow.h index 31223e1..4f5f519 100644 --- a/DDrawCompat/Gdi/PresentationWindow.h +++ b/DDrawCompat/Gdi/PresentationWindow.h @@ -2,23 +2,11 @@ #include -namespace Overlay -{ - class ConfigWindow; -} - namespace Gdi { namespace PresentationWindow { - HWND create(HWND owner, WNDPROC wndProc = nullptr); - void destroy(HWND hwnd); - Overlay::ConfigWindow* getConfigWindow(); - bool isPresentationWindow(HWND hwnd); - bool isThreadReady(); - void setWindowPos(HWND hwnd, const WINDOWPOS& wp); - void setWindowRgn(HWND hwnd, HRGN rgn); - void startThread(); + HWND create(HWND owner); void installHooks(); } diff --git a/DDrawCompat/Gdi/User32WndProcs.cpp b/DDrawCompat/Gdi/User32WndProcs.cpp index b771a5b..a5dd531 100644 --- a/DDrawCompat/Gdi/User32WndProcs.cpp +++ b/DDrawCompat/Gdi/User32WndProcs.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include @@ -319,7 +319,7 @@ namespace if (wp.x + wp.cx > mr.right) { HWND parent = GetNextWindow(wp.hwnd, GW_HWNDNEXT); - while (Gdi::PresentationWindow::isPresentationWindow(parent)) + while (Gdi::GuiThread::isGuiThreadWindow(parent)) { parent = GetNextWindow(parent, GW_HWNDNEXT); } diff --git a/DDrawCompat/Gdi/WinProc.cpp b/DDrawCompat/Gdi/WinProc.cpp index 95efb3c..0d2d121 100644 --- a/DDrawCompat/Gdi/WinProc.cpp +++ b/DDrawCompat/Gdi/WinProc.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -39,7 +40,6 @@ namespace WindowProc getWindowProc(HWND hwnd); bool isTopLevelWindow(HWND hwnd); bool isUser32ScrollBar(HWND hwnd); - void onCreateWindow(HWND hwnd); void onDestroyWindow(HWND hwnd); void onGetMinMaxInfo(MINMAXINFO& mmi); void onInitMenuPopup(HMENU menu); @@ -95,12 +95,15 @@ namespace case WM_ACTIVATEAPP: if (!wParam) { - auto configWindow = Gdi::PresentationWindow::getConfigWindow(); - if (configWindow) - { - configWindow->setVisible(false); - } - CALL_ORIG_FUNC(ClipCursor)(nullptr); + Gdi::GuiThread::execute([&]() + { + auto configWindow = Gdi::GuiThread::getConfigWindow(); + if (configWindow) + { + configWindow->setVisible(false); + } + CALL_ORIG_FUNC(ClipCursor)(nullptr); + }); } break; @@ -202,40 +205,6 @@ namespace IsWindowUnicode(hwnd) ? it->second.wndProcW : it->second.wndProcA); } - void onCreateWindow(HWND hwnd) - { - LOG_FUNC("onCreateWindow", hwnd); - - { - Compat::ScopedSrwLockExclusive lock(g_windowProcSrwLock); - if (g_windowProc.find(hwnd) != g_windowProc.end()) - { - return; - } - - auto wndProcA = reinterpret_cast(CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_WNDPROC)); - auto wndProcW = reinterpret_cast(CALL_ORIG_FUNC(GetWindowLongW)(hwnd, GWL_WNDPROC)); - g_windowProc[hwnd] = { wndProcA, wndProcW }; - setWindowProc(hwnd, ddcWindowProcA, ddcWindowProcW); - } - - if (!isTopLevelWindow(hwnd)) - { - return; - } - - char className[64] = {}; - GetClassName(hwnd, className, sizeof(className)); - if (std::string(className) == "CompatWindowDesktopReplacement") - { - // Disable VirtualizeDesktopPainting shim - SendNotifyMessage(hwnd, WM_CLOSE, 0, 0); - return; - } - - Gdi::Window::updateAll(); - } - void onDestroyWindow(HWND hwnd) { if (isTopLevelWindow(hwnd)) @@ -415,9 +384,9 @@ namespace switch (event) { case EVENT_OBJECT_CREATE: - if (OBJID_WINDOW == idObject && !Gdi::PresentationWindow::isPresentationWindow(hwnd)) + if (OBJID_WINDOW == idObject) { - onCreateWindow(hwnd); + Gdi::WinProc::onCreateWindow(hwnd); } break; @@ -511,10 +480,40 @@ namespace Gdi void onCreateWindow(HWND hwnd) { - if (PresentationWindow::isThreadReady()) + LOG_FUNC("onCreateWindow", hwnd); + if (!GuiThread::isReady() || GuiThread::isGuiThreadWindow(hwnd)) { - ::onCreateWindow(hwnd); + return; } + + { + Compat::ScopedSrwLockExclusive lock(g_windowProcSrwLock); + if (g_windowProc.find(hwnd) != g_windowProc.end()) + { + return; + } + + auto wndProcA = reinterpret_cast(CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_WNDPROC)); + auto wndProcW = reinterpret_cast(CALL_ORIG_FUNC(GetWindowLongW)(hwnd, GWL_WNDPROC)); + g_windowProc[hwnd] = { wndProcA, wndProcW }; + setWindowProc(hwnd, ddcWindowProcA, ddcWindowProcW); + } + + if (!isTopLevelWindow(hwnd)) + { + return; + } + + char className[64] = {}; + GetClassName(hwnd, className, sizeof(className)); + if (std::string(className) == "CompatWindowDesktopReplacement") + { + // Disable VirtualizeDesktopPainting shim + SendNotifyMessage(hwnd, WM_CLOSE, 0, 0); + return; + } + + Gdi::Window::updateAll(); } void watchWindowPosChanges(WindowPosChangeNotifyFunc notifyFunc) diff --git a/DDrawCompat/Gdi/Window.cpp b/DDrawCompat/Gdi/Window.cpp index 656b7c1..13f0636 100644 --- a/DDrawCompat/Gdi/Window.cpp +++ b/DDrawCompat/Gdi/Window.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -249,7 +250,7 @@ namespace DWORD processId = 0; GetWindowThreadProcessId(hwnd, &processId); if (processId != context.processId || - Gdi::PresentationWindow::isPresentationWindow(hwnd)) + Gdi::GuiThread::isGuiThreadWindow(hwnd)) { return TRUE; } @@ -277,7 +278,7 @@ namespace } else if (it->second.presentationWindow) { - Gdi::PresentationWindow::destroy(it->second.presentationWindow); + Gdi::GuiThread::destroyWindow(it->second.presentationWindow); it->second.presentationWindow = nullptr; } } @@ -351,7 +352,7 @@ namespace { if (setPresentationWindowRgn) { - Gdi::PresentationWindow::setWindowRgn(it->second.presentationWindow, it->second.windowRegion); + Gdi::GuiThread::setWindowRgn(it->second.presentationWindow, it->second.windowRegion); } WINDOWPOS wp = {}; @@ -379,7 +380,11 @@ namespace wp.flags |= SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER; } - Gdi::PresentationWindow::setWindowPos(it->second.presentationWindow, wp); + Gdi::GuiThread::execute([&]() + { + CALL_ORIG_FUNC(SetWindowPos)(it->second.presentationWindow, + wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags); + }); } } return TRUE; @@ -524,7 +529,7 @@ namespace Gdi } RECT wr = {}; - auto configWindow = PresentationWindow::getConfigWindow(); + auto configWindow = GuiThread::getConfigWindow(); if (configWindow && configWindow->isVisible()) { GetWindowRect(configWindow->getWindow(), &wr); @@ -550,7 +555,7 @@ namespace Gdi void updateAll() { LOG_FUNC("Window::updateAll"); - if (!Gdi::PresentationWindow::isThreadReady()) + if (!GuiThread::isReady()) { return; } @@ -571,7 +576,7 @@ namespace Gdi { if (it->second.presentationWindow) { - Gdi::PresentationWindow::destroy(it->second.presentationWindow); + GuiThread::destroyWindow(it->second.presentationWindow); } it = g_windows.erase(it); } diff --git a/DDrawCompat/Input/Input.cpp b/DDrawCompat/Input/Input.cpp index 19c0880..9622fcd 100644 --- a/DDrawCompat/Input/Input.cpp +++ b/DDrawCompat/Input/Input.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -21,9 +22,6 @@ namespace void* context; }; - const UINT WM_USER_HOTKEY = WM_USER; - const UINT WM_USER_RESET_HOOK = WM_USER + 1; - HANDLE g_bmpArrow = nullptr; SIZE g_bmpArrowSize = {}; Overlay::Window* g_capture = nullptr; @@ -31,7 +29,6 @@ namespace HWND g_cursorWindow = nullptr; std::map g_hotKeys; RECT g_monitorRect = {}; - DWORD g_inputThreadId = 0; HHOOK g_keyboardHook = nullptr; HHOOK g_mouseHook = nullptr; @@ -65,72 +62,22 @@ namespace return CALL_ORIG_FUNC(DefWindowProcA)(hwnd, uMsg, wParam, lParam); } - unsigned WINAPI inputThreadProc(LPVOID /*lpParameter*/) - { - g_inputThreadId = GetCurrentThreadId(); - g_bmpArrow = CALL_ORIG_FUNC(LoadImageA)(Dll::g_currentModule, "BMP_ARROW", IMAGE_BITMAP, 0, 0, 0); - - BITMAP bm = {}; - GetObject(g_bmpArrow, sizeof(bm), &bm); - g_bmpArrowSize = { bm.bmWidth, bm.bmHeight }; - - g_keyboardHook = CALL_ORIG_FUNC(SetWindowsHookExA)(WH_KEYBOARD_LL, &lowLevelKeyboardProc, Dll::g_currentModule, 0); - - MSG msg = {}; - while (GetMessage(&msg, nullptr, 0, 0)) - { - if (msg.message == WM_TIMER && !msg.hwnd && msg.lParam) - { - reinterpret_cast(msg.lParam)(nullptr, WM_TIMER, msg.wParam, 0); - } - if (!msg.hwnd) - { - if (WM_USER_HOTKEY == msg.message) - { - DWORD pid = 0; - GetWindowThreadProcessId(GetForegroundWindow(), &pid); - if (GetCurrentProcessId() == pid) - { - auto it = std::find_if(g_hotKeys.begin(), g_hotKeys.end(), - [&](const auto& v) { return v.first.vk == msg.wParam; }); - if (it != g_hotKeys.end()) - { - it->second.action(it->second.context); - } - } - } - else if (WM_USER_RESET_HOOK == msg.message) - { - if (msg.wParam == WH_KEYBOARD_LL) - { - UnhookWindowsHookEx(g_keyboardHook); - g_keyboardHook = CALL_ORIG_FUNC(SetWindowsHookExA)( - WH_KEYBOARD_LL, &lowLevelKeyboardProc, Dll::g_currentModule, 0); - } - else if (msg.wParam == WH_MOUSE_LL && g_mouseHook) - { - UnhookWindowsHookEx(g_mouseHook); - g_mouseHook = CALL_ORIG_FUNC(SetWindowsHookExA)( - WH_MOUSE_LL, &lowLevelMouseProc, Dll::g_currentModule, 0); - } - } - } - else - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - - return 0; - } - LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { if (HC_ACTION == nCode && (WM_KEYDOWN == wParam || WM_SYSKEYDOWN == wParam)) { - auto llHook = reinterpret_cast(lParam); - PostThreadMessage(GetCurrentThreadId(), WM_USER_HOTKEY, llHook->vkCode, llHook->scanCode); + DWORD pid = 0; + GetWindowThreadProcessId(GetForegroundWindow(), &pid); + if (GetCurrentProcessId() == pid) + { + auto llHook = reinterpret_cast(lParam); + auto it = std::find_if(g_hotKeys.begin(), g_hotKeys.end(), + [&](const auto& v) { return v.first.vk == llHook->vkCode; }); + if (it != g_hotKeys.end()) + { + it->second.action(it->second.context); + } + } } return CallNextHookEx(nullptr, nCode, wParam, lParam); } @@ -174,6 +121,32 @@ namespace return CallNextHookEx(nullptr, nCode, wParam, lParam); } + void resetKeyboardHook() + { + Gdi::GuiThread::execute([]() + { + if (g_keyboardHook) + { + UnhookWindowsHookEx(g_keyboardHook); + } + g_keyboardHook = CALL_ORIG_FUNC(SetWindowsHookExA)( + WH_KEYBOARD_LL, &lowLevelKeyboardProc, Dll::g_currentModule, 0); + }); + } + + void resetMouseHook() + { + Gdi::GuiThread::execute([]() + { + if (g_mouseHook) + { + UnhookWindowsHookEx(g_mouseHook); + } + g_mouseHook = CALL_ORIG_FUNC(SetWindowsHookExA)( + WH_MOUSE_LL, &lowLevelMouseProc, Dll::g_currentModule, 0); + }); + } + void setCursorPos(POINT cp) { g_cursorPos = cp; @@ -191,9 +164,16 @@ namespace } HHOOK result = origSetWindowsHookEx(idHook, lpfn, hmod, dwThreadId); - if (result && g_inputThreadId && (WH_KEYBOARD_LL == idHook || WH_MOUSE_LL == idHook)) + if (result) { - PostThreadMessage(g_inputThreadId, WM_USER_RESET_HOOK, idHook, 0); + if (WH_KEYBOARD_LL == idHook) + { + resetKeyboardHook(); + } + else if (WH_MOUSE_LL == idHook && g_mouseHook) + { + resetMouseHook(); + } } return result; } @@ -235,16 +215,22 @@ namespace Input void installHooks() { + g_bmpArrow = CALL_ORIG_FUNC(LoadImageA)(Dll::g_currentModule, "BMP_ARROW", IMAGE_BITMAP, 0, 0, 0); + + BITMAP bm = {}; + GetObject(g_bmpArrow, sizeof(bm), &bm); + g_bmpArrowSize = { bm.bmWidth, bm.bmHeight }; + HOOK_FUNCTION(user32, SetWindowsHookExA, setWindowsHookExA); HOOK_FUNCTION(user32, SetWindowsHookExW, setWindowsHookExW); } void registerHotKey(const HotKey& hotKey, std::function action, void* context) { - static HANDLE thread = Dll::createThread(&inputThreadProc, nullptr, THREAD_PRIORITY_TIME_CRITICAL); - if (thread) + g_hotKeys[hotKey] = { action, context }; + if (!g_keyboardHook) { - g_hotKeys[hotKey] = { action, context }; + resetKeyboardHook(); } } @@ -255,7 +241,8 @@ namespace Input { if (!g_mouseHook) { - g_cursorWindow = Gdi::PresentationWindow::create(window->getWindow(), &cursorWindowProc); + g_cursorWindow = Gdi::PresentationWindow::create(window->getWindow()); + CALL_ORIG_FUNC(SetWindowLongA)(g_cursorWindow, GWL_WNDPROC, reinterpret_cast(&cursorWindowProc)); CALL_ORIG_FUNC(SetLayeredWindowAttributes)(g_cursorWindow, RGB(0xFF, 0xFF, 0xFF), 0, LWA_COLORKEY); MONITORINFO mi = {}; @@ -266,17 +253,16 @@ namespace Input RECT r = window->getRect(); g_cursorPos = { (r.left + r.right) / 2, (r.top + r.bottom) / 2 }; CALL_ORIG_FUNC(SetWindowPos)(g_cursorWindow, HWND_TOPMOST, g_cursorPos.x, g_cursorPos.y, - g_bmpArrowSize.cx, g_bmpArrowSize.cy, SWP_NOACTIVATE | SWP_NOSENDCHANGING); - ShowWindow(g_cursorWindow, SW_SHOW); + g_bmpArrowSize.cx, g_bmpArrowSize.cy, SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_SHOWWINDOW); - g_mouseHook = CALL_ORIG_FUNC(SetWindowsHookExA)(WH_MOUSE_LL, &lowLevelMouseProc, Dll::g_currentModule, 0); + resetMouseHook(); } } else if (g_mouseHook) { UnhookWindowsHookEx(g_mouseHook); g_mouseHook = nullptr; - PostMessage(g_cursorWindow, WM_CLOSE, 0, 0); + Gdi::GuiThread::destroyWindow(g_cursorWindow); g_cursorWindow = nullptr; } } diff --git a/DDrawCompat/Overlay/Window.cpp b/DDrawCompat/Overlay/Window.cpp index e0d9753..c79f74f 100644 --- a/DDrawCompat/Overlay/Window.cpp +++ b/DDrawCompat/Overlay/Window.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -46,12 +47,14 @@ namespace Overlay { Window::Window(Window* parentWindow, const RECT& rect, const Input::HotKey& hotKey) : Control(nullptr, rect, WS_BORDER) - , m_hwnd(Gdi::PresentationWindow::create(parentWindow ? parentWindow->m_hwnd : nullptr, &staticWindowProc)) + , m_hwnd(Gdi::PresentationWindow::create(parentWindow ? parentWindow->m_hwnd : nullptr)) , m_parentWindow(parentWindow) , m_transparency(25) { g_windows.emplace(m_hwnd, *this); + CALL_ORIG_FUNC(SetWindowLongA)(m_hwnd, GWL_WNDPROC, reinterpret_cast(&staticWindowProc)); setTransparency(m_transparency); + if (0 != hotKey.vk) { Input::registerHotKey(hotKey, &toggleWindow, this); @@ -60,7 +63,7 @@ namespace Overlay Window::~Window() { - Gdi::PresentationWindow::destroy(m_hwnd); + Gdi::GuiThread::destroyWindow(m_hwnd); g_windows.erase(m_hwnd); } @@ -122,7 +125,7 @@ namespace Overlay else { auto capture = Input::getCapture(); - if (capture != this && capture->m_parentWindow == this) + if (capture && capture != this && capture->m_parentWindow == this) { capture->setVisible(false); } @@ -133,7 +136,12 @@ namespace Overlay LRESULT CALLBACK Window::staticWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - return g_windows.find(hwnd)->second.windowProc(uMsg, wParam, lParam); + auto it = g_windows.find(hwnd); + if (it != g_windows.end()) + { + return it->second.windowProc(uMsg, wParam, lParam); + } + return CALL_ORIG_FUNC(DefWindowProcA)(hwnd, uMsg, wParam, lParam); } void Window::updatePos() diff --git a/DDrawCompat/Win32/DisplayMode.cpp b/DDrawCompat/Win32/DisplayMode.cpp index dec79d8..19dcd51 100644 --- a/DDrawCompat/Win32/DisplayMode.cpp +++ b/DDrawCompat/Win32/DisplayMode.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -672,7 +673,7 @@ namespace { DWORD pid = 0; GetWindowThreadProcessId(hwnd, &pid); - if (GetCurrentProcessId() == pid) + if (GetCurrentProcessId() == pid && !Gdi::GuiThread::isGuiThreadWindow(hwnd)) { SendNotifyMessage(hwnd, WM_DISPLAYCHANGE, 0, lParam); }