From fb2d35d21ef8747676935a70041a348c404f3970 Mon Sep 17 00:00:00 2001 From: Cynthia Foxwell Date: Thu, 30 Mar 2023 20:40:29 -0600 Subject: [PATCH] Classic Theme Explorer: goodbye ExplorerPatcher --- classic-theme-explorer.wh.cpp | 387 +++++++++++++++++++++++++++++++++- 1 file changed, 377 insertions(+), 10 deletions(-) diff --git a/classic-theme-explorer.wh.cpp b/classic-theme-explorer.wh.cpp index 4ae0efa..8d38e04 100644 --- a/classic-theme-explorer.wh.cpp +++ b/classic-theme-explorer.wh.cpp @@ -7,7 +7,7 @@ // @github https://github.com/Cynosphere // @homepage https://c7.pm/ // @include explorer.exe -// @compilerOptions -lcomctl32 +// @compilerOptions -lcomctl32 -luxtheme -lgdi32 // ==/WindhawkMod== // ==WindhawkModReadme== @@ -15,7 +15,7 @@ # Classic Theme Explorer Classic Theme mitigations for Explorer as a Windhawk mod. -Based on [SimpleClassicTheme.FileExplorerHook](https://github.com/AEAEAEAE4343/SimpleClassicTheme.FileExplorerHook) and the AutoHotkey scripts that came before it. +Based on [ExplorerPatcher](https://github.com/valinet/ExplorerPatcher), [SimpleClassicTheme.FileExplorerHook](https://github.com/AEAEAEAE4343/SimpleClassicTheme.FileExplorerHook) and the AutoHotkey scripts that came before it. */ // ==/WindhawkModReadme== @@ -45,6 +45,9 @@ Based on [SimpleClassicTheme.FileExplorerHook](https://github.com/AEAEAEAE4343/S - hideRefresh: true $name: "Hide Refresh Button" $description: "Hides the refresh button from Classic Address Bar" +- epMitigate: true + $name: "ExplorerPatcher's Mitigations" + $description: "ExplorerPatcher's Mitigations" */ // ==/WindhawkModSettings== @@ -53,6 +56,9 @@ Based on [SimpleClassicTheme.FileExplorerHook](https://github.com/AEAEAEAE4343/S #include #include #include +#include +#include + #include #include #include @@ -67,6 +73,7 @@ struct { bool addressSyncFullPath; bool addressHeight; bool hideRefresh; + bool epMitigate; } settings; void LoadSettings() { @@ -78,6 +85,7 @@ void LoadSettings() { settings.addressSyncFullPath = Wh_GetIntSetting(L"addressSyncFullPath"); settings.addressHeight = Wh_GetIntSetting(L"addressHeight"); settings.hideRefresh = Wh_GetIntSetting(L"hideRefresh"); + settings.epMitigate = Wh_GetIntSetting(L"epMitigate"); } // Explorer modifications @@ -457,28 +465,387 @@ HWND WINAPI SHCreateWorkerWindowHook(WNDPROC wndProc, HWND hWndParent, DWORD dwE return result; } +// taskbar fixes from ExplorerPatcher +using CreateWindowExW_t = decltype(&CreateWindowExW); +CreateWindowExW_t CreateWindowExW_Orig; +HWND WINAPI CreateWindowExW_Hook(DWORD dwExStyle,LPCWSTR lpClassName,LPCWSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam) { + if (settings.epMitigate && (*((WORD*)&(lpClassName)+1)) && !wcscmp(lpClassName, L"TrayNotifyWnd")) + { + dwExStyle |= WS_EX_STATICEDGE; + } + if (settings.epMitigate && (*((WORD*)&(lpClassName)+1)) && !wcscmp(lpClassName, L"NotifyIconOverflowWindow")) + { + dwExStyle |= WS_EX_STATICEDGE; + } + if (settings.clientEdge && (*((WORD*)&(lpClassName)+1)) && (!wcscmp(lpClassName, L"SysListView32") || !wcscmp(lpClassName, L"SysTreeView32"))) // !wcscmp(lpClassName, L"FolderView") + { + wchar_t wszClassName[200]; + ZeroMemory(wszClassName, 200); + GetClassNameW(GetAncestor(hWndParent, GA_ROOT), wszClassName, 200); + if (!wcscmp(wszClassName, L"CabinetWClass")) + { + dwExStyle |= WS_EX_CLIENTEDGE; + } + } + if (settings.epMitigate && (*((WORD*)&(lpClassName)+1)) && !wcscmp(lpClassName, L"ReBarWindow32")) + { + wchar_t wszClassName[200]; + ZeroMemory(wszClassName, 200); + GetClassNameW(hWndParent, wszClassName, 200); + if (!wcscmp(wszClassName, L"Shell_TrayWnd")) + { + dwStyle |= RBS_BANDBORDERS; + } + } + + HWND hWnd = CreateWindowExW_Orig(dwExStyle,lpClassName,lpWindowName,dwStyle,X,Y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam); + + return hWnd; +} +using SetWindowLongPtrW_t = decltype(&SetWindowLongPtrW); +SetWindowLongPtrW_t SetWindowLongPtrW_Orig; +LONG_PTR SetWindowLongPtrW_Hook(HWND hWnd, int nIndex, LONG_PTR dwNewLong) { + WCHAR lpClassName[200]; + ZeroMemory(lpClassName, 200); + GetClassNameW(hWnd, lpClassName, 200); + HWND hWndParent = GetParent(hWnd); + + if (settings.epMitigate && (*((WORD*)&(lpClassName)+1)) && !wcscmp(lpClassName, L"TrayNotifyWnd")) + { + if (nIndex == GWL_EXSTYLE) + { + dwNewLong |= WS_EX_STATICEDGE; + } + } + if (settings.epMitigate && (*((WORD*)&(lpClassName)+1)) && !wcscmp(lpClassName, L"NotifyIconOverflowWindow")) + { + if (nIndex == GWL_EXSTYLE) + { + dwNewLong |= WS_EX_STATICEDGE; + } + } + if (settings.clientEdge && (*((WORD*)&(lpClassName)+1)) && (!wcscmp(lpClassName, L"SysListView32") || !wcscmp(lpClassName, L"SysTreeView32"))) // !wcscmp(lpClassName, L"FolderView") + { + wchar_t wszClassName[200]; + ZeroMemory(wszClassName, 200); + GetClassNameW(GetAncestor(hWndParent, GA_ROOT), wszClassName, 200); + if (!wcscmp(wszClassName, L"CabinetWClass")) + { + if (nIndex == GWL_EXSTYLE) + { + dwNewLong |= WS_EX_CLIENTEDGE; + } + } + } + if (settings.epMitigate && (*((WORD*)&(lpClassName)+1)) && !wcscmp(lpClassName, L"ReBarWindow32")) + { + wchar_t wszClassName[200]; + ZeroMemory(wszClassName, 200); + GetClassNameW(hWndParent, wszClassName, 200); + if (!wcscmp(wszClassName, L"Shell_TrayWnd")) + { + if (nIndex == GWL_STYLE) + { + dwNewLong |= RBS_BANDBORDERS; + } + } + } + + return SetWindowLongPtrW_Orig(hWnd, nIndex, dwNewLong); +} + +HTHEME(*pOriginalOpenThemeDataForDpi)(HWND hWnd, LPCWSTR pszClassList, UINT dpi); +HTHEME OpenThemeDataForDpiHook(HWND hWnd, LPCWSTR pszClassList, UINT dpi) +{ + if (settings.epMitigate && (*((WORD*)&(pszClassList)+1)) && !wcscmp(pszClassList, L"Taskband2")) { + Wh_Log(L"Redirecting Taskband2 hTheme"); + return (HTHEME)0xDEADBEEF; + } else if (settings.epMitigate && (*((WORD*)&(pszClassList)+1)) && !wcscmp(pszClassList, L"TrayNotifyFlyout")) { + Wh_Log(L"Redirecting TrayNotifyFlyout hTheme"); + return (HTHEME)0xDEADBEFF; + } + + return pOriginalOpenThemeDataForDpi(hWnd, pszClassList, dpi); +} + +HRESULT(*pOriginalGetThemeMetric)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, int iPropId, int* piVal); +HRESULT GetThemeMetricHook(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, int iPropId, int* piVal) { + Wh_Log(L"hTheme: %08X", hTheme); + + if (!settings.epMitigate || (hTheme != (HTHEME)0xDEADBEFF)) { + return pOriginalGetThemeMetric(hTheme, hdc, iPartId, iStateId, iPropId, piVal); + } + + const int TMT_WIDTH = 2416; + const int TMT_HEIGHT = 2417; + if (hTheme == (HTHEME)0xDEADBEFF && iPropId == TMT_WIDTH && iPartId == 3 && iStateId == 0) + { + *piVal = GetSystemMetrics(SM_CXICON); + } + else if (hTheme == (HTHEME)0xDEADBEFF && iPropId == TMT_HEIGHT && iPartId == 3 && iStateId == 0) + { + *piVal = GetSystemMetrics(SM_CYICON); + } + return S_OK; +} + + +HRESULT(*pOriginalGetThemeMargins)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, int iPropId, LPCRECT prc, MARGINS* pMargins); +HRESULT GetThemeMarginsHook(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, int iPropId, LPCRECT prc, MARGINS* pMargins) { + Wh_Log(L"hTheme: %08X", hTheme); + + if (!settings.epMitigate || (hTheme != (HTHEME)0xDEADBEEF && hTheme != (HTHEME)0xDEADBEFF)) { + return pOriginalGetThemeMargins(hTheme, hdc, iPartId, iStateId, iPropId, prc, pMargins); + } + + const int TMT_SIZINGMARGINS = 3601; + const int TMT_CONTENTMARGINS = 3602; + HRESULT hr = S_OK; + if (hTheme) + { + hr = pOriginalGetThemeMargins( + hTheme, + hdc, + iPartId, + iStateId, + iPropId, + prc, + pMargins + ); + } + + if (hTheme == (HTHEME)0xDEADBEEF && iPropId == TMT_CONTENTMARGINS && iPartId == 5 && iStateId == 1) { + // task list button measurements + pMargins->cxLeftWidth = 4; + pMargins->cyTopHeight = 3; + pMargins->cxRightWidth = 4; + pMargins->cyBottomHeight = 3; + } else if (hTheme == (HTHEME)0xDEADBEEF && iPropId == TMT_CONTENTMARGINS && iPartId == 1 && iStateId == 0) { + // task list measurements + pMargins->cxLeftWidth = 0; + pMargins->cyTopHeight = 0; + pMargins->cxRightWidth = 4; + pMargins->cyBottomHeight = 0; + } else if (hTheme == (HTHEME)0xDEADBEEF && iPropId == TMT_SIZINGMARGINS && iPartId == 5 && iStateId == 1) { + pMargins->cxLeftWidth = 10; + pMargins->cyTopHeight = 10; + pMargins->cxRightWidth = 10; + pMargins->cyBottomHeight = 10; + } else if (hTheme == (HTHEME)0xDEADBEFF && iPropId == TMT_CONTENTMARGINS && iPartId == 3 && iStateId == 0) { + pMargins->cxLeftWidth = 4; // GetSystemMetrics(SM_CXICONSPACING); + pMargins->cyTopHeight = 4; // GetSystemMetrics(SM_CYICONSPACING); + pMargins->cxRightWidth = 4; //GetSystemMetrics(SM_CXICONSPACING); + pMargins->cyBottomHeight = 4; // GetSystemMetrics(SM_CYICONSPACING); + } + + HWND hShell_TrayWnd = FindWindowEx(NULL, NULL, L"Shell_TrayWnd", NULL); + if (hShell_TrayWnd) { + LONG dwStyle = 0; + dwStyle = GetWindowLongW(hShell_TrayWnd, GWL_STYLE); + dwStyle |= WS_DLGFRAME; + SetWindowLongW(hShell_TrayWnd, GWL_STYLE, dwStyle); + dwStyle &= ~WS_DLGFRAME; + SetWindowLongW(hShell_TrayWnd, GWL_STYLE, dwStyle); + } + + HWND hWnd = NULL; + do { + hWnd = FindWindowEx( + NULL, + hWnd, + L"Shell_SecondaryTrayWnd", + NULL + ); + if (hWnd) { + LONG dwStyle = 0; + dwStyle = GetWindowLongW(hWnd, GWL_STYLE); + dwStyle |= WS_DLGFRAME; + SetWindowLongW(hWnd, GWL_STYLE, dwStyle); + dwStyle &= ~WS_DLGFRAME; + SetWindowLongW(hWnd, GWL_STYLE, dwStyle); + } + } while (hWnd); + + return S_OK; +} + +HRESULT(*pOriginalDrawThemeTextEx)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int cchText, DWORD dwTextFlags, LPRECT pRect, const DTTOPTS* pOptions); +HRESULT DrawThemeTextExHook(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int cchText, DWORD dwTextFlags, LPRECT pRect, const DTTOPTS* pOptions) { + if (!settings.epMitigate) { + return pOriginalDrawThemeTextEx(hTheme, hdc, iPartId, iStateId, pszText, cchText, dwTextFlags, pRect, pOptions); + } + + COLORREF bc = GetBkColor(hdc); + COLORREF fc = GetTextColor(hdc); + int mode = SetBkMode(hdc, TRANSPARENT); + + wchar_t text[200]; + GetWindowTextW(GetForegroundWindow(), text, 200); + + BOOL bIsActiveUnhovered = (iPartId == 5 && iStateId == 5); + BOOL bIsInactiveUnhovered = (iPartId == 5 && iStateId == 1); + BOOL bIsInactiveHovered = (iPartId == 5 && iStateId == 2); + BOOL bIsActiveHovered = bIsInactiveHovered && !wcscmp(text, pszText); + + SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT)); + + NONCLIENTMETRICSW ncm; + ncm.cbSize = sizeof(NONCLIENTMETRICSW); + SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSW), &ncm, 0); + + HFONT hFont = NULL; + if (bIsActiveUnhovered) + { + hFont = CreateFontIndirectW(&(ncm.lfCaptionFont)); + } + else if (bIsInactiveUnhovered) + { + hFont = CreateFontIndirectW(&(ncm.lfMenuFont)); + } + else if (bIsActiveHovered) + { + hFont = CreateFontIndirectW(&(ncm.lfCaptionFont)); + } + else if (bIsInactiveHovered) + { + hFont = CreateFontIndirectW(&(ncm.lfMenuFont)); + } + else + { + hFont = CreateFontIndirectW(&(ncm.lfMenuFont)); + } + + if (iPartId == 5 && iStateId == 0) // clock + { + pRect->top += 2; + } + + HGDIOBJ hOldFont = SelectObject(hdc, hFont); + DrawTextW( + hdc, + pszText, + cchText, + pRect, + dwTextFlags + ); + SelectObject(hdc, hOldFont); + DeleteObject(hFont); + SetBkColor(hdc, bc); + SetTextColor(hdc, fc); + SetBkMode(hdc, mode); + + return S_OK; +} + +HRESULT(*pOriginalDrawThemeBackground)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPRECT pRect, LPCRECT pClipRect); +HRESULT DrawThemeBackgroundHook(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPRECT pRect, LPCRECT pClipRect) { + if (settings.epMitigate) { + if (iPartId == 4 && iStateId == 1) { + COLORREF bc = GetBkColor(hdc); + COLORREF fc = GetTextColor(hdc); + int mode = SetBkMode(hdc, TRANSPARENT); + + SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT)); + + NONCLIENTMETRICSW ncm; + ncm.cbSize = sizeof(NONCLIENTMETRICSW); + SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSW), &ncm, 0); + + HFONT hFont = CreateFontIndirectW(&(ncm.lfCaptionFont)); + + /*UINT dpiX, dpiY; + HRESULT hr = GetDpiForMonitor( + MonitorFromWindow(WindowFromDC(hdc), MONITOR_DEFAULTTOPRIMARY), + MDT_DEFAULT, + &dpiX, + &dpiY + ); + double dx = dpiX / 96.0, dy = dpiY / 96.0;*/ + + HGDIOBJ hOldFont = SelectObject(hdc, hFont); + DWORD dwTextFlags = DT_SINGLELINE | DT_CENTER | DT_VCENTER; + RECT rc = *pRect; + rc.bottom -= 7; + DrawTextW( + hdc, + L"\u2026", + -1, + &rc, + dwTextFlags + ); + SelectObject(hdc, hOldFont); + DeleteObject(hFont); + SetBkColor(hdc, bc); + SetTextColor(hdc, fc); + SetBkMode(hdc, mode); + } + return S_OK; + } + + return pOriginalDrawThemeBackground(hTheme, hdc, iPartId, iStateId, pRect, pClipRect); +} + +struct WINCOMPATTRDATA +{ + DWORD attribute; + PVOID pData; + ULONG dataSize; +}; + +BOOL (WINAPI *pOriginalSetWindowCompositionAttribute)(HWND hWnd, WINCOMPATTRDATA* pData); +BOOL WINAPI SetWindowCompositionAttributeHook(HWND hWnd, WINCOMPATTRDATA* pData) { + if (settings.epMitigate) { + return TRUE; + } + + return pOriginalSetWindowCompositionAttribute(hWnd, pData); +} + // Windhawk boilerplate BOOL Wh_ModInit() { - Wh_Log(L"Init"); - LoadSettings(); HMODULE hShcore = GetModuleHandle(L"shcore.dll"); - void* origFunc = (void*)GetProcAddress(hShcore, (LPCSTR)188); - Wh_SetFunctionHook(origFunc, (void*)SHCreateWorkerWindowHook, (void**)&pOriginalSHCreateWorkerWindow); + void* origCWW = (void*)GetProcAddress(hShcore, (LPCSTR)188); + Wh_SetFunctionHook(origCWW, (void*)SHCreateWorkerWindowHook, (void**)&pOriginalSHCreateWorkerWindow); + + HMODULE hUxtheme = GetModuleHandle(L"uxtheme.dll"); + + void* origOTDFD = (void*)GetProcAddress(hUxtheme, "OpenThemeDataForDpi"); + Wh_SetFunctionHook(origOTDFD, (void*)OpenThemeDataForDpiHook, (void**)&pOriginalOpenThemeDataForDpi); + + void* origGTMe = (void*)GetProcAddress(hUxtheme, "GetThemeMetric"); + Wh_SetFunctionHook(origGTMe, (void*)GetThemeMetricHook, (void**)&pOriginalGetThemeMetric); + + void* origGTMa = (void*)GetProcAddress(hUxtheme, "GetThemeMargins"); + Wh_SetFunctionHook(origGTMa, (void*)GetThemeMarginsHook, (void**)&pOriginalGetThemeMargins); + + void* origDTTE = (void*)GetProcAddress(hUxtheme, "DrawThemeTextEx"); + Wh_SetFunctionHook(origDTTE, (void*)DrawThemeTextExHook, (void**)&pOriginalDrawThemeTextEx); + + void* origDTB = (void*)GetProcAddress(hUxtheme, "DrawThemeBackground"); + Wh_SetFunctionHook(origDTB, (void*)DrawThemeBackgroundHook, (void**)&pOriginalDrawThemeBackground); + + //HMODULE hUser32 = GetModuleHandle(L"user32.dll"); + + //void* origSWCA = (void*)GetProcAddress(hUser32, "SetWindowCompositionAttribute"); + //Wh_SetFunctionHook(origSWCA, (void*)SetWindowCompositionAttributeHook, (void**)&pOriginalSetWindowCompositionAttribute); + + Wh_SetFunctionHook((void*)CreateWindowExW, + (void*)CreateWindowExW_Hook, + (void**)&CreateWindowExW_Orig); + Wh_SetFunctionHook((void*)SetWindowLongPtrW, + (void*)SetWindowLongPtrW_Hook, + (void**)&SetWindowLongPtrW_Orig); return TRUE; } void Wh_ModUninit() { - Wh_Log(L"Uninit"); - if (g_uiThreadId != 0) EnumThreadWindows(g_uiThreadId, EnumBrowserWindowsUnsubclassFunc, 0); } void Wh_ModSettingsChanged() { - Wh_Log(L"SettingsChanged"); - LoadSettings(); }