1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00

Disable DIB redirection for icon and cursor creating functions

Fixes corrupt icon in volume mixer.
This commit is contained in:
narzoul 2021-02-14 12:31:39 +01:00
parent 8b8a4e544f
commit b83f7ca879
8 changed files with 197 additions and 123 deletions

View File

@ -220,6 +220,7 @@
<ClInclude Include="Gdi\Dc.h" />
<ClInclude Include="Gdi\DcCache.h" />
<ClInclude Include="Gdi\DcFunctions.h" />
<ClInclude Include="Gdi\Icon.h" />
<ClInclude Include="Gdi\Metrics.h" />
<ClInclude Include="Gdi\PresentationWindow.h" />
<ClInclude Include="Gdi\User32WndProcs.h" />
@ -294,6 +295,7 @@
<ClCompile Include="Gdi\Dc.cpp" />
<ClCompile Include="Gdi\DcCache.cpp" />
<ClCompile Include="Gdi\DcFunctions.cpp" />
<ClCompile Include="Gdi\Icon.cpp" />
<ClCompile Include="Gdi\Metrics.cpp" />
<ClCompile Include="Gdi\PresentationWindow.cpp" />
<ClCompile Include="Gdi\User32WndProcs.cpp" />

View File

@ -402,6 +402,9 @@
<ClInclude Include="Gdi\CompatDc.h">
<Filter>Header Files\Gdi</Filter>
</ClInclude>
<ClInclude Include="Gdi\Icon.h">
<Filter>Header Files\Gdi</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Gdi\Gdi.cpp">
@ -620,5 +623,8 @@
<ClCompile Include="Gdi\CompatDc.cpp">
<Filter>Source Files\Gdi</Filter>
</ClCompile>
<ClCompile Include="Gdi\Icon.cpp">
<Filter>Source Files\Gdi</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -9,13 +9,12 @@
#include <Gdi/Gdi.h>
#include <Gdi/Region.h>
#include <Gdi/VirtualScreen.h>
#include <Gdi/Window.h>
#include <Win32/DisplayMode.h>
namespace
{
std::unordered_map<void*, const char*> g_funcNames;
thread_local bool g_redirectToDib = true;
thread_local UINT g_disableDibRedirection = 0;
#define CREATE_DC_FUNC_ATTRIBUTE(attribute) \
template <typename OrigFuncPtr, OrigFuncPtr origFunc> \
@ -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<OrigFuncPtr, origFunc>(origFunc));
}
template <typename WndClass, typename WndClassEx>
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 <typename WndClassEx>
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<LPCSTR>(atom), "", 0, 0, 0, 0, 0, nullptr, nullptr, nullptr, nullptr);
if (!hwnd)
{
UnregisterClass(reinterpret_cast<LPCSTR>(atom), GetModuleHandle(nullptr));
return origRegisterClassEx(lpWndClassEx);
}
if (lpWndClassEx->hIcon)
{
SetClassLong(hwnd, GCL_HICON, reinterpret_cast<LONG>(lpWndClassEx->hIcon));
}
if (lpWndClassEx->hIconSm)
{
SetClassLong(hwnd, GCL_HICONSM, reinterpret_cast<LONG>(lpWndClassEx->hIconSm));
}
origSetClassLong(hwnd, GCL_WNDPROC, reinterpret_cast<LONG>(lpWndClassEx->lpfnWndProc));
SetWindowLong(hwnd, GWL_WNDPROC, reinterpret_cast<LONG>(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);
}
}
}

View File

@ -4,6 +4,8 @@ namespace Gdi
{
namespace DcFunctions
{
void disableDibRedirection(bool disable);
void installHooks();
}
}

View File

@ -5,6 +5,7 @@
#include <Gdi/DcFunctions.h>
#include <Gdi/Font.h>
#include <Gdi/Gdi.h>
#include <Gdi/Icon.h>
#include <Gdi/Metrics.h>
#include <Gdi/Palette.h>
#include <Gdi/PresentationWindow.h>
@ -40,6 +41,7 @@ namespace Gdi
DisableProcessWindowsGhosting();
DcFunctions::installHooks();
Icon::installHooks();
Metrics::installHooks();
Palette::installHooks();
PresentationWindow::installHooks();

165
DDrawCompat/Gdi/Icon.cpp Normal file
View File

@ -0,0 +1,165 @@
#include <map>
#include <Common/Hook.h>
#include <Common/Log.h>
#include <Gdi/DcFunctions.h>
#include <Gdi/Icon.h>
namespace
{
std::map<void*, const char*> g_funcNames;
template <typename Result, typename... Params>
using FuncPtr = Result(WINAPI*)(Params...);
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename... Params>
struct EnableDibRedirection
{
bool operator()(Params...) { return false; }
};
template <typename... Params>
struct EnableDibRedirection<decltype(&CopyImage), &CopyImage, Params...>
{
bool operator()(HANDLE, UINT type, int, int, UINT)
{
return IMAGE_CURSOR != type && IMAGE_ICON != type;
}
};
struct EnableDibRedirectionLoadImage
{
template <typename String>
bool operator()(HINSTANCE, String, UINT type, int, int, UINT)
{
return IMAGE_CURSOR != type && IMAGE_ICON != type;
}
};
template <typename... Params>
struct EnableDibRedirection<decltype(&LoadImageA), &LoadImageA, Params...> : EnableDibRedirectionLoadImage {};
template <typename... Params>
struct EnableDibRedirection<decltype(&LoadImageW), &LoadImageW, Params...> : EnableDibRedirectionLoadImage {};
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params>
Result WINAPI iconFunc(Params... params)
{
LOG_FUNC(g_funcNames[origFunc], params...);
if (EnableDibRedirection<OrigFuncPtr, origFunc, Params...>()(params...))
{
return LOG_RESULT(Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(params...));
}
Gdi::DcFunctions::disableDibRedirection(true);
Result result = Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(params...);
Gdi::DcFunctions::disableDibRedirection(false);
return LOG_RESULT(result);
}
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params>
OrigFuncPtr getIconFuncPtr(FuncPtr<Result, Params...>)
{
return &iconFunc<OrigFuncPtr, origFunc, Result, Params...>;
}
template <typename OrigFuncPtr, OrigFuncPtr origFunc>
void hookIconFunc(const char* moduleName, const char* funcName)
{
#ifdef DEBUGLOGS
g_funcNames[origFunc] = funcName;
#endif
Compat::hookFunction<OrigFuncPtr, origFunc>(
moduleName, funcName, getIconFuncPtr<OrigFuncPtr, origFunc>(origFunc));
}
template <typename WndClass, typename WndClassEx>
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 <typename WndClassEx>
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<decltype(&func), &func>(#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);
}
}
}

9
DDrawCompat/Gdi/Icon.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
namespace Gdi
{
namespace Icon
{
void installHooks();
}
}

View File

@ -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);