From a08c60fdb07f810002787e4b6bf12dd0828973ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aubrey/=E3=82=AA=E3=83=BC=E3=83=96=E3=83=AA=E3=83=BC?= <44238627+aubymori@users.noreply.github.com> Date: Sat, 4 Nov 2023 21:19:53 -0500 Subject: [PATCH] Message Box Fix 1.4.6 (#357) * Add option to fix background color for pre-Windows Vista classic theme look --- mods/msg-box-font-fix.wh.cpp | 261 ++++++++++++++++++++++++++++++----- 1 file changed, 227 insertions(+), 34 deletions(-) diff --git a/mods/msg-box-font-fix.wh.cpp b/mods/msg-box-font-fix.wh.cpp index 204ddd128..3b079042c 100644 --- a/mods/msg-box-font-fix.wh.cpp +++ b/mods/msg-box-font-fix.wh.cpp @@ -1,34 +1,36 @@ // ==WindhawkMod== // @id msg-box-font-fix -// @name Message Box Font Fix -// @description Fixes the MessageBox font size in 1709+ -// @version 1.2 +// @name Message Box Fix +// @description Fixes the MessageBox font size and background +// @version 1.4.6 // @author aubymori // @github https://github.com/aubymori // @include * -// @compilerOptions -luser32 -lgdi32 -// @architecture x86-64 +// @compilerOptions -luser32 -lgdi32 -lcomctl32 // ==/WindhawkMod== // ==WindhawkModReadme== /* -# IMPORTANT -Due to a bug with Windhawk's symbols system, this mod will only work on 64-bit applications for now. +# Message Box Fix +Starting with Windows Vista, message boxes render the "Window" color in their upper half. -# Message Box Font Fix 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 that. +This mod fixes both of those things. + +**This mod will only work on Windhawk v1.4 and greater.** **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 @@ -36,14 +38,46 @@ 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 -typedef HFONT (*GetMessageBoxFontForDpi_t)(UINT); +struct { + BOOL font; + BOOL background; +} settings; + +/* Only available in Windows 10 version 1607 and greater. */ +UINT (* WINAPI GetDpiForSystem)(void); + +/* Message box text windows that have been + subclassed for background removal. + + See WM_PAINT on MsgBoxTextSubclassProc. */ +std::vector subclassed; + +typedef HFONT (__fastcall *GetMessageBoxFontForDpi_t)(UINT); GetMessageBoxFontForDpi_t GetMessageBoxFontForDpi_orig; -HFONT GetMessageBoxFontForDpi_hook( +HFONT __fastcall GetMessageBoxFontForDpi_hook( UINT nDpi ) { + if (!settings.font) + { + return GetMessageBoxFontForDpi_orig( + nDpi + ); + } + NONCLIENTMETRICSW ncm; ncm.cbSize = sizeof(NONCLIENTMETRICSW); @@ -57,50 +91,209 @@ HFONT GetMessageBoxFontForDpi_hook( return CreateFontIndirectW(&(ncm.lfMessageFont)); } -BOOL Wh_ModInit() +LRESULT CALLBACK MsgBoxTextSubclassProc( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam, + DWORD_PTR dwRefData +) { - Wh_Log(L"Initializing Message Box Font Fix"); + if (settings.background) + { + switch (uMsg) + { + /* I literally could not find any style or anything that could + remove the background on this, so I just paint it myself. + Sorry. */ + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hDC = BeginPaint(hWnd, &ps); + + RECT rcClient; + GetClientRect(hWnd, &rcClient); - HMODULE hUser32 = LoadLibraryW(L"user32.dll"); + 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; + } + )); + return 0; + } + } + + return DefSubclassProc(hWnd, uMsg, wParam, lParam); +} + +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 +) +{ + if (settings.background) + { + 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; + BeginPaint(hWnd, &ps); + EndPaint(hWnd, &ps); + return TRUE; + } + } + } + + return MB_DlgProc_orig(hWnd, uMsg, wParam, lParam); +} + +void LoadSettings(void) +{ + settings.font = Wh_GetIntSetting(L"font"); + settings.background = Wh_GetIntSetting(L"background"); +} + +BOOL Wh_ModInit(void) +{ + 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 your Windows install or Windhawk.", - L"Windhawk: Message Box Font Fix", + L"Failed to load user32.dll. There is something seriously wrong with either your Windows install or Windhawk.", + L"Windhawk: Message Box Fix", MB_ICONERROR ); return FALSE; } - WindhawkUtils::SYMBOL_HOOK symbolHooks[] = { + GetDpiForSystem = (UINT (* WINAPI)(void))GetProcAddress(hUser32, "GetDpiForSystem"); + + WindhawkUtils::SYMBOL_HOOK hooks[] = { + { + { + L"struct HFONT__ * " + #ifdef _WIN64 + L"__cdecl" + #else + L"__stdcall" + #endif + L" GetMessageBoxFontForDpi(unsigned int)" + }, + &GetMessageBoxFontForDpi_orig, + GetMessageBoxFontForDpi_hook, + false + }, { { - L"struct HFONT__ * __cdecl GetMessageBoxFontForDpi(unsigned int)" + #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 **)&GetMessageBoxFontForDpi_orig, - (void *)GetMessageBoxFontForDpi_hook + &MB_DlgProc_orig, + MB_DlgProc_hook, + false } }; - bool bHookSuccess = HookSymbols( - hUser32, - symbolHooks, - ARRAYSIZE(symbolHooks) - ); - - if (!bHookSuccess) + if (!HookSymbols(hUser32, hooks, ARRAYSIZE(hooks))) { - // Many applications will always fail to hook this. - // Coincidentally, none of these ever use MessageBox. - // At least for me. Anyways, silently fail to log, - // we don't want to bombard the user with a million - // error message boxes. - Wh_Log(L"Failed to hook GetMessageBoxFontForDpi"); + Wh_Log(L"Failed to hook one or more symbol functions"); return FALSE; } - Wh_Log(L"Done initializing Message Box Font 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 + ); + } +} + +void Wh_ModSettingsChanged(void) +{ + LoadSettings(); } \ No newline at end of file