From acbc183d006e609b1a99975d89b94ac3638eae85 Mon Sep 17 00:00:00 2001 From: narzoul Date: Sun, 17 Jan 2016 15:31:08 +0100 Subject: [PATCH] Disabled themes, fixed nonclient area rendering and caret deadlock Disabled visual styles and added WM_NCPAINT handling (as a simple BitBlt copy from the original DC) to reduce glitches in rendering of common controls and windows, such as the GetSaveFileName dialog window in StarCraft. Fixed a deadlock in the caret emulation code caused by locking the GDI critical section prior to calling beginGdiRendering, which is locking both the DirectDraw and GDI critical sections. Another thread that only calls beginGdiRendering without entering the GDI critical section first could thus run into a deadlock as both threads were waiting on each other's critical sections. Now the global caret data has it its own critical section instead of sharing the GDI critical section. --- DDrawCompat/CompatGdiCaret.cpp | 25 ++++++++++++++++---- DDrawCompat/CompatGdiDc.cpp | 4 +--- DDrawCompat/CompatGdiWinProc.cpp | 39 ++++++++++++++++++++++++++++++++ DDrawCompat/DDrawCompat.vcxproj | 4 ++-- DDrawCompat/DllMain.cpp | 6 +++++ 5 files changed, 69 insertions(+), 9 deletions(-) diff --git a/DDrawCompat/CompatGdiCaret.cpp b/DDrawCompat/CompatGdiCaret.cpp index 26db63e..018f70d 100644 --- a/DDrawCompat/CompatGdiCaret.cpp +++ b/DDrawCompat/CompatGdiCaret.cpp @@ -22,6 +22,21 @@ namespace }; CaretData g_caret = {}; + CRITICAL_SECTION g_caretCriticalSection; + + class CaretScopedThreadLock + { + public: + CaretScopedThreadLock() + { + EnterCriticalSection(&g_caretCriticalSection); + } + + ~CaretScopedThreadLock() + { + LeaveCriticalSection(&g_caretCriticalSection); + } + }; void drawCaret() { @@ -55,7 +70,7 @@ namespace DWORD /*dwEventThread*/, DWORD /*dwmsEventTime*/) { - CompatGdi::GdiScopedThreadLock gdiLock; + CaretScopedThreadLock caretLock; if (OBJID_CARET != idObject || !g_caret.isDrawn || g_caret.hwnd != hwnd) { return; @@ -80,7 +95,7 @@ namespace BOOL result = CALL_ORIG_GDI(CreateCaret)(hWnd, hBitmap, nWidth, nHeight); if (result) { - CompatGdi::GdiScopedThreadLock gdiLock; + CaretScopedThreadLock caretLock; if (g_caret.isDrawn) { drawCaret(); @@ -99,7 +114,7 @@ namespace return FALSE; } - CompatGdi::GdiScopedThreadLock gdiLock; + CaretScopedThreadLock caretLock; if (!g_caret.isDrawn) { IAccessible* accessible = nullptr; @@ -129,7 +144,7 @@ namespace BOOL result = CALL_ORIG_GDI(HideCaret)(hWnd); if (result) { - CompatGdi::GdiScopedThreadLock gdiLock; + CaretScopedThreadLock caretLock; if (g_caret.isDrawn) { drawCaret(); @@ -147,6 +162,8 @@ namespace CompatGdiCaret { void installHooks() { + InitializeCriticalSection(&g_caretCriticalSection); + DetourTransactionBegin(); HOOK_GDI_FUNCTION(user32, CreateCaret, createCaret); HOOK_GDI_FUNCTION(user32, ShowCaret, showCaret); diff --git a/DDrawCompat/CompatGdiDc.cpp b/DDrawCompat/CompatGdiDc.cpp index 2ad6172..e2479e0 100644 --- a/DDrawCompat/CompatGdiDc.cpp +++ b/DDrawCompat/CompatGdiDc.cpp @@ -99,10 +99,8 @@ namespace if (hwnd) { ExcludeClipRectsData excludeClipRectsData = { compatDc, origin, GetAncestor(hwnd, GA_ROOT) }; - EnumThreadWindows(GetCurrentThreadId(), &excludeClipRectsForOverlappingWindows, + EnumWindows(&excludeClipRectsForOverlappingWindows, reinterpret_cast(&excludeClipRectsData)); - RECT windowRect = {}; - GetWindowRect(hwnd, &windowRect); } } } diff --git a/DDrawCompat/CompatGdiWinProc.cpp b/DDrawCompat/CompatGdiWinProc.cpp index a5af382..54ac958 100644 --- a/DDrawCompat/CompatGdiWinProc.cpp +++ b/DDrawCompat/CompatGdiWinProc.cpp @@ -10,6 +10,7 @@ namespace { void eraseBackground(HWND hwnd, HDC dc); + void ncPaint(HWND wnd); LRESULT CALLBACK callWndRetProc(int nCode, WPARAM wParam, LPARAM lParam) { @@ -23,6 +24,13 @@ namespace eraseBackground(ret->hwnd, reinterpret_cast(ret->wParam)); } } + else if (WM_NCPAINT == ret->message) + { + if (0 == ret->lResult) + { + ncPaint(ret->hwnd); + } + } else if (WM_WINDOWPOSCHANGED == ret->message) { CompatGdi::invalidate(); @@ -49,6 +57,37 @@ namespace CompatGdi::endGdiRendering(); } } + + void ncPaint(HWND hwnd) + { + if (!CompatGdi::beginGdiRendering()) + { + return; + } + + HDC windowDc = GetWindowDC(hwnd); + HDC compatDc = CompatGdiDc::getDc(windowDc); + + if (compatDc) + { + RECT windowRect = {}; + GetWindowRect(hwnd, &windowRect); + RECT clientRect = {}; + GetClientRect(hwnd, &clientRect); + POINT clientOrigin = {}; + ClientToScreen(hwnd, &clientOrigin); + + OffsetRect(&clientRect, clientOrigin.x - windowRect.left, clientOrigin.y - windowRect.top); + ExcludeClipRect(compatDc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); + CALL_ORIG_GDI(BitBlt)(compatDc, 0, 0, + windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, windowDc, 0, 0, SRCCOPY); + + CompatGdiDc::releaseDc(windowDc); + } + + ReleaseDC(hwnd, windowDc); + CompatGdi::endGdiRendering(); + } } namespace CompatGdiWinProc diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index 97e1604..6b161bd 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -94,7 +94,7 @@ DDrawCompat.def - dxguid.lib;detours.lib;msimg32.lib;oleacc.lib;%(AdditionalDependencies) + dxguid.lib;detours.lib;msimg32.lib;oleacc.lib;uxtheme.lib;%(AdditionalDependencies) @@ -121,7 +121,7 @@ DDrawCompat.def - dxguid.lib;detours.lib;msimg32.lib;oleacc.lib;%(AdditionalDependencies) + dxguid.lib;detours.lib;msimg32.lib;oleacc.lib;uxtheme.lib;%(AdditionalDependencies) No diff --git a/DDrawCompat/DllMain.cpp b/DDrawCompat/DllMain.cpp index 65253c7..0f98350 100644 --- a/DDrawCompat/DllMain.cpp +++ b/DDrawCompat/DllMain.cpp @@ -1,5 +1,10 @@ +#define WIN32_LEAN_AND_MEAN + #include +#include +#include + #include "CompatDirectDraw.h" #include "CompatDirectDrawSurface.h" #include "CompatDirectDrawPalette.h" @@ -163,6 +168,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID /*lpvReserved*/) Compat::origProcs.DirectInputCreateA = GetProcAddress(g_origDInputModule, "DirectInputCreateA"); SetProcessAffinityMask(GetCurrentProcess(), 1); + SetThemeAppProperties(0); if (Compat::origProcs.SetAppCompatData) {