From 7c06d9440bd8de2b786383fa28eec0ded44cc9d2 Mon Sep 17 00:00:00 2001 From: narzoul Date: Sun, 20 Mar 2016 22:58:51 +0100 Subject: [PATCH] Added WM_PAINT handling for popup menus --- DDrawCompat/CompatGdiDc.cpp | 64 ++++++++++++++++++-------- DDrawCompat/CompatGdiPaintHandlers.cpp | 50 ++++++++++++++++++++ DDrawCompat/CompatGdiWinProc.cpp | 15 ++++++ 3 files changed, 111 insertions(+), 18 deletions(-) diff --git a/DDrawCompat/CompatGdiDc.cpp b/DDrawCompat/CompatGdiDc.cpp index 135232c..c3217eb 100644 --- a/DDrawCompat/CompatGdiDc.cpp +++ b/DDrawCompat/CompatGdiDc.cpp @@ -87,7 +87,7 @@ namespace MoveToEx(compatDc.dc, currentPos.x, currentPos.y, nullptr); } - BOOL CALLBACK excludeClipRectsForOverlappingWindows(HWND hwnd, LPARAM lParam) + BOOL CALLBACK excludeClipRectForOverlappingWindow(HWND hwnd, LPARAM lParam) { auto excludeClipRectsData = reinterpret_cast(lParam); if (hwnd == excludeClipRectsData->rootWnd) @@ -107,30 +107,58 @@ namespace return TRUE; } - void setClippingRegion(HDC compatDc, HDC origDc, POINT& origin) + void excludeClipRectsForOverlappingWindows( + HWND hwnd, bool isMenuWindow, HDC compatDc, const POINT& origin) { - HRGN clipRgn = CreateRectRgn(0, 0, 0, 0); - const bool isEmptyClipRgn = 1 != GetRandomRgn(origDc, clipRgn, SYSRGN); - SelectClipRgn(compatDc, isEmptyClipRgn ? nullptr : clipRgn); - DeleteObject(clipRgn); - - HRGN origClipRgn = CreateRectRgn(0, 0, 0, 0); - if (1 == GetClipRgn(origDc, origClipRgn)) + ExcludeClipRectsData excludeClipRectsData = { compatDc, origin, GetAncestor(hwnd, GA_ROOT) }; + if (!isMenuWindow) { - OffsetRgn(origClipRgn, origin.x, origin.y); - ExtSelectClipRgn(compatDc, origClipRgn, RGN_AND); + EnumWindows(&excludeClipRectForOverlappingWindow, + reinterpret_cast(&excludeClipRectsData)); } - DeleteObject(origClipRgn); - if (!isEmptyClipRgn) + HWND menuWindow = FindWindow(reinterpret_cast(0x8000), nullptr); + while (menuWindow && menuWindow != hwnd) { - HWND hwnd = WindowFromDC(origDc); - if (hwnd) + excludeClipRectForOverlappingWindow( + menuWindow, reinterpret_cast(&excludeClipRectsData)); + menuWindow = FindWindowEx(nullptr, menuWindow, reinterpret_cast(0x8000), nullptr); + } + } + + void setClippingRegion(HDC compatDc, HDC origDc, const POINT& origin) + { + const HWND hwnd = WindowFromDC(origDc); + const bool isMenuWindow = hwnd && 0x8000 == GetClassLongPtr(hwnd, GCW_ATOM); + + if (isMenuWindow) + { + RECT windowRect = {}; + GetWindowRect(hwnd, &windowRect); + + HRGN windowRgn = CreateRectRgnIndirect(&windowRect); + SelectClipRgn(compatDc, windowRgn); + DeleteObject(windowRgn); + } + else + { + HRGN clipRgn = CreateRectRgn(0, 0, 0, 0); + const bool isEmptyClipRgn = 1 != GetRandomRgn(origDc, clipRgn, SYSRGN); + SelectClipRgn(compatDc, isEmptyClipRgn ? nullptr : clipRgn); + DeleteObject(clipRgn); + + HRGN origClipRgn = CreateRectRgn(0, 0, 0, 0); + if (1 == GetClipRgn(origDc, origClipRgn)) { - ExcludeClipRectsData excludeClipRectsData = { compatDc, origin, GetAncestor(hwnd, GA_ROOT) }; - EnumWindows(&excludeClipRectsForOverlappingWindows, - reinterpret_cast(&excludeClipRectsData)); + OffsetRgn(origClipRgn, origin.x, origin.y); + ExtSelectClipRgn(compatDc, origClipRgn, RGN_AND); } + DeleteObject(origClipRgn); + } + + if (hwnd) + { + excludeClipRectsForOverlappingWindows(hwnd, isMenuWindow, compatDc, origin); } } } diff --git a/DDrawCompat/CompatGdiPaintHandlers.cpp b/DDrawCompat/CompatGdiPaintHandlers.cpp index cc68327..d8b76bd 100644 --- a/DDrawCompat/CompatGdiPaintHandlers.cpp +++ b/DDrawCompat/CompatGdiPaintHandlers.cpp @@ -13,11 +13,14 @@ namespace LRESULT WINAPI eraseBackgroundProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC origWndProc, const char* wndProcName); 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_origEditWndProc = nullptr; WNDPROC g_origListBoxWndProc = nullptr; + WNDPROC g_origMenuWndProc = nullptr; WNDPROC g_origScrollBarWndProc = nullptr; LRESULT WINAPI defDlgProcA(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam) @@ -104,6 +107,26 @@ namespace return eraseBackgroundProc(hwnd, msg, wParam, lParam, g_origListBoxWndProc, "listBoxWndProc"); } + LRESULT WINAPI menuWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) + { + Compat::LogEnter("menuWndProc", hwnd, msg, wParam, lParam); + LRESULT result = 0; + + switch (msg) + { + case WM_PAINT: + result = onMenuPaint(hwnd, g_origMenuWndProc); + break; + + default: + result = g_origMenuWndProc(hwnd, msg, wParam, lParam); + break; + } + + Compat::LogLeave("menuWndProc", hwnd, msg, wParam, lParam) << result; + return result; + } + LRESULT onEraseBackground(HWND hwnd, HDC dc, WNDPROC origWndProc) { if (!hwnd || !CompatGdi::beginGdiRendering()) @@ -157,6 +180,32 @@ namespace return 0; } + LRESULT onMenuPaint(HWND hwnd, WNDPROC origWndProc) + { + if (!hwnd || !CompatGdi::beginGdiRendering()) + { + return origWndProc(hwnd, WM_PAINT, 0, 0); + } + + HDC dc = GetWindowDC(hwnd); + HDC compatDc = CompatGdiDc::getDc(dc); + if (compatDc) + { + origWndProc(hwnd, WM_PRINT, reinterpret_cast(compatDc), + PRF_NONCLIENT | PRF_ERASEBKGND | PRF_CLIENT); + ValidateRect(hwnd, nullptr); + CompatGdiDc::releaseDc(dc); + } + else + { + origWndProc(hwnd, WM_PAINT, 0, 0); + } + + ReleaseDC(hwnd, dc); + CompatGdi::endGdiRendering(); + return 0; + } + LRESULT onPaint(HWND hwnd, WNDPROC origWndProc) { if (!hwnd || !CompatGdi::beginGdiRendering()) @@ -242,6 +291,7 @@ namespace CompatGdiPaintHandlers { CompatGdi::hookWndProc("Edit", g_origEditWndProc, &editWndProc); CompatGdi::hookWndProc("ListBox", g_origListBoxWndProc, &listBoxWndProc); + CompatGdi::hookWndProc("#32768", g_origMenuWndProc, &menuWndProc); CompatGdi::hookWndProc("ScrollBar", g_origScrollBarWndProc, &scrollBarWndProc); DetourTransactionBegin(); diff --git a/DDrawCompat/CompatGdiWinProc.cpp b/DDrawCompat/CompatGdiWinProc.cpp index da3e6ad..bc1fddd 100644 --- a/DDrawCompat/CompatGdiWinProc.cpp +++ b/DDrawCompat/CompatGdiWinProc.cpp @@ -18,6 +18,7 @@ namespace std::unordered_map g_prevWindowRect; void disableDwmAttributes(HWND hwnd); + void onMenuSelect(); void onWindowPosChanged(HWND hwnd); void removeDropShadow(HWND hwnd); @@ -55,6 +56,10 @@ namespace CompatGdiScrollFunctions::updateScrolledWindow(reinterpret_cast(ret->lParam)); } } + else if (WM_MENUSELECT == ret->message) + { + onMenuSelect(); + } else if (BM_SETSTYLE == ret->message) { RedrawWindow(ret->hwnd, nullptr, nullptr, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE); @@ -131,6 +136,16 @@ namespace } } + 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) { CompatGdi::GdiScopedThreadLock lock;