Classic Task Dialog Fix
Oct 7, 2023 21:16:06 GMT -8
Post by aubymori on Oct 7, 2023 21:16:06 GMT -8
IMPORTANT: This mod has been moved to the official Windhawk repository. As such, this post is likely to be outdated.
In Windows 10, the button sizing for task dialogs is wrong.
This mod fixes that.
Before:
After:
Prerequisite mod (2023/10/07)
As of now (2023/10/07), there is a bug in Windhawk's symbol hook system which makes mods that hook symbols crash on x86 (32-bit) programs.
You MUST install this mod, or else EVERY 32-bit application (INCLUDING THE WINDHAWK UI AND THE WINDHAWK ENGINE ITSELF) will CRASH.
// ==WindhawkMod==
// @id -windhawk-load-symbols-self-fix
// @name Windhawk load symbols self fix
// @description Fix Windhawk symbol loading for 32-bit apps
// @version 0.2
// @author m417z
// @include *
// @architecture x86
// ==/WindhawkMod==
// ==WindhawkModReadme==
/*
# Windhawk load symbols self fix
A temporary fix until a new version is released. The name starts with a dash to
make the mod loaded first.
*/
// ==/WindhawkModReadme==
#include <initializer_list>
bool fix() {
HMODULE module = GetModuleHandle(L"windhawk.dll");
if (!module) {
return false;
}
struct {
size_t rva;
std::initializer_list<BYTE> original;
std::initializer_list<BYTE> patched;
} patches[] = {
{0x2A3D2, {0x8B, 0xE5}, {0xEB, 0x3A}},
{0x2A3FD, {0x8B, 0xE5}, {0xEB, 0x0F}},
{0x2A411, {0xC3, 0xCC, 0xCC}, {0xC2, 0x14, 0x00}},
};
for (const auto& patch : patches) {
BYTE* address = (BYTE*)module + patch.rva;
if (memcmp(address, patch.original.begin(), patch.original.size()) != 0) {
return false;
}
}
for (const auto& patch : patches) {
BYTE* address = (BYTE*)module + patch.rva;
DWORD dwOldProtect;
VirtualProtect(address, patch.patched.size(), PAGE_EXECUTE_READWRITE, &dwOldProtect);
memcpy(address, patch.patched.begin(), patch.patched.size());
VirtualProtect(address, patch.patched.size(), dwOldProtect, &dwOldProtect);
}
return true;
}
BOOL Wh_ModInit() {
Wh_Log(L"Init " WH_MOD_ID L" version " WH_MOD_VERSION);
fix();
return TRUE;
}
void Wh_ModUninit() {
Wh_Log(L"Uninit");
}
Mod code
// ==WindhawkMod==
// @id classic-taskdlg-fix
// @name Classic Task Dialog Fix
// @description Fixes task dialogs in classic theme.
// @version 1.0.1
// @author aubymori
// @github https://github.com/aubymori
// @include *
// @architecture x86-64
// ==/WindhawkMod==
// ==WindhawkModReadme==
/*
# Classic Task Dialog Fix
In Windows 10, the button sizing for task dialogs is wrong.
This mod fixes that.
*/
// ==/WindhawkModReadme==
#include <windhawk_utils.h>
/* Calling conventions */
#ifdef _WIN64
/* __thiscall */
#define THISCALL __cdecl
#define STHISCALL L"__cdecl"
#else
/* __thiscall */
#define THISCALL __thiscall
#define STHISCALL L"__thiscall"
#endif
/* Only available in Windows 10 1607 and up. */
UINT (* GetSystemDpiForProcess)(HANDLE);
typedef LPSIZE (* THISCALL DirectUI_CCPushButton_GetContentSize_t)(void *, LPSIZE, int, void *, HDC);
DirectUI_CCPushButton_GetContentSize_t DirectUI_CCPushButton_GetContentSize_orig;
LPSIZE THISCALL DirectUI_CCPushButton_GetContentSize_hook(
void *pThis,
LPSIZE psz,
int i1,
void *pSurface,
HDC hDC /* Not actually a real device context :/ */
)
{
/* Get original metrics */
DirectUI_CCPushButton_GetContentSize_orig(
pThis, psz, i1, pSurface, hDC
);
int dpi;
if (GetSystemDpiForProcess)
{
dpi = GetSystemDpiForProcess(GetCurrentProcess());
}
else
{
dpi = 96;
}
psz->cy = MulDiv(22, dpi, 96);
return psz;
}
#ifdef _WIN64
# define PATHCACHE_VALNAME L"last-comctl32-v6-path"
#else
# define PATHCACHE_VALNAME L"last-comctl32-v6-path-wow64"
#endif
#define COMCTL_582_SEARCH L"microsoft.windows.common-controls_6595b64144ccf1df_5.82"
/* Load the ComCtl32 module */
HMODULE LoadComCtlModule(void)
{
HMODULE hComCtl = LoadLibraryW(L"comctl32.dll");
if (!hComCtl)
{
return NULL;
}
WCHAR szPath[MAX_PATH];
GetModuleFileNameW(hComCtl, szPath, MAX_PATH);
WCHAR szv6Path[MAX_PATH];
BOOL bNoCache = FALSE;
if (!Wh_GetStringValue(PATHCACHE_VALNAME, szv6Path, MAX_PATH))
{
bNoCache = TRUE;
}
/**
* the !bNoCache check here is nested because we only want to fall through
* to the cacher if the current comctl32 path is NOT 5.82.
*/
if (wcsstr(szPath, COMCTL_582_SEARCH))
{
if (!bNoCache)
{
hComCtl = LoadLibraryW(szv6Path);
}
}
else if (bNoCache || wcsicmp(szPath, szv6Path))
{
Wh_SetStringValue(PATHCACHE_VALNAME, szPath);
}
return hComCtl;
}
BOOL Wh_ModInit(void)
{
HMODULE hComCtl32 = LoadComCtlModule();
if (!hComCtl32)
{
Wh_Log(L"Failed to load comctl32.dll");
return FALSE;
}
HMODULE hUser32 = LoadLibraryW(L"user32.dll");
if (hUser32)
{
GetSystemDpiForProcess = (UINT(*)(HANDLE))GetProcAddress(hUser32, "GetSystemDpiForProcess");
}
WindhawkUtils::SYMBOL_HOOK hook = {
{
L"public: virtual struct tagSIZE "
STHISCALL
L" DirectUI::CCPushButton::GetContentSize(int,int,class DirectUI::Surface *)"
},
(void **)&DirectUI_CCPushButton_GetContentSize_orig,
(void *)DirectUI_CCPushButton_GetContentSize_hook,
false
};
if (!HookSymbols(hComCtl32, &hook, 1))
{
Wh_Log(L"Failed to hook DirectUI::CCPushButton::GetContentSize");
return FALSE;
}
return TRUE;
}