From 2f00b74a56aa4d5d42f8f50417f1460e6ac72bf5 Mon Sep 17 00:00:00 2001 From: narzoul Date: Sat, 20 Oct 2018 17:49:00 +0200 Subject: [PATCH] Fixed display issues with user32 controls --- DDrawCompat/Common/Log.cpp | 9 +- DDrawCompat/DDraw/RealPrimarySurface.cpp | 104 +++---- DDrawCompat/Gdi/Dc.cpp | 43 +-- DDrawCompat/Gdi/Dc.h | 1 - DDrawCompat/Gdi/DcFunctions.cpp | 133 ++++----- DDrawCompat/Gdi/Gdi.cpp | 10 - DDrawCompat/Gdi/Gdi.h | 3 +- DDrawCompat/Gdi/PaintHandlers.cpp | 347 ++++++++++++++++------- DDrawCompat/Gdi/ScrollFunctions.cpp | 15 +- DDrawCompat/Gdi/VirtualScreen.cpp | 64 +++-- DDrawCompat/Gdi/VirtualScreen.h | 1 + DDrawCompat/Gdi/WinProc.cpp | 39 +-- DDrawCompat/Gdi/Window.cpp | 114 +++++--- DDrawCompat/Gdi/Window.h | 10 +- DDrawCompat/Win32/Registry.cpp | 2 +- 15 files changed, 510 insertions(+), 385 deletions(-) diff --git a/DDrawCompat/Common/Log.cpp b/DDrawCompat/Common/Log.cpp index 81b5cd6..b23e33b 100644 --- a/DDrawCompat/Common/Log.cpp +++ b/DDrawCompat/Common/Log.cpp @@ -96,10 +96,13 @@ std::ostream& operator<<(std::ostream& os, HRGN__& rgn) std::ostream& operator<<(std::ostream& os, HWND__& hwnd) { - char name[256] = {}; - GetClassName(&hwnd, name, sizeof(name)); + char name[256] = "INVALID"; RECT rect = {}; - GetWindowRect(&hwnd, &rect); + if (IsWindow(&hwnd)) + { + GetClassName(&hwnd, name, sizeof(name)); + GetWindowRect(&hwnd, &rect); + } return os << "WND(" << static_cast(&hwnd) << ',' << name << ',' << rect << ')'; } diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index 969400b..4179222 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -22,18 +22,6 @@ namespace { - struct BltToWindowViaGdiArgs - { - std::unique_ptr virtualScreenDc; - Gdi::Region* primaryRegion; - - BltToWindowViaGdiArgs() - : virtualScreenDc(nullptr, &Gdi::VirtualScreen::deleteDc) - , primaryRegion(nullptr) - { - } - }; - void onRelease(); DWORD WINAPI updateThreadProc(LPVOID lpParameter); @@ -70,65 +58,61 @@ namespace return TRUE; } - BOOL CALLBACK bltToWindow(HWND hwnd, LPARAM lParam) + void bltToWindow(CompatRef src) { - if (!IsWindowVisible(hwnd) || !Gdi::Window::isPresentationWindow(hwnd)) + for (auto windowPair : Gdi::Window::getWindows()) { - return TRUE; + if (IsWindowVisible(windowPair.first)) + { + g_clipper->SetHWnd(g_clipper, 0, windowPair.second->getPresentationWindow()); + g_frontBuffer->Blt(g_frontBuffer, nullptr, &src, nullptr, DDBLT_WAIT, nullptr); + } } - - g_clipper->SetHWnd(g_clipper, 0, hwnd); - auto src = reinterpret_cast(lParam); - g_frontBuffer->Blt(g_frontBuffer, nullptr, src, nullptr, DDBLT_WAIT, nullptr); - return TRUE; } - BOOL CALLBACK bltToWindowViaGdi(HWND hwnd, LPARAM lParam) + void bltToWindowViaGdi(Gdi::Region* primaryRegion) { - if (!IsWindowVisible(hwnd) || !Gdi::Window::isPresentationWindow(hwnd)) - { - return TRUE; - } + std::unique_ptr virtualScreenDc(nullptr, &Gdi::VirtualScreen::deleteDc); - auto window = Gdi::Window::get(GetParent(hwnd)); - if (!window) + for (auto windowPair : Gdi::Window::getWindows()) { - return TRUE; - } + if (!IsWindowVisible(windowPair.first)) + { + continue; + } - Gdi::Region visibleRegion = window->getVisibleRegion(); - if (visibleRegion.isEmpty()) - { - return TRUE; - } - - auto& args = *reinterpret_cast(lParam); - if (args.primaryRegion) - { - visibleRegion -= *args.primaryRegion; + Gdi::Region visibleRegion = windowPair.second->getVisibleRegion(); if (visibleRegion.isEmpty()) { - return TRUE; + continue; } - } - if (!args.virtualScreenDc) - { - args.virtualScreenDc.reset(Gdi::VirtualScreen::createDc()); - if (!args.virtualScreenDc) + if (primaryRegion) { - return FALSE; + visibleRegion -= *primaryRegion; + if (visibleRegion.isEmpty()) + { + continue; + } } + + if (!virtualScreenDc) + { + virtualScreenDc.reset(Gdi::VirtualScreen::createDc()); + if (!virtualScreenDc) + { + return; + } + } + + Gdi::GdiAccessGuard gdiAccessGuard(Gdi::ACCESS_READ); + HWND presentationWindow = windowPair.second->getPresentationWindow(); + HDC dc = GetWindowDC(presentationWindow); + RECT rect = windowPair.second->getWindowRect(); + CALL_ORIG_FUNC(BitBlt)(dc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, + virtualScreenDc.get(), rect.left, rect.top, SRCCOPY); + ReleaseDC(presentationWindow, dc); } - - Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_READ); - HDC presentationWindowDc = GetWindowDC(hwnd); - RECT rect = window->getWindowRect(); - CALL_ORIG_FUNC(BitBlt)(presentationWindowDc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, - args.virtualScreenDc.get(), rect.left, rect.top, SRCCOPY); - ReleaseDC(hwnd, presentationWindowDc); - - return TRUE; } void bltVisibleLayeredWindowsToBackBuffer() @@ -174,7 +158,7 @@ namespace { if (!g_isFullScreen) { - EnumThreadWindows(Gdi::getGdiThreadId(), bltToWindow, reinterpret_cast(&src)); + bltToWindow(src); return; } @@ -364,19 +348,15 @@ namespace Gdi::VirtualScreen::update(); - BltToWindowViaGdiArgs bltToWindowViaGdiArgs; if (!g_frontBuffer || !src || DDraw::RealPrimarySurface::isLost()) { - EnumThreadWindows(Gdi::getGdiThreadId(), bltToWindowViaGdi, - reinterpret_cast(&bltToWindowViaGdiArgs)); + bltToWindowViaGdi(nullptr); Compat::LogLeave("RealPrimarySurface::presentToPrimaryChain", src.get()) << false; return; } Gdi::Region primaryRegion(D3dDdi::KernelModeThunks::getMonitorRect()); - bltToWindowViaGdiArgs.primaryRegion = &primaryRegion; - EnumThreadWindows(Gdi::getGdiThreadId(), bltToWindowViaGdi, - reinterpret_cast(&bltToWindowViaGdiArgs)); + bltToWindowViaGdi(&primaryRegion); Gdi::DDrawAccessGuard accessGuard(Gdi::ACCESS_READ, DDraw::PrimarySurface::isGdiSurface(src.get())); if (DDraw::PrimarySurface::getDesc().ddpfPixelFormat.dwRGBBitCount <= 8) diff --git a/DDrawCompat/Gdi/Dc.cpp b/DDrawCompat/Gdi/Dc.cpp index 0c08796..a6c63d3 100644 --- a/DDrawCompat/Gdi/Dc.cpp +++ b/DDrawCompat/Gdi/Dc.cpp @@ -4,7 +4,7 @@ #include "Common/Hook.h" #include "Common/Log.h" -#include "Common/ScopedCriticalSection.h" +#include "DDraw/ScopedThreadLock.h" #include "Gdi/Dc.h" #include "Gdi/DcCache.h" #include "Gdi/Gdi.h" @@ -24,7 +24,6 @@ namespace typedef std::unique_ptr OrigDc; typedef std::unordered_map CompatDcMap; - CRITICAL_SECTION g_cs; CompatDcMap g_origDcToCompatDc; thread_local std::vector g_threadDcs; @@ -82,7 +81,7 @@ namespace void deleteDc(HDC origDc) { - Compat::ScopedCriticalSection lock(g_cs); + DDraw::ScopedThreadLock lock; auto it = g_origDcToCompatDc.find(origDc); RestoreDC(it->second.dc, it->second.savedState); Gdi::DcCache::deleteDc(it->second.dc); @@ -110,24 +109,6 @@ namespace } DeleteObject(clipRgn); } - - void updateWindow(HWND wnd) - { - auto window = Gdi::Window::get(wnd); - if (!window) - { - return; - } - - RECT windowRect = {}; - GetWindowRect(wnd, &windowRect); - - RECT cachedWindowRect = window->getWindowRect(); - if (!EqualRect(&windowRect, &cachedWindowRect)) - { - Gdi::Window::updateAll(); - } - } } namespace Gdi @@ -141,7 +122,7 @@ namespace Gdi return nullptr; } - Compat::ScopedCriticalSection lock(g_cs); + DDraw::ScopedThreadLock lock; auto it = g_origDcToCompatDc.find(origDc); if (it != g_origDcToCompatDc.end()) { @@ -150,10 +131,15 @@ namespace Gdi } const HWND wnd = CALL_ORIG_FUNC(WindowFromDC)(origDc); - const HWND rootWnd = wnd ? GetAncestor(wnd, GA_ROOT) : nullptr; + auto rootWnd = wnd ? GetAncestor(wnd, GA_ROOT) : nullptr; if (rootWnd && GetDesktopWindow() != rootWnd) { - updateWindow(rootWnd); + auto rootWindow(Window::get(rootWnd)); + if (!rootWindow) + { + return nullptr; + } + rootWindow->updateWindow(); } CompatDc compatDc; @@ -183,20 +169,15 @@ namespace Gdi HDC getOrigDc(HDC dc) { - Compat::ScopedCriticalSection lock(g_cs); + DDraw::ScopedThreadLock lock; const auto it = std::find_if(g_origDcToCompatDc.begin(), g_origDcToCompatDc.end(), [dc](const CompatDcMap::value_type& compatDc) { return compatDc.second.dc == dc; }); return it != g_origDcToCompatDc.end() ? it->first : dc; } - void init() - { - InitializeCriticalSection(&g_cs); - } - void releaseDc(HDC origDc) { - Compat::ScopedCriticalSection lock(g_cs); + DDraw::ScopedThreadLock lock; auto it = g_origDcToCompatDc.find(origDc); if (it == g_origDcToCompatDc.end()) { diff --git a/DDrawCompat/Gdi/Dc.h b/DDrawCompat/Gdi/Dc.h index 36e2971..a3a78e1 100644 --- a/DDrawCompat/Gdi/Dc.h +++ b/DDrawCompat/Gdi/Dc.h @@ -10,7 +10,6 @@ namespace Gdi { HDC getDc(HDC origDc); HDC getOrigDc(HDC dc); - void init(); void releaseDc(HDC origDc); } } diff --git a/DDrawCompat/Gdi/DcFunctions.cpp b/DDrawCompat/Gdi/DcFunctions.cpp index 15659cf..b67ea34 100644 --- a/DDrawCompat/Gdi/DcFunctions.cpp +++ b/DDrawCompat/Gdi/DcFunctions.cpp @@ -6,7 +6,9 @@ #include "Gdi/Dc.h" #include "Gdi/DcFunctions.h" #include "Gdi/Gdi.h" +#include "Gdi/Region.h" #include "Gdi/VirtualScreen.h" +#include "Gdi/Window.h" #include "Win32/DisplayMode.h" namespace @@ -20,7 +22,7 @@ namespace std::unordered_map g_funcNames; template - DWORD getDdLockFlags(Params... params); + HDC getDestinationDc(Params... params); HRGN getWindowRegion(HWND hwnd); @@ -85,7 +87,7 @@ namespace Result result = 0; if (hasDisplayDcArg(params...)) { - const bool isReadOnlyAccess = getDdLockFlags(params...) & DDLOCK_READONLY; + const bool isReadOnlyAccess = !hasDisplayDcArg(getDestinationDc(params...)); Gdi::GdiAccessGuard accessGuard(isReadOnlyAccess ? Gdi::ACCESS_READ : Gdi::ACCESS_WRITE); result = Compat::getOrigFuncPtr()(replaceDc(params)...); releaseDc(params...); @@ -102,6 +104,49 @@ namespace return result; } + template <> + BOOL WINAPI compatGdiDcFunc( + HDC hdc, int x, int y, UINT options, const RECT* lprect, LPCWSTR lpString, UINT c, const INT* lpDx) + { + Compat::LogEnter("ExtTextOutW", hdc, x, y, options, lprect, lpString, c, lpDx); + + BOOL result = TRUE; + if (hasDisplayDcArg(hdc)) + { + HWND hwnd = CALL_ORIG_FUNC(WindowFromDC)(hdc); + ATOM atom = static_cast(GetClassLong(hwnd, GCW_ATOM)); + POINT p = { x, y }; + if (Gdi::MENU_ATOM == atom) + { + RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE); + } + else if (GetCurrentThreadId() == GetWindowThreadProcessId(hwnd, nullptr) && + LPtoDP(hdc, &p, 1) && + HTMENU == SendMessage(hwnd, WM_NCHITTEST, 0, (p.y << 16) | (p.x & 0xFFFF))) + { + WINDOWINFO wi = {}; + GetWindowInfo(hwnd, &wi); + Gdi::Region ncRegion(wi.rcWindow); + ncRegion -= wi.rcClient; + ncRegion.offset(-wi.rcClient.left, -wi.rcClient.top); + RedrawWindow(hwnd, nullptr, ncRegion, RDW_INVALIDATE | RDW_FRAME); + } + else + { + Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE); + result = CALL_ORIG_FUNC(ExtTextOutW)(replaceDc(hdc), x, y, options, lprect, lpString, c, lpDx); + releaseDc(hdc); + } + } + else + { + result = CALL_ORIG_FUNC(ExtTextOutW)(hdc, x, y, options, lprect, lpString, c, lpDx); + } + + Compat::LogLeave("ExtTextOutW", hdc, x, y, options, lprect, lpString, c, lpDx) << result; + return result; + } + BOOL CALLBACK excludeRgnForOverlappingWindow(HWND hwnd, LPARAM lParam) { auto& args = *reinterpret_cast(lParam); @@ -129,84 +174,40 @@ namespace return &compatGdiDcFunc; } - DWORD getDdLockFlagsBlt(HDC hdcDest, HDC hdcSrc) + HDC getFirstDc() { - return hasDisplayDcArg(hdcSrc) && !hasDisplayDcArg(hdcDest) ? DDLOCK_READONLY : 0; + return nullptr; + } + + template + HDC getFirstDc(HDC dc, Params...) + { + return dc; + } + + template + HDC getFirstDc(FirstParam, Params... params) + { + return getFirstDc(params...); } template - DWORD getDdLockFlags(Params...) + HDC getDestinationDc(Params... params) { - return 0; + return getFirstDc(params...); } template <> - DWORD getDdLockFlags( - HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, int, int, BLENDFUNCTION) - { - return getDdLockFlagsBlt(hdcDest, hdcSrc); - } - - template <> - DWORD getDdLockFlags( - HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, DWORD) - { - return getDdLockFlagsBlt(hdcDest, hdcSrc); - } - - template <> - DWORD getDdLockFlags( - HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, int, int, BLENDFUNCTION) - { - return getDdLockFlagsBlt(hdcDest, hdcSrc); - } - - template <> - DWORD getDdLockFlags( - HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, int, int, UINT) - { - return getDdLockFlagsBlt(hdcDest, hdcSrc); - } - - template <> - DWORD getDdLockFlags( + HDC getDestinationDc( HDC, HBITMAP, UINT, UINT, LPVOID, LPBITMAPINFO, UINT) { - return DDLOCK_READONLY; + return nullptr; } template <> - DWORD getDdLockFlags(HDC, int, int) + HDC getDestinationDc(HDC, int, int) { - return DDLOCK_READONLY; - } - - template <> - DWORD getDdLockFlags( - HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, HBITMAP, int, int, DWORD) - { - return getDdLockFlagsBlt(hdcDest, hdcSrc); - } - - template <> - DWORD getDdLockFlags( - HDC hdcDest, const POINT*, HDC hdcSrc, int, int, int, int, HBITMAP, int, int) - { - return getDdLockFlagsBlt(hdcDest, hdcSrc); - } - - template <> - DWORD getDdLockFlags( - HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, int, int, DWORD) - { - return getDdLockFlagsBlt(hdcDest, hdcSrc); - } - - template <> - DWORD getDdLockFlags( - HDC hdcDest, int, int, int, int, HDC hdcSrc, int, int, int, int, UINT) - { - return getDdLockFlagsBlt(hdcDest, hdcSrc); + return nullptr; } HRGN getWindowRegion(HWND hwnd) diff --git a/DDrawCompat/Gdi/Gdi.cpp b/DDrawCompat/Gdi/Gdi.cpp index a2f891e..f63066b 100644 --- a/DDrawCompat/Gdi/Gdi.cpp +++ b/DDrawCompat/Gdi/Gdi.cpp @@ -1,6 +1,5 @@ #include "DDraw/Surfaces/PrimarySurface.h" #include "Gdi/Caret.h" -#include "Gdi/Dc.h" #include "Gdi/DcFunctions.h" #include "Gdi/Gdi.h" #include "Gdi/PaintHandlers.h" @@ -37,20 +36,11 @@ namespace Gdi return DcFunctions::getVisibleWindowRgn(hwnd); } - void hookWndProc(LPCSTR className, WNDPROC &oldWndProc, WNDPROC newWndProc) - { - HWND hwnd = CreateWindow(className, nullptr, 0, 0, 0, 0, 0, nullptr, nullptr, nullptr, 0); - oldWndProc = reinterpret_cast( - SetClassLongPtr(hwnd, GCLP_WNDPROC, reinterpret_cast(newWndProc))); - DestroyWindow(hwnd); - } - void installHooks() { g_gdiThreadId = GetCurrentThreadId(); g_screenDc = GetDC(nullptr); - Gdi::Dc::init(); Gdi::DcFunctions::installHooks(); Gdi::PaintHandlers::installHooks(); Gdi::ScrollFunctions::installHooks(); diff --git a/DDrawCompat/Gdi/Gdi.h b/DDrawCompat/Gdi/Gdi.h index 1052360..1f7828b 100644 --- a/DDrawCompat/Gdi/Gdi.h +++ b/DDrawCompat/Gdi/Gdi.h @@ -6,12 +6,13 @@ namespace Gdi { + const ATOM MENU_ATOM = 0x8000; + typedef void(*WindowPosChangeNotifyFunc)(); DWORD getGdiThreadId(); HDC getScreenDc(); HRGN getVisibleWindowRgn(HWND hwnd); - void hookWndProc(LPCSTR className, WNDPROC &oldWndProc, WNDPROC newWndProc); void installHooks(); void redraw(HRGN rgn); void redrawWindow(HWND hwnd, HRGN rgn); diff --git a/DDrawCompat/Gdi/PaintHandlers.cpp b/DDrawCompat/Gdi/PaintHandlers.cpp index 4368d8a..da6b59b 100644 --- a/DDrawCompat/Gdi/PaintHandlers.cpp +++ b/DDrawCompat/Gdi/PaintHandlers.cpp @@ -1,3 +1,5 @@ +#include + #include "Common/Hook.h" #include "Common/Log.h" #include "DDraw/RealPrimarySurface.h" @@ -8,56 +10,130 @@ #include "Gdi/ScrollBar.h" #include "Gdi/ScrollFunctions.h" #include "Gdi/TitleBar.h" +#include "Gdi/VirtualScreen.h" +#include "Gdi/Window.h" #include "Win32/Registry.h" namespace { - LRESULT WINAPI defPaintProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, - WNDPROC origWndProc, const char* origWndProcName); + typedef LRESULT(*WndProcHook)(HWND, UINT, WPARAM, LPARAM, WNDPROC); + + struct User32WndProc + { + WNDPROC oldWndProcTrampoline; + WNDPROC oldWndProc; + WNDPROC newWndProc; + std::string name; + + User32WndProc() + : oldWndProcTrampoline(nullptr) + , oldWndProc(nullptr) + , newWndProc(nullptr) + { + } + }; + + LRESULT defPaintProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc); + LRESULT defPaintProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc, + const char* origWndProcName); LRESULT onEraseBackground(HWND hwnd, HDC dc, WNDPROC origWndProc); - LRESULT onMenuPaint(HWND hwnd, WNDPROC origWndProc); LRESULT onNcPaint(HWND hwnd, WPARAM wParam, WNDPROC origWndProc); LRESULT onPaint(HWND hwnd, WNDPROC origWndProc); LRESULT onPrint(HWND hwnd, UINT msg, HDC dc, LONG flags, WNDPROC origWndProc); - WNDPROC g_origButtonWndProc = nullptr; - WNDPROC g_origComboListBoxWndProc = nullptr; - WNDPROC g_origEditWndProc = nullptr; - WNDPROC g_origListBoxWndProc = nullptr; - WNDPROC g_origMenuWndProc = nullptr; - WNDPROC g_origScrollBarWndProc = nullptr; + HHOOK g_cbtProcHook = nullptr; + int g_menuWndProcIndex = 0; + int g_scrollBarWndProcIndex = 0; - LRESULT WINAPI buttonWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) + std::vector g_user32WndProcA; + std::vector g_user32WndProcW; + std::vector g_user32WndProcHook; + + LRESULT buttonWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc) { - Compat::LogEnter("buttonWndProc", hwnd, msg, wParam, lParam); - LRESULT result = 0; - switch (msg) { case WM_PAINT: - result = onPaint(hwnd, g_origButtonWndProc); - break; + return onPaint(hwnd, origWndProc); case WM_ENABLE: case WM_SETTEXT: case BM_SETCHECK: case BM_SETSTATE: - result = CallWindowProc(g_origButtonWndProc, hwnd, msg, wParam, lParam); + { + LRESULT result = CallWindowProc(origWndProc, hwnd, msg, wParam, lParam); RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW); - break; - - default: - result = CallWindowProc(g_origButtonWndProc, hwnd, msg, wParam, lParam); - break; + return result; } - Compat::LogLeave("buttonWndProc", hwnd, msg, wParam, lParam) << result; + default: + return CallWindowProc(origWndProc, hwnd, msg, wParam, lParam); + } + } + + LRESULT CALLBACK cbtProc(int nCode, WPARAM wParam, LPARAM lParam) + { + Compat::LogEnter("cbtProc", Compat::hex(nCode), Compat::hex(wParam), Compat::hex(lParam)); + LRESULT result = 0; + + if (nCode < 0) + { + result = CallNextHookEx(nullptr, nCode, wParam, lParam); + } + else if (HCBT_CREATEWND == nCode) + { + HWND hwnd = reinterpret_cast(wParam); + WNDPROC wndProcA = reinterpret_cast(GetWindowLongA(hwnd, GWL_WNDPROC)); + WNDPROC wndProcW = reinterpret_cast(GetWindowLongW(hwnd, GWL_WNDPROC)); + + int index = -1; + if (wndProcA == g_user32WndProcA[g_menuWndProcIndex].oldWndProc || + wndProcW == g_user32WndProcW[g_menuWndProcIndex].oldWndProc) + { + index = g_menuWndProcIndex; + } + else if (wndProcA == g_user32WndProcA[g_scrollBarWndProcIndex].oldWndProc || + wndProcW == g_user32WndProcW[g_scrollBarWndProcIndex].oldWndProc) + { + index = g_scrollBarWndProcIndex; + } + + if (-1 != index) + { + if (IsWindowUnicode(hwnd)) + { + CALL_ORIG_FUNC(SetWindowLongW)(hwnd, GWL_WNDPROC, + reinterpret_cast(g_user32WndProcW[index].newWndProc)); + } + else + { + CALL_ORIG_FUNC(SetWindowLongA)(hwnd, GWL_WNDPROC, + reinterpret_cast(g_user32WndProcA[index].newWndProc)); + } + } + } + + Compat::LogLeave("cbtProc", Compat::hex(nCode), Compat::hex(wParam), Compat::hex(lParam)) << result; return result; } - LRESULT WINAPI comboListBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) + LRESULT comboBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc) { - return defPaintProc(hwnd, msg, wParam, lParam, g_origComboListBoxWndProc, "comboListBoxWndProc"); + return defPaintProc(hwnd, msg, wParam, lParam, origWndProc); + } + + LRESULT comboListBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc) + { + LRESULT result = defPaintProc(hwnd, msg, wParam, lParam, origWndProc); + + switch (msg) + { + case WM_NCPAINT: + CallWindowProc(origWndProc, hwnd, msg, wParam, lParam); + break; + } + + return result; } LRESULT WINAPI defDlgProcA(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam) @@ -70,38 +146,31 @@ namespace return defPaintProc(hdlg, msg, wParam, lParam, CALL_ORIG_FUNC(DefDlgProcW), "defDlgProcW"); } - LRESULT WINAPI defPaintProc( - HWND hwnd, - UINT msg, - WPARAM wParam, - LPARAM lParam, - WNDPROC origWndProc, - const char* origWndProcName) + LRESULT defPaintProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc) { - Compat::LogEnter(origWndProcName, hwnd, msg, wParam, lParam); - LRESULT result = 0; - switch (msg) { case WM_ERASEBKGND: - result = onEraseBackground(hwnd, reinterpret_cast(wParam), origWndProc); - break; + return onEraseBackground(hwnd, reinterpret_cast(wParam), origWndProc); case WM_NCPAINT: - result = onNcPaint(hwnd, wParam, origWndProc); - break; + return onNcPaint(hwnd, wParam, origWndProc); case WM_PRINT: case WM_PRINTCLIENT: - result = onPrint(hwnd, msg, reinterpret_cast(wParam), lParam, origWndProc); - break; + return onPrint(hwnd, msg, reinterpret_cast(wParam), lParam, origWndProc); default: - result = CallWindowProc(origWndProc, hwnd, msg, wParam, lParam); - break; + return CallWindowProc(origWndProc, hwnd, msg, wParam, lParam); } + } - Compat::LogLeave(origWndProcName, hwnd, msg, wParam, lParam) << result; + LRESULT defPaintProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc, + const char* origWndProcName) + { + Compat::LogEnter(origWndProcName, hwnd, Compat::hex(msg), Compat::hex(wParam), Compat::hex(lParam)); + LRESULT result = defPaintProc(hwnd, msg, wParam, lParam, origWndProc); + Compat::LogLeave(origWndProcName, hwnd, Compat::hex(msg), Compat::hex(wParam), Compat::hex(lParam)) << result; return result; } @@ -141,9 +210,9 @@ namespace 0); } - LRESULT WINAPI editWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) + LRESULT editWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc) { - LRESULT result = defPaintProc(hwnd, msg, wParam, lParam, g_origEditWndProc, "editWndProc"); + LRESULT result = defPaintProc(hwnd, msg, wParam, lParam, origWndProc); if (0 == result && (WM_HSCROLL == msg || WM_VSCROLL == msg)) { Gdi::ScrollFunctions::updateScrolledWindow(hwnd); @@ -151,37 +220,88 @@ namespace return result; } - LRESULT WINAPI listBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) + void hookUser32WndProc(const std::string& wndProcName, HWND hwnd, WNDPROC newWndProc, + decltype(GetWindowLongPtr)* getWindowLong, std::vector& user32WndProc) { - return defPaintProc(hwnd, msg, wParam, lParam, g_origListBoxWndProc, "listBoxWndProc"); + User32WndProc wndProc; + wndProc.oldWndProc = + reinterpret_cast(getWindowLong(hwnd, GWL_WNDPROC)); + wndProc.oldWndProcTrampoline = wndProc.oldWndProc; + wndProc.newWndProc = newWndProc; + wndProc.name = wndProcName; + user32WndProc.push_back(wndProc); + + if (reinterpret_cast(wndProc.oldWndProcTrampoline) < 0xFFFF0000) + { + Compat::hookFunction( + reinterpret_cast(user32WndProc.back().oldWndProcTrampoline), newWndProc); + } } - LRESULT WINAPI menuWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) + void hookUser32WndProcA(const char* className, WNDPROC newWndProc, const std::string& wndProcName) { - Compat::LogEnter("menuWndProc", hwnd, msg, wParam, lParam); - LRESULT result = 0; + CLIENTCREATESTRUCT ccs = {}; + HWND hwnd = CreateWindowA(className, "", 0, 0, 0, 0, 0, 0, 0, 0, &ccs); + hookUser32WndProc(wndProcName + 'A', hwnd, newWndProc, CALL_ORIG_FUNC(GetWindowLongA), g_user32WndProcA); + DestroyWindow(hwnd); + } + void hookUser32WndProcW(const char* name, WNDPROC newWndProc, const std::string& wndProcName) + { + CLIENTCREATESTRUCT ccs = {}; + HWND hwnd = CreateWindowW( + std::wstring(name, name + std::strlen(name)).c_str(), L"", 0, 0, 0, 0, 0, 0, 0, 0, &ccs); + hookUser32WndProc(wndProcName + 'W', hwnd, newWndProc, CALL_ORIG_FUNC(GetWindowLongW), g_user32WndProcW); + DestroyWindow(hwnd); + } + + LRESULT listBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc) + { + return defPaintProc(hwnd, msg, wParam, lParam, origWndProc); + } + + LRESULT mdiClientWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc) + { + return defPaintProc(hwnd, msg, wParam, lParam, origWndProc); + } + + LRESULT menuWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc) + { switch (msg) { + case WM_NCPAINT: + CallWindowProc(origWndProc, hwnd, msg, wParam, lParam); + return onNcPaint(hwnd, wParam, origWndProc); + case WM_PAINT: - result = onMenuPaint(hwnd, g_origMenuWndProc); - break; + return onPaint(hwnd, origWndProc); + + case WM_PRINTCLIENT: + { + RECT r = {}; + GetClientRect(hwnd, &r); + HDC dc = CreateCompatibleDC(nullptr); + HBITMAP dib = Gdi::VirtualScreen::createOffScreenDib(r.right, r.bottom); + HGDIOBJ origBitmap = SelectObject(dc, dib); + CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND, reinterpret_cast(dc), 0); + LRESULT result = CallWindowProc(origWndProc, hwnd, msg, reinterpret_cast(dc), lParam); + CALL_ORIG_FUNC(BitBlt)(reinterpret_cast(wParam), 0, 0, r.right, r.bottom, dc, 0, 0, SRCCOPY); + SelectObject(dc, origBitmap); + DeleteObject(dib); + DeleteDC(dc); + return result; + } case 0x1e5: if (-1 == wParam) { - // Clearing of selection is not caught by WM_MENUSELECT when mouse leaves menu window - RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE); + RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE); } - // fall through to default + return CallWindowProc(origWndProc, hwnd, msg, wParam, lParam); default: - result = CallWindowProc(g_origMenuWndProc, hwnd, msg, wParam, lParam); - break; + return defPaintProc(hwnd, msg, wParam, lParam, origWndProc); } - - Compat::LogLeave("menuWndProc", hwnd, msg, wParam, lParam) << result; - return result; } LRESULT onEraseBackground(HWND hwnd, HDC dc, WNDPROC origWndProc) @@ -202,32 +322,6 @@ namespace return CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND, reinterpret_cast(dc), 0); } - LRESULT onMenuPaint(HWND hwnd, WNDPROC origWndProc) - { - if (!hwnd) - { - return CallWindowProc(origWndProc, hwnd, WM_PAINT, 0, 0); - } - - HDC dc = GetWindowDC(hwnd); - HDC compatDc = Gdi::Dc::getDc(dc); - if (compatDc) - { - Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE); - CallWindowProc(origWndProc, hwnd, WM_PRINT, reinterpret_cast(compatDc), - PRF_NONCLIENT | PRF_ERASEBKGND | PRF_CLIENT); - ValidateRect(hwnd, nullptr); - Gdi::Dc::releaseDc(dc); - } - else - { - CallWindowProc(origWndProc, hwnd, WM_PAINT, 0, 0); - } - - ReleaseDC(hwnd, dc); - return 0; - } - LRESULT onNcPaint(HWND hwnd, WPARAM wParam, WNDPROC origWndProc) { if (!hwnd) @@ -249,7 +343,7 @@ namespace scrollBar.drawAll(); scrollBar.excludeFromClipRegion(); - SendMessage(hwnd, WM_PRINT, reinterpret_cast(compatDc), PRF_NONCLIENT); + CallWindowProc(origWndProc, hwnd, WM_PRINT, reinterpret_cast(compatDc), PRF_NONCLIENT); Gdi::Dc::releaseDc(windowDc); } @@ -265,6 +359,7 @@ namespace return CallWindowProc(origWndProc, hwnd, WM_PAINT, 0, 0); } + DDraw::ScopedThreadLock lock; PAINTSTRUCT paint = {}; HDC dc = BeginPaint(hwnd, &paint); HDC compatDc = Gdi::Dc::getDc(dc); @@ -303,33 +398,52 @@ namespace return result; } - LRESULT WINAPI scrollBarWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) + LRESULT scrollBarWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc) { - Compat::LogEnter("scrollBarWndProc", hwnd, msg, wParam, lParam); - LRESULT result = 0; - switch (msg) { case WM_PAINT: - result = onPaint(hwnd, g_origScrollBarWndProc); - break; + return onPaint(hwnd, origWndProc); case WM_SETCURSOR: if (GetWindowLong(hwnd, GWL_STYLE) & (SBS_SIZEBOX | SBS_SIZEGRIP)) { SetCursor(LoadCursor(nullptr, IDC_SIZENWSE)); } - result = TRUE; - break; + return TRUE; default: - result = CallWindowProc(g_origScrollBarWndProc, hwnd, msg, wParam, lParam); - break; + return CallWindowProc(origWndProc, hwnd, msg, wParam, lParam); } + } - Compat::LogLeave("scrollBarWndProc", hwnd, msg, wParam, lParam) << result; + LRESULT staticWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc) + { + return defPaintProc(hwnd, msg, wParam, lParam, origWndProc); + } + + LRESULT CALLBACK user32WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, + const User32WndProc& user32WndProc, WndProcHook wndProcHook) + { + Compat::LogEnter(user32WndProc.name.c_str(), + hwnd, Compat::hex(uMsg), Compat::hex(wParam), Compat::hex(lParam)); + LRESULT result = wndProcHook(hwnd, uMsg, wParam, lParam, user32WndProc.oldWndProcTrampoline); + Compat::LogLeave(user32WndProc.name.c_str(), + hwnd, Compat::hex(uMsg), Compat::hex(wParam), Compat::hex(lParam)) << result; return result; } + + template + LRESULT CALLBACK user32WndProcA(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) + { + return user32WndProc(hwnd, uMsg, wParam, lParam, g_user32WndProcA[index], g_user32WndProcHook[index]); + } + + template + LRESULT CALLBACK user32WndProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) + { + return user32WndProc(hwnd, uMsg, wParam, lParam, g_user32WndProcW[index], g_user32WndProcHook[index]); + } } namespace Gdi @@ -340,27 +454,40 @@ namespace Gdi { disableImmersiveContextMenus(); - Gdi::hookWndProc("Button", g_origButtonWndProc, &buttonWndProc); - Gdi::hookWndProc("ComboLBox", g_origComboListBoxWndProc, &comboListBoxWndProc); - Gdi::hookWndProc("Edit", g_origEditWndProc, &editWndProc); - Gdi::hookWndProc("ListBox", g_origListBoxWndProc, &listBoxWndProc); - Gdi::hookWndProc("#32768", g_origMenuWndProc, &menuWndProc); - Gdi::hookWndProc("ScrollBar", g_origScrollBarWndProc, &scrollBarWndProc); +#define HOOK_USER32_WNDPROC(index, name, wndProcHook) \ + g_user32WndProcHook.push_back(wndProcHook); \ + hookUser32WndProcA(name, user32WndProcA, #wndProcHook); \ + hookUser32WndProcW(name, user32WndProcW, #wndProcHook) + + g_user32WndProcA.reserve(9); + g_user32WndProcW.reserve(9); + + HOOK_USER32_WNDPROC(0, "Button", buttonWndProc); + HOOK_USER32_WNDPROC(1, "ComboBox", comboBoxWndProc); + HOOK_USER32_WNDPROC(2, "Edit", editWndProc); + HOOK_USER32_WNDPROC(3, "ListBox", listBoxWndProc); + HOOK_USER32_WNDPROC(4, "MDIClient", mdiClientWndProc); + HOOK_USER32_WNDPROC(5, "ScrollBar", scrollBarWndProc); + HOOK_USER32_WNDPROC(6, "Static", staticWndProc); + HOOK_USER32_WNDPROC(7, "ComboLBox", comboListBoxWndProc); + HOOK_USER32_WNDPROC(8, "#32768", menuWndProc); + + g_scrollBarWndProcIndex = 5; + g_menuWndProcIndex = 8; + +#undef HOOK_USER32_WNDPROC HOOK_FUNCTION(user32, DefWindowProcA, defWindowProcA); HOOK_FUNCTION(user32, DefWindowProcW, defWindowProcW); HOOK_FUNCTION(user32, DefDlgProcA, defDlgProcA); HOOK_FUNCTION(user32, DefDlgProcW, defDlgProcW); + + g_cbtProcHook = SetWindowsHookEx(WH_CBT, cbtProc, nullptr, Gdi::getGdiThreadId()); } void uninstallHooks() { - Gdi::unhookWndProc("Button", g_origButtonWndProc); - Gdi::unhookWndProc("ComboLBox", g_origComboListBoxWndProc); - Gdi::unhookWndProc("Edit", g_origEditWndProc); - Gdi::unhookWndProc("ListBox", g_origListBoxWndProc); - Gdi::unhookWndProc("#32768", g_origMenuWndProc); - Gdi::unhookWndProc("ScrollBar", g_origScrollBarWndProc); + UnhookWindowsHookEx(g_cbtProcHook); } } } diff --git a/DDrawCompat/Gdi/ScrollFunctions.cpp b/DDrawCompat/Gdi/ScrollFunctions.cpp index 0d1f9f7..56c742c 100644 --- a/DDrawCompat/Gdi/ScrollFunctions.cpp +++ b/DDrawCompat/Gdi/ScrollFunctions.cpp @@ -1,8 +1,9 @@ #include "Common/Hook.h" #include "Common/Log.h" -#include "DDraw/RealPrimarySurface.h" +#include "DDraw/ScopedThreadLock.h" #include "Gdi/Gdi.h" #include "Gdi/ScrollFunctions.h" +#include "Gdi/Window.h" namespace { @@ -55,10 +56,14 @@ namespace Gdi void updateScrolledWindow(HWND hwnd) { - DDraw::RealPrimarySurface::disableUpdates(); - RedrawWindow(hwnd, nullptr, nullptr, - RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN | RDW_UPDATENOW); - DDraw::RealPrimarySurface::enableUpdates(); + DDraw::ScopedThreadLock lock; + auto window(Gdi::Window::get(hwnd)); + UINT flags = RDW_ERASE | RDW_INVALIDATE | RDW_NOCHILDREN | RDW_UPDATENOW; + if (!window || window->getPresentationWindow() != hwnd) + { + flags |= RDW_FRAME; + } + RedrawWindow(hwnd, nullptr, nullptr, flags); } } } diff --git a/DDrawCompat/Gdi/VirtualScreen.cpp b/DDrawCompat/Gdi/VirtualScreen.cpp index fe25eb5..52c5fad 100644 --- a/DDrawCompat/Gdi/VirtualScreen.cpp +++ b/DDrawCompat/Gdi/VirtualScreen.cpp @@ -32,6 +32,37 @@ namespace virtualScreenRegion |= monitorRegion; return TRUE; } + + HBITMAP createDibSection(DWORD width, DWORD height, HANDLE section) + { + struct BITMAPINFO256 : public BITMAPINFO + { + RGBQUAD bmiRemainingColors[255]; + }; + + BITMAPINFO256 bmi = {}; + bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -static_cast(height); + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = static_cast(g_bpp); + bmi.bmiHeader.biCompression = 8 == g_bpp ? BI_RGB : BI_BITFIELDS; + + if (8 == g_bpp) + { + memcpy(bmi.bmiColors, g_systemPalette, sizeof(g_systemPalette)); + } + else + { + const auto pf = DDraw::getRgbPixelFormat(g_bpp); + reinterpret_cast(bmi.bmiColors[0]) = pf.dwRBitMask; + reinterpret_cast(bmi.bmiColors[1]) = pf.dwGBitMask; + reinterpret_cast(bmi.bmiColors[2]) = pf.dwBBitMask; + } + + void* bits = nullptr; + return CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, &bits, section, 0); + } } namespace Gdi @@ -74,34 +105,13 @@ namespace Gdi { return nullptr; } + return createDibSection(g_width, g_height, g_surfaceFileMapping); + } - struct BITMAPINFO256 : public BITMAPINFO - { - RGBQUAD bmiRemainingColors[255]; - }; - - BITMAPINFO256 bmi = {}; - bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); - bmi.bmiHeader.biWidth = g_width; - bmi.bmiHeader.biHeight = -g_height; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = static_cast(g_bpp); - bmi.bmiHeader.biCompression = 8 == g_bpp ? BI_RGB : BI_BITFIELDS; - - if (8 == g_bpp) - { - memcpy(bmi.bmiColors, g_systemPalette, sizeof(g_systemPalette)); - } - else - { - const auto pf = DDraw::getRgbPixelFormat(g_bpp); - reinterpret_cast(bmi.bmiColors[0]) = pf.dwRBitMask; - reinterpret_cast(bmi.bmiColors[1]) = pf.dwGBitMask; - reinterpret_cast(bmi.bmiColors[2]) = pf.dwBBitMask; - } - - void* bits = nullptr; - return CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, &bits, g_surfaceFileMapping, 0); + HBITMAP createOffScreenDib(DWORD width, DWORD height) + { + Compat::ScopedCriticalSection lock(g_cs); + return createDibSection(width, height, nullptr); } CompatPtr createSurface(const RECT& rect) diff --git a/DDrawCompat/Gdi/VirtualScreen.h b/DDrawCompat/Gdi/VirtualScreen.h index 38b791f..9ac4dfb 100644 --- a/DDrawCompat/Gdi/VirtualScreen.h +++ b/DDrawCompat/Gdi/VirtualScreen.h @@ -14,6 +14,7 @@ namespace Gdi { HDC createDc(); HBITMAP createDib(); + HBITMAP createOffScreenDib(DWORD width, DWORD height); CompatPtr createSurface(const RECT& rect); void deleteDc(HDC dc); diff --git a/DDrawCompat/Gdi/WinProc.cpp b/DDrawCompat/Gdi/WinProc.cpp index 960a8f6..c440c67 100644 --- a/DDrawCompat/Gdi/WinProc.cpp +++ b/DDrawCompat/Gdi/WinProc.cpp @@ -27,14 +27,13 @@ namespace void onActivate(HWND hwnd); void onCreateWindow(HWND hwnd); void onDestroyWindow(HWND hwnd); - void onMenuSelect(); void onWindowPosChanged(HWND hwnd); void removeDropShadow(HWND hwnd); LRESULT CALLBACK callWndRetProc(int nCode, WPARAM wParam, LPARAM lParam) { auto ret = reinterpret_cast(lParam); - Compat::LogEnter("callWndRetProc", nCode, wParam, ret); + Compat::LogEnter("callWndRetProc", Compat::hex(nCode), Compat::hex(wParam), ret); if (HC_ACTION == nCode) { @@ -62,14 +61,10 @@ namespace Gdi::ScrollFunctions::updateScrolledWindow(reinterpret_cast(ret->lParam)); } } - else if (WM_MENUSELECT == ret->message) - { - onMenuSelect(); - } } LRESULT result = CallNextHookEx(nullptr, nCode, wParam, lParam); - Compat::LogLeave("callWndRetProc", nCode, wParam, ret) << result; + Compat::LogLeave("callWndRetProc", Compat::hex(nCode), Compat::hex(wParam), ret) << result; return result; } @@ -95,12 +90,6 @@ namespace return TRUE; } - bool isTopLevelNonLayeredWindow(HWND hwnd) - { - return !(GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED) && - (!(GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CHILD) || GetParent(hwnd) == GetDesktopWindow()); - } - void CALLBACK objectStateChangeEvent( HWINEVENTHOOK /*hWinEventHook*/, DWORD /*event*/, @@ -160,12 +149,9 @@ namespace void onCreateWindow(HWND hwnd) { - if (isTopLevelNonLayeredWindow(hwnd)) - { - disableDwmAttributes(hwnd); - removeDropShadow(hwnd); - Gdi::Window::add(hwnd); - } + disableDwmAttributes(hwnd); + removeDropShadow(hwnd); + Gdi::Window::add(hwnd); } void onDestroyWindow(HWND hwnd) @@ -173,20 +159,9 @@ namespace Gdi::Window::remove(hwnd); } - void onMenuSelect() - { - HWND menuWindow = FindWindow(reinterpret_cast(0x8000), nullptr); - while (menuWindow) - { - RedrawWindow(menuWindow, nullptr, nullptr, RDW_INVALIDATE); - menuWindow = FindWindowEx(nullptr, menuWindow, reinterpret_cast(0x8000), nullptr); - } - } - void onWindowPosChanged(HWND hwnd) { - const ATOM menuAtom = 0x8000; - if (menuAtom == GetClassLongPtr(hwnd, GCW_ATOM)) + if (Gdi::MENU_ATOM == GetClassLongPtr(hwnd, GCW_ATOM)) { SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED); } @@ -196,7 +171,7 @@ namespace notifyFunc(); } - if (isTopLevelNonLayeredWindow(hwnd)) + if (Gdi::Window::get(hwnd)) { Gdi::Window::updateAll(); } diff --git a/DDrawCompat/Gdi/Window.cpp b/DDrawCompat/Gdi/Window.cpp index 703bfcb..5258eba 100644 --- a/DDrawCompat/Gdi/Window.cpp +++ b/DDrawCompat/Gdi/Window.cpp @@ -1,3 +1,4 @@ +#include "DDraw/ScopedThreadLock.h" #include "Gdi/Gdi.h" #include "Gdi/VirtualScreen.h" #include "Gdi/Window.h" @@ -8,6 +9,13 @@ namespace { ATOM registerPresentationWindowClass(); + ATOM getComboLBoxAtom() + { + WNDCLASS wc = {}; + static ATOM comboLBoxAtom = static_cast(GetClassInfo(nullptr, "ComboLBox", &wc)); + return comboLBoxAtom; + } + ATOM getPresentationWindowClassAtom() { static ATOM atom = registerPresentationWindowClass(); @@ -33,37 +41,43 @@ namespace Gdi { Window::Window(HWND hwnd) : m_hwnd(hwnd) + , m_presentationWindow(nullptr) , m_windowRect{ 0, 0, 0, 0 } , m_isUpdating(false) { - 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); + 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); + } + update(); } - Window* Window::add(HWND hwnd) + bool Window::add(HWND hwnd) { - auto it = s_windows.find(hwnd); - if (it != s_windows.end()) + const bool isTopLevelNonLayeredWindow = !(GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED) && + (!(GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CHILD) || GetParent(hwnd) == GetDesktopWindow() || + getComboLBoxAtom() == GetClassLong(hwnd, GCW_ATOM)); + + if (isTopLevelNonLayeredWindow && !get(hwnd) && + GetClassLong(hwnd, GCW_ATOM) != getPresentationWindowClassAtom()) { - return &it->second; + s_windows.emplace(hwnd, std::make_shared(hwnd)); + return true; } - if (isPresentationWindow(hwnd)) - { - return nullptr; - } - - return &s_windows.emplace(hwnd, hwnd).first->second; + return false; } void Window::calcInvalidatedRegion(const RECT& oldWindowRect, const Region& oldVisibleRegion) @@ -97,22 +111,36 @@ namespace Gdi } } - Window* Window::get(HWND hwnd) + std::shared_ptr Window::get(HWND hwnd) { + DDraw::ScopedThreadLock lock; auto it = s_windows.find(hwnd); - return it != s_windows.end() ? &it->second : nullptr; + return it != s_windows.end() ? it->second : nullptr; + } + + HWND Window::getPresentationWindow() const + { + return m_presentationWindow ? m_presentationWindow : m_hwnd; } Region Window::getVisibleRegion() const { + DDraw::ScopedThreadLock lock; return m_visibleRegion; } RECT Window::getWindowRect() const { + DDraw::ScopedThreadLock lock; return m_windowRect; } + std::map> Window::getWindows() + { + DDraw::ScopedThreadLock lock; + return s_windows; + } + bool Window::isPresentationWindow(HWND hwnd) { return GetClassLong(hwnd, GCW_ATOM) == getPresentationWindowClassAtom(); @@ -120,11 +148,13 @@ namespace Gdi void Window::remove(HWND hwnd) { + DDraw::ScopedThreadLock lock; s_windows.erase(hwnd); } void Window::update() { + DDraw::ScopedThreadLock lock; if (m_isUpdating) { return; @@ -145,9 +175,16 @@ namespace Gdi newVisibleRegion &= VirtualScreen::getRegion(); } - SetWindowPos(m_presentationWindow, nullptr, newWindowRect.left, newWindowRect.top, - newWindowRect.right - newWindowRect.left, newWindowRect.bottom - newWindowRect.top, - SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW); + if (m_presentationWindow) + { + SetWindowPos(m_presentationWindow, nullptr, newWindowRect.left, newWindowRect.top, + newWindowRect.right - newWindowRect.left, newWindowRect.bottom - newWindowRect.top, + SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOREDRAW); + } + } + else if (m_presentationWindow) + { + ShowWindow(m_presentationWindow, SW_HIDE); } std::swap(m_windowRect, newWindowRect); @@ -160,23 +197,34 @@ namespace Gdi void Window::updateAll() { - for (auto& windowPair : s_windows) + auto windows(getWindows()); + for (auto& windowPair : windows) { - windowPair.second.update(); + windowPair.second->update(); } - for (auto& windowPair : s_windows) + for (auto& windowPair : windows) { - if (!windowPair.second.m_invalidatedRegion.isEmpty()) + if (!windowPair.second->m_invalidatedRegion.isEmpty()) { POINT clientOrigin = {}; ClientToScreen(windowPair.first, &clientOrigin); - windowPair.second.m_invalidatedRegion.offset(-clientOrigin.x, -clientOrigin.y); - RedrawWindow(windowPair.first, nullptr, windowPair.second.m_invalidatedRegion, + windowPair.second->m_invalidatedRegion.offset(-clientOrigin.x, -clientOrigin.y); + RedrawWindow(windowPair.first, nullptr, windowPair.second->m_invalidatedRegion, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASENOW); } } } - std::map Window::s_windows; + void Window::updateWindow() + { + RECT windowRect = {}; + GetWindowRect(m_hwnd, &windowRect); + if (!EqualRect(&windowRect, &m_windowRect)) + { + updateAll(); + } + } + + std::map> Window::s_windows; } diff --git a/DDrawCompat/Gdi/Window.h b/DDrawCompat/Gdi/Window.h index dc138ba..122c04a 100644 --- a/DDrawCompat/Gdi/Window.h +++ b/DDrawCompat/Gdi/Window.h @@ -3,6 +3,7 @@ #define WIN32_LEAN_AND_MEAN #include +#include #include @@ -17,13 +18,16 @@ namespace Gdi Window(const Window&) = delete; Window& operator=(const Window&) = delete; + HWND getPresentationWindow() const; Region getVisibleRegion() const; RECT getWindowRect() const; + void updateWindow(); - static Window* add(HWND hwnd); - static Window* get(HWND hwnd); + static bool add(HWND hwnd); + static std::shared_ptr get(HWND hwnd); static void remove(HWND hwnd); + static std::map> getWindows(); static bool isPresentationWindow(HWND hwnd); static void updateAll(); @@ -38,6 +42,6 @@ namespace Gdi Region m_invalidatedRegion; bool m_isUpdating; - static std::map s_windows; + static std::map> s_windows; }; } diff --git a/DDrawCompat/Win32/Registry.cpp b/DDrawCompat/Win32/Registry.cpp index 0d9ac73..5605b14 100644 --- a/DDrawCompat/Win32/Registry.cpp +++ b/DDrawCompat/Win32/Registry.cpp @@ -30,7 +30,7 @@ namespace const int subKeyComp = lstrcmpiW(subKey.c_str(), rhs.subKey.c_str()); if (subKeyComp < 0) { return true; } if (subKeyComp > 0) { return false; } - return lstrcmpiW(value.c_str(), rhs.value.c_str()); + return lstrcmpiW(value.c_str(), rhs.value.c_str()) < 0; } bool operator==(const RegistryKey& rhs) const