Classic Theme Explorer: goodbye ExplorerPatcher

This commit is contained in:
Cynthia Foxwell 2023-03-30 20:40:29 -06:00
parent c4d84e84ce
commit fb2d35d21e

View file

@ -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 <initguid.h>
#include <commctrl.h>
#include <dwmapi.h>
#include <uxtheme.h>
#include <wingdi.h>
#include <string>
#include <regex>
#include <locale>
@ -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();
}