From b83f7ca879b908b1ee8c62c13f975b71b25b1447 Mon Sep 17 00:00:00 2001 From: narzoul Date: Sun, 14 Feb 2021 12:31:39 +0100 Subject: [PATCH] Disable DIB redirection for icon and cursor creating functions Fixes corrupt icon in volume mixer. --- DDrawCompat/DDrawCompat.vcxproj | 2 + DDrawCompat/DDrawCompat.vcxproj.filters | 6 + DDrawCompat/Gdi/DcFunctions.cpp | 130 ++----------------- DDrawCompat/Gdi/DcFunctions.h | 2 + DDrawCompat/Gdi/Gdi.cpp | 2 + DDrawCompat/Gdi/Icon.cpp | 165 ++++++++++++++++++++++++ DDrawCompat/Gdi/Icon.h | 9 ++ DDrawCompat/Gdi/PresentationWindow.cpp | 4 +- 8 files changed, 197 insertions(+), 123 deletions(-) create mode 100644 DDrawCompat/Gdi/Icon.cpp create mode 100644 DDrawCompat/Gdi/Icon.h diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index 6f3dbad..d31e5ca 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -220,6 +220,7 @@ + @@ -294,6 +295,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index ac12b5d..c6da761 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -402,6 +402,9 @@ Header Files\Gdi + + Header Files\Gdi + @@ -620,5 +623,8 @@ Source Files\Gdi + + Source Files\Gdi + \ No newline at end of file diff --git a/DDrawCompat/Gdi/DcFunctions.cpp b/DDrawCompat/Gdi/DcFunctions.cpp index 98f646c..6756958 100644 --- a/DDrawCompat/Gdi/DcFunctions.cpp +++ b/DDrawCompat/Gdi/DcFunctions.cpp @@ -9,13 +9,12 @@ #include #include #include -#include #include namespace { std::unordered_map g_funcNames; - thread_local bool g_redirectToDib = true; + thread_local UINT g_disableDibRedirection = 0; #define CREATE_DC_FUNC_ATTRIBUTE(attribute) \ template \ @@ -175,7 +174,7 @@ namespace HBITMAP WINAPI createCompatibleBitmap(HDC hdc, int cx, int cy) { LOG_FUNC("CreateCompatibleBitmap", hdc, cx, cy); - if (g_redirectToDib && Gdi::isDisplayDc(hdc)) + if (!g_disableDibRedirection && Gdi::isDisplayDc(hdc)) { const bool useDefaultPalette = false; return LOG_RESULT(Gdi::VirtualScreen::createOffScreenDib(cx, cy, useDefaultPalette)); @@ -188,7 +187,7 @@ namespace { LOG_FUNC("CreateDIBitmap", hdc, lpbmih, fdwInit, lpbInit, lpbmi, fuUsage); const DWORD CBM_CREATDIB = 2; - if (g_redirectToDib && !(fdwInit & CBM_CREATDIB) && lpbmih && Gdi::isDisplayDc(hdc)) + if (!g_disableDibRedirection && !(fdwInit & CBM_CREATDIB) && lpbmih && Gdi::isDisplayDc(hdc)) { const bool useDefaultPalette = false; HBITMAP bitmap = Gdi::VirtualScreen::createOffScreenDib( @@ -205,7 +204,7 @@ namespace HBITMAP WINAPI createDiscardableBitmap(HDC hdc, int nWidth, int nHeight) { LOG_FUNC("CreateDiscardableBitmap", hdc, nWidth, nHeight); - if (g_redirectToDib && Gdi::isDisplayDc(hdc)) + if (!g_disableDibRedirection && Gdi::isDisplayDc(hdc)) { const bool useDefaultPalette = false; return LOG_RESULT(Gdi::VirtualScreen::createOffScreenDib(nWidth, nHeight, useDefaultPalette)); @@ -257,114 +256,6 @@ namespace moduleName, funcName, getCompatGdiTextDcFuncPtr(origFunc)); } - template - ATOM WINAPI registerClass(const WndClass* lpWndClass, ATOM(WINAPI* origRegisterClass)(const WndClass*), - ATOM(WINAPI* registerClassEx)(const WndClassEx*)) - { - if (!lpWndClass) - { - return origRegisterClass(lpWndClass); - } - - WndClassEx wc = {}; - wc.cbSize = sizeof(wc); - memcpy(&wc.style, &lpWndClass->style, sizeof(WndClass)); - return registerClassEx(&wc); - } - - template - ATOM registerClassEx(const WndClassEx* lpWndClassEx, - ATOM(WINAPI* origRegisterClassEx)(const WndClassEx*), - decltype(&SetClassLong) origSetClassLong, - decltype(&DefWindowProc) origDefWindowProc) - { - if (!lpWndClassEx || (!lpWndClassEx->hIcon && !lpWndClassEx->hIconSm)) - { - return origRegisterClassEx(lpWndClassEx); - } - - WndClassEx wc = *lpWndClassEx; - wc.lpfnWndProc = origDefWindowProc; - wc.hIcon = nullptr; - wc.hIconSm = nullptr; - - ATOM atom = origRegisterClassEx(&wc); - if (atom) - { - HWND hwnd = CreateWindow(reinterpret_cast(atom), "", 0, 0, 0, 0, 0, nullptr, nullptr, nullptr, nullptr); - if (!hwnd) - { - UnregisterClass(reinterpret_cast(atom), GetModuleHandle(nullptr)); - return origRegisterClassEx(lpWndClassEx); - } - - if (lpWndClassEx->hIcon) - { - SetClassLong(hwnd, GCL_HICON, reinterpret_cast(lpWndClassEx->hIcon)); - } - if (lpWndClassEx->hIconSm) - { - SetClassLong(hwnd, GCL_HICONSM, reinterpret_cast(lpWndClassEx->hIconSm)); - } - - origSetClassLong(hwnd, GCL_WNDPROC, reinterpret_cast(lpWndClassEx->lpfnWndProc)); - SetWindowLong(hwnd, GWL_WNDPROC, reinterpret_cast(CALL_ORIG_FUNC(DefWindowProcA))); - DestroyWindow(hwnd); - } - - return atom; - } - - ATOM WINAPI registerClassA(const WNDCLASSA* lpWndClass) - { - LOG_FUNC("RegisterClassA", lpWndClass); - return LOG_RESULT(registerClass(lpWndClass, CALL_ORIG_FUNC(RegisterClassA), RegisterClassExA)); - } - - ATOM WINAPI registerClassW(const WNDCLASSW* lpWndClass) - { - LOG_FUNC("RegisterClassW", lpWndClass); - return LOG_RESULT(registerClass(lpWndClass, CALL_ORIG_FUNC(RegisterClassW), RegisterClassExW)); - } - - ATOM WINAPI registerClassExA(const WNDCLASSEXA* lpWndClassEx) - { - LOG_FUNC("RegisterClassExA", lpWndClassEx); - return LOG_RESULT(registerClassEx(lpWndClassEx, CALL_ORIG_FUNC(RegisterClassExA), CALL_ORIG_FUNC(SetClassLongA), - CALL_ORIG_FUNC(DefWindowProcA))); - } - - ATOM WINAPI registerClassExW(const WNDCLASSEXW* lpWndClassEx) - { - LOG_FUNC("RegisterClassExW", lpWndClassEx); - return LOG_RESULT(registerClassEx(lpWndClassEx, CALL_ORIG_FUNC(RegisterClassExW), CALL_ORIG_FUNC(SetClassLongW), - CALL_ORIG_FUNC(DefWindowProcW))); - } - - DWORD WINAPI setClassLong(HWND hWnd, int nIndex, LONG dwNewLong, decltype(&SetClassLong) origSetClassLong) - { - if (GCL_HICON == nIndex || GCL_HICONSM == nIndex) - { - g_redirectToDib = false; - DWORD result = origSetClassLong(hWnd, nIndex, dwNewLong); - g_redirectToDib = true; - return result; - } - return origSetClassLong(hWnd, nIndex, dwNewLong); - } - - DWORD WINAPI setClassLongA(HWND hWnd, int nIndex, LONG dwNewLong) - { - LOG_FUNC("setClassLongA", hWnd, nIndex, dwNewLong); - return LOG_RESULT(setClassLong(hWnd, nIndex, dwNewLong, CALL_ORIG_FUNC(SetClassLongA))); - } - - DWORD WINAPI setClassLongW(HWND hWnd, int nIndex, LONG dwNewLong) - { - LOG_FUNC("setClassLongW", hWnd, nIndex, dwNewLong); - return LOG_RESULT(setClassLong(hWnd, nIndex, dwNewLong, CALL_ORIG_FUNC(SetClassLongW))); - } - HWND WINAPI windowFromDc(HDC dc) { return CALL_ORIG_FUNC(WindowFromDC)(Gdi::Dc::getOrigDc(dc)); @@ -382,6 +273,11 @@ namespace Gdi { namespace DcFunctions { + void disableDibRedirection(bool disable) + { + g_disableDibRedirection += disable ? 1 : -1; + } + void installHooks() { // Bitmap functions @@ -469,14 +365,6 @@ namespace Gdi // Undocumented functions HOOK_GDI_DC_FUNCTION(gdi32, GdiDrawStream); HOOK_GDI_DC_FUNCTION(gdi32, PolyPatBlt); - - // Window class functions - HOOK_FUNCTION(user32, RegisterClassA, registerClassA); - HOOK_FUNCTION(user32, RegisterClassW, registerClassW); - HOOK_FUNCTION(user32, RegisterClassExA, registerClassExA); - HOOK_FUNCTION(user32, RegisterClassExW, registerClassExW); - HOOK_FUNCTION(user32, SetClassLongA, setClassLongA); - HOOK_FUNCTION(user32, SetClassLongW, setClassLongW); } } } diff --git a/DDrawCompat/Gdi/DcFunctions.h b/DDrawCompat/Gdi/DcFunctions.h index 3ae80af..8c21c0d 100644 --- a/DDrawCompat/Gdi/DcFunctions.h +++ b/DDrawCompat/Gdi/DcFunctions.h @@ -4,6 +4,8 @@ namespace Gdi { namespace DcFunctions { + void disableDibRedirection(bool disable); + void installHooks(); } } diff --git a/DDrawCompat/Gdi/Gdi.cpp b/DDrawCompat/Gdi/Gdi.cpp index b9a308a..d051f66 100644 --- a/DDrawCompat/Gdi/Gdi.cpp +++ b/DDrawCompat/Gdi/Gdi.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,7 @@ namespace Gdi DisableProcessWindowsGhosting(); DcFunctions::installHooks(); + Icon::installHooks(); Metrics::installHooks(); Palette::installHooks(); PresentationWindow::installHooks(); diff --git a/DDrawCompat/Gdi/Icon.cpp b/DDrawCompat/Gdi/Icon.cpp new file mode 100644 index 0000000..8bf5331 --- /dev/null +++ b/DDrawCompat/Gdi/Icon.cpp @@ -0,0 +1,165 @@ +#include + +#include +#include +#include +#include + +namespace +{ + std::map g_funcNames; + + template + using FuncPtr = Result(WINAPI*)(Params...); + + template + struct EnableDibRedirection + { + bool operator()(Params...) { return false; } + }; + + template + struct EnableDibRedirection + { + bool operator()(HANDLE, UINT type, int, int, UINT) + { + return IMAGE_CURSOR != type && IMAGE_ICON != type; + } + }; + + struct EnableDibRedirectionLoadImage + { + template + bool operator()(HINSTANCE, String, UINT type, int, int, UINT) + { + return IMAGE_CURSOR != type && IMAGE_ICON != type; + } + }; + + template + struct EnableDibRedirection : EnableDibRedirectionLoadImage {}; + template + struct EnableDibRedirection : EnableDibRedirectionLoadImage {}; + + template + Result WINAPI iconFunc(Params... params) + { + LOG_FUNC(g_funcNames[origFunc], params...); + + if (EnableDibRedirection()(params...)) + { + return LOG_RESULT(Compat::getOrigFuncPtr()(params...)); + } + + Gdi::DcFunctions::disableDibRedirection(true); + Result result = Compat::getOrigFuncPtr()(params...); + Gdi::DcFunctions::disableDibRedirection(false); + return LOG_RESULT(result); + } + + template + OrigFuncPtr getIconFuncPtr(FuncPtr) + { + return &iconFunc; + } + + template + void hookIconFunc(const char* moduleName, const char* funcName) + { +#ifdef DEBUGLOGS + g_funcNames[origFunc] = funcName; +#endif + + Compat::hookFunction( + moduleName, funcName, getIconFuncPtr(origFunc)); + } + + template + ATOM registerClass(const WndClass* lpWndClass, ATOM(WINAPI* origRegisterClassEx)(const WndClassEx*)) + { + if (!lpWndClass) + { + return origRegisterClassEx(nullptr); + } + + WndClassEx wc = {}; + wc.cbSize = sizeof(wc); + memcpy(&wc.style, lpWndClass, sizeof(*lpWndClass)); + wc.hIconSm = wc.hIcon; + return origRegisterClassEx(&wc); + } + + template + ATOM registerClassEx(const WndClassEx* lpwcx, ATOM(WINAPI* origRegisterClassEx)(const WndClassEx*)) + { + if (!lpwcx) + { + return origRegisterClassEx(nullptr); + } + + WndClassEx wc = *lpwcx; + if (!wc.hIconSm) + { + wc.hIconSm = wc.hIcon; + } + return origRegisterClassEx(&wc); + } + + ATOM WINAPI registerClassA(const WNDCLASSA* lpWndClass) + { + LOG_FUNC("RegisterClassA", lpWndClass); + return LOG_RESULT(registerClass(lpWndClass, CALL_ORIG_FUNC(RegisterClassExA))); + } + + ATOM WINAPI registerClassW(const WNDCLASSW* lpWndClass) + { + LOG_FUNC("RegisterClassW", lpWndClass); + return LOG_RESULT(registerClass(lpWndClass, CALL_ORIG_FUNC(RegisterClassExW))); + } + + ATOM WINAPI registerClassExA(const WNDCLASSEXA* lpwcx) + { + LOG_FUNC("RegisterClassExA", lpwcx); + return LOG_RESULT(registerClassEx(lpwcx, CALL_ORIG_FUNC(RegisterClassExA))); + } + + ATOM WINAPI registerClassExW(const WNDCLASSEXW* lpwcx) + { + LOG_FUNC("RegisterClassExW", lpwcx); + return LOG_RESULT(registerClassEx(lpwcx, CALL_ORIG_FUNC(RegisterClassExW))); + } +} + +#define HOOK_ICON_FUNCTION(module, func) hookIconFunc(#module, #func) + +namespace Gdi +{ + namespace Icon + { + void installHooks() + { + HOOK_ICON_FUNCTION(user32, CopyIcon); + HOOK_ICON_FUNCTION(user32, CopyImage); + HOOK_ICON_FUNCTION(user32, CreateCursor); + HOOK_ICON_FUNCTION(user32, CreateIcon); + HOOK_ICON_FUNCTION(user32, CreateIconFromResource); + HOOK_ICON_FUNCTION(user32, CreateIconFromResourceEx); + HOOK_ICON_FUNCTION(user32, CreateIconIndirect); + HOOK_ICON_FUNCTION(user32, LoadCursorA); + HOOK_ICON_FUNCTION(user32, LoadCursorW); + HOOK_ICON_FUNCTION(user32, LoadCursorFromFileA); + HOOK_ICON_FUNCTION(user32, LoadCursorFromFileW); + HOOK_ICON_FUNCTION(user32, LoadIconA); + HOOK_ICON_FUNCTION(user32, LoadIconW); + HOOK_ICON_FUNCTION(user32, LoadImageA); + HOOK_ICON_FUNCTION(user32, LoadImageW); + HOOK_ICON_FUNCTION(user32, PrivateExtractIconsA); + HOOK_ICON_FUNCTION(user32, PrivateExtractIconsW); + + HOOK_FUNCTION(user32, RegisterClassA, registerClassA); + HOOK_FUNCTION(user32, RegisterClassW, registerClassW); + HOOK_FUNCTION(user32, RegisterClassExA, registerClassExA); + HOOK_FUNCTION(user32, RegisterClassExW, registerClassExW); + } + } +} diff --git a/DDrawCompat/Gdi/Icon.h b/DDrawCompat/Gdi/Icon.h new file mode 100644 index 0000000..b9866d8 --- /dev/null +++ b/DDrawCompat/Gdi/Icon.h @@ -0,0 +1,9 @@ +#pragma once + +namespace Gdi +{ + namespace Icon + { + void installHooks(); + } +} diff --git a/DDrawCompat/Gdi/PresentationWindow.cpp b/DDrawCompat/Gdi/PresentationWindow.cpp index 80bb889..69f0ffc 100644 --- a/DDrawCompat/Gdi/PresentationWindow.cpp +++ b/DDrawCompat/Gdi/PresentationWindow.cpp @@ -88,7 +88,7 @@ namespace wc.lpfnWndProc = &messageWindowProc; wc.hInstance = Dll::g_currentModule; wc.lpszClassName = "DDrawCompatMessageWindow"; - RegisterClass(&wc); + CALL_ORIG_FUNC(RegisterClassA)(&wc); g_messageWindow = CreateWindow( "DDrawCompatMessageWindow", nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr); @@ -136,7 +136,7 @@ namespace Gdi wc.lpfnWndProc = &presentationWindowProc; wc.hInstance = Dll::g_currentModule; wc.lpszClassName = "DDrawCompatPresentationWindow"; - RegisterClass(&wc); + CALL_ORIG_FUNC(RegisterClassA)(&wc); g_presentationWindowThread = CreateThread( nullptr, 0, &presentationWindowThreadProc, nullptr, 0, &g_presentationWindowThreadId);