Message Box Fix
Oct 2, 2023 13:53:51 GMT -8
Post by aubymori on Oct 2, 2023 13:53:51 GMT -8
IMPORTANT: This mod has been moved to the official Windhawk repository. As such, this post is likely to be outdated.
This mod I made for Windhawk fixes both the font size and the background of message boxes.
Before:
After:
Prerequisite mod (2023/10/02)
As of now (2023/10/02), 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 msg-box-font-fix
// @name Message Box Fix
// @description Fixes the MessageBox font size and background
// @version 1.4.5
// @author aubymori
// @github https://github.com/aubymori
// @include *
// @compilerOptions -luser32 -lgdi32 -lcomctl32
// ==/WindhawkMod==
// ==WindhawkModReadme==
/*
# Message Box Fix
Starting with Windows Vista, message boxes render the "Window" color in their upper half.
Starting with Windows 10 1709, message boxes render their font size 1pt less than the
user-defined size.\* You cannot just set this size higher, as many applications still query
it, and will show up with bigger fonts.
This mod fixes both of those things.
**Before:**
![Before](https://raw.githubusercontent.com/aubymori/images/main/message-box-font-fix-before.png)
![Before (classic)](https://raw.githubusercontent.com/aubymori/images/main/message-box-fix-before-classic.png)
**After:**
![After](https://raw.githubusercontent.com/aubymori/images/main/message-box-font-fix-after.png)
![After (classic)](https://raw.githubusercontent.com/aubymori/images/main/message-box-fix-after-classic.png)
*\*Microsoft changed the way the font size was calculator for Per-Monitor V2 DPI awareness. It ALWAYS gets
1pt below the font size, even when on a higher DPI. This is because Microsoft decided to do some weird math
instead of just using `SystemParametersInfoW` like a normal person.*
*/
// ==/WindhawkModReadme==
// ==WindhawkModSettings==
/*
- font: true
$name: Fix font size
$description: Fix font rendering
- background: false
$name: Remove "Window" background
$description: Remove the "Window" color from the background, much like XP and before
*/
// ==/WindhawkModSettings==
#include <windhawk_utils.h>
struct {
BOOL font;
BOOL background;
} settings;
UINT (* WINAPI GetDpiForSystem)(void);
std::vector<HWND> subclassed;
typedef HFONT (*GetMessageBoxFontForDpi_t)(UINT);
GetMessageBoxFontForDpi_t GetMessageBoxFontForDpi_orig;
HFONT GetMessageBoxFontForDpi_hook(
UINT nDpi
)
{
NONCLIENTMETRICSW ncm;
ncm.cbSize = sizeof(NONCLIENTMETRICSW);
SystemParametersInfoW(
SPI_GETNONCLIENTMETRICS,
sizeof(NONCLIENTMETRICSW),
&ncm,
0
);
return CreateFontIndirectW(&(ncm.lfMessageFont));
}
/**
* HACK: The function that easily gets a symbol also hooks it, so just
* direct it here if the user doesn't want their fonts fixed for whatever
* reason.
*/
HFONT GetMessageBoxFontForDpi_hook_none(
UINT nDpi
)
{
return GetMessageBoxFontForDpi_orig(nDpi);
}
BOOL CALLBACK EnumChildrenProc(HWND hWnd, LPARAM lParam)
{
DWORD dwStyle = GetWindowLongW(hWnd, GWL_STYLE);
if ((dwStyle & SS_EDITCONTROL) == SS_EDITCONTROL)
{
*(HWND *)lParam = hWnd;
return FALSE;
}
return TRUE;
}
LRESULT CALLBACK MsgBoxTextSubclassProc(
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
DWORD_PTR dwRefData
)
{
switch (uMsg)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hDC = BeginPaint(hWnd, &ps);
RECT rcClient;
GetClientRect(hWnd, &rcClient);
int len = GetWindowTextLengthW(hWnd) + 1;
LPWSTR szText = (LPWSTR)malloc(sizeof(WCHAR) * len);
GetWindowTextW(hWnd, szText, len);
HFONT hfMsg;
if (settings.font || !GetDpiForSystem)
{
hfMsg = GetMessageBoxFontForDpi_hook(
GetDpiForSystem ? GetDpiForSystem() : 96
);
}
else
{
hfMsg = GetMessageBoxFontForDpi_orig(GetDpiForSystem());
}
HFONT hfOld = (HFONT)SelectObject(hDC, hfMsg);
SetBkMode(hDC, TRANSPARENT);
SetTextColor(hDC, GetSysColor(COLOR_BTNTEXT));
DRAWTEXTPARAMS dtp = { 0 };
dtp.cbSize = sizeof(DRAWTEXTPARAMS);
dtp.uiLengthDrawn = wcslen(szText);
DrawTextExW(
hDC,
szText,
-1,
&rcClient,
DT_LEFT | DT_WORDBREAK | DT_EDITCONTROL,
&dtp
);
SelectObject(hDC, hfOld);
DeleteObject(hfMsg);
free(szText);
EndPaint(hWnd, &ps);
return 0;
}
case WM_DESTROY:
subclassed.erase(std::remove_if(
subclassed.begin(),
subclassed.end(),
[hWnd](HWND hw)
{
return hw == hWnd;
}
));
break;
default:
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
typedef INT_PTR (* WINAPI MB_DlgProc_t)(HWND, UINT, WPARAM, LPARAM);
MB_DlgProc_t MB_DlgProc_orig;
INT_PTR WINAPI MB_DlgProc_hook(
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
switch (uMsg)
{
case WM_CTLCOLORDLG:
case WM_CTLCOLORSTATIC:
return (INT_PTR)GetSysColorBrush(COLOR_3DFACE);
/* The static window for text itself must handle WM_CTLCOLORSTATIC */
case WM_INITDIALOG:
{
HWND hTxt = GetDlgItem(hWnd, 65535);
if (WindhawkUtils::SetWindowSubclassFromAnyThread(hTxt, MsgBoxTextSubclassProc, NULL))
{
subclassed.push_back(hTxt);
}
return MB_DlgProc_orig(hWnd, uMsg, wParam, lParam);
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hDC = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
}
default:
return MB_DlgProc_orig(hWnd, uMsg, wParam, lParam);
}
return TRUE;
}
void LoadSettings(void)
{
settings.font = Wh_GetIntSetting(L"font");
settings.background = Wh_GetIntSetting(L"background");
}
BOOL Wh_ModInit(void)
{
Wh_Log(L"Initializing Message Box Font Fix");
LoadSettings();
HMODULE hUser32 = GetModuleHandleW(L"user32.dll");
if (!hUser32)
{
hUser32 = LoadLibraryW(L"user32.dll");
}
if (!hUser32)
{
MessageBoxW(
NULL,
L"Failed to load user32.dll. There is something seriously wrong with either your Windows install or Windhawk.",
L"Windhawk: Message Box Font Fix",
MB_ICONERROR
);
return FALSE;
}
GetDpiForSystem = (UINT (* WINAPI)(void))GetProcAddress(hUser32, "GetDpiForSystem");
WindhawkUtils::SYMBOL_HOOK hooks[2];
int nHooks = 1;
hooks[0] = {
{
L"struct HFONT__ * "
#ifdef _WIN64
L"__cdecl"
#else
L"__stdcall"
#endif
L" GetMessageBoxFontForDpi(unsigned int)"
},
(void **)&GetMessageBoxFontForDpi_orig,
settings.font
? (void *)GetMessageBoxFontForDpi_hook
: (void *)GetMessageBoxFontForDpi_hook_none,
TRUE
};
if (settings.background)
{
nHooks++;
hooks[1] = {
{
#ifdef _WIN64
L"__int64 __cdecl MB_DlgProc(struct HWND__ *,unsigned int,unsigned __int64,__int64)"
#else
L"int __stdcall MB_DlgProc(struct HWND__ *,unsigned int,unsigned int,long)"
#endif
},
(void **)&MB_DlgProc_orig,
(void *)MB_DlgProc_hook,
TRUE
};
}
if (!HookSymbols(hUser32, hooks, nHooks))
{
Wh_Log(L"Failed to hook GetMessageBoxFontForDpi or MB_DlgProc");
return FALSE;
}
Wh_Log(L"Done initializing Message Box Fix");
return TRUE;
}
/**
* Remove any subclasses from message box texts that are still there
* If we don't do this, programs with open message boxes will crash
*/
void Wh_ModUninit(void)
{
size_t len = subclassed.size();
for (size_t i = 0; i < len; i++)
{
WindhawkUtils::RemoveWindowSubclassFromAnyThread(
subclassed[i],
MsgBoxTextSubclassProc
);
}
}
BOOL Wh_ModSettingsChanged(BOOL *bReload)
{
*bReload = TRUE;
return TRUE;
}