Skip to content

Commit

Permalink
Add Explorerframe fixes for Win11 22H2+ (#864)
Browse files Browse the repository at this point in the history
* Add Explorerframe fixes for Win11 22H2+

* Explorerframe fixes for Win11: fix hook variable names

* Explorerframe fixes for Win11: fix hook variable names 2
  • Loading branch information
CyprinusCarpio authored Aug 15, 2024
1 parent 1f573ac commit 441cbdf
Showing 1 changed file with 282 additions and 0 deletions.
282 changes: 282 additions & 0 deletions mods/explorerframe-fixes-for-win11-22h2plus.wh.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
// ==WindhawkMod==
// @id explorerframe-fixes-for-win11-22h2plus
// @name Explorerframe fixes for Win11 22H2+
// @description Fixes three problems with file explorer
// @version 1.0
// @author Waldemar
// @github https://github.com/CyprinusCarpio
// @include explorer.exe
// @architecture x86-64
// @compilerOptions -lcomctl32 -lgdi32
// ==/WindhawkMod==

// ==WindhawkModReadme==
/*
# Explorerframe fixes for Win11 22H2+
This mod fixes a couple of issues with File Explorer windows appearance in Windows 11 releases 22H2, 23H2 and 24H2.
Unpredictable menu bar appearance: On Windows 11 22H2 and 23H2, the menu bar may appear unpredictably. This mod allows the user to disable the menu bar entirely, or have it be shown at all times.
You can force show/hide the menu bar in the mod settings. Forcing the menu bar to be shown is intended for the Classic theme.
Delay on navigation to a new folder when using SysListView32: this is caused by a extra erroneous message sent to the list view window. This mod supresses it, fixing the problem.
Black artifacts briefly visible in new file explorer windows under Classic theme: this is caused by incorrect handling of WM_ERASEBKGND in CabinetWClass window procedure. This mod adds a option to correct this.
Changes will be visible in new file explorer windows.
*/
// ==/WindhawkModReadme==
#include <windhawk_utils.h>
#include <Windows.h>
#include <vector>

// ==WindhawkModSettings==
/*
- DisplayMenuBar: true
$name: Display Menu Bar
$description: Whether to display the menu bar. This overrides system behaviour, which is unpredictable.
- ClassicBackgroundColor: false
$name: Classic CabinetWClass background color
$description: Use classic background color for explorer windows.
*/
// ==/WindhawkModSettings==

bool g_settingDisplayMenuBar;
bool g_settingFixCWCBackground;
std::vector<HWND> g_subclassedRebars;
std::vector<HWND> g_subclassedListviews;

int FindMenuBand(HWND hReBar)
{
int bandCount = (int)SendMessage(hReBar, RB_GETBANDCOUNT, 0, 0);
for (int i = 0; i < bandCount; i++)
{
REBARBANDINFO rbbi = { sizeof(REBARBANDINFO) };
rbbi.fMask = RBBIM_CHILD | RBBIM_STYLE;
SendMessage(hReBar, RB_GETBANDINFO, i, (LPARAM)&rbbi);

if (rbbi.hwndChild == NULL) continue;

// Check if the child window is a ToolbarWindow32
wchar_t className[256];
GetClassNameW(rbbi.hwndChild, className, sizeof(className));
if (lstrcmpW(className, L"ToolbarWindow32") != 0) continue;

// Check for image list. Menu doesn't have one.
if(SendMessageW(rbbi.hwndChild, TB_GETIMAGELIST, 0, 0) != NULL) continue;

return i;
}

return -1;
}

#define HACKFIX_FLAGS SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE

LRESULT CALLBACK RebarSubclassProc(_In_ HWND hWnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam,
_In_ DWORD_PTR dwRefData)
{
if(uMsg == WM_DESTROY)
{
g_subclassedRebars.erase(std::remove_if(
g_subclassedRebars.begin(), g_subclassedRebars.end(),
[hWnd](HWND &h)
{
return h == hWnd;
}));
return 0;
}
if(uMsg == RB_SHOWBAND)
{
if((int)wParam == FindMenuBand(hWnd))
{
LRESULT toRet = DefSubclassProc(hWnd, uMsg, wParam, g_settingDisplayMenuBar);
if(g_settingDisplayMenuBar)
{
// If the following hack is not done, menu bar items may be invisible.
HWND stwc = GetParent(GetParent(hWnd));
RECT rect;
GetClientRect(stwc, &rect);
int wx = rect.right - rect.left;
int wy = rect.bottom - rect.top;
SetWindowPos(stwc, NULL, 0, 0, wx <= 0 ? 1300 : wx + 1, wy <= 0 ? 900 : wy + 1, HACKFIX_FLAGS);
if(wx <= 0)
SetWindowPos(stwc, NULL, 0, 0, wx, wy, HACKFIX_FLAGS);
RedrawWindow(stwc, NULL, NULL, RDW_INVALIDATE);
}
return toRet;
}
}

return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}

typedef long (*__cdecl CBSInitialize_t)(void*, HWND);
CBSInitialize_t CBSInitializeOriginal;
long __cdecl CBSInitializeHook(void *pThis, HWND hWnd)
{
// We need not subclass the other ReBarWindow32.
// At this point in time, it's exstyle is different.
if(GetWindowLong(hWnd, GWL_EXSTYLE) == 0)
{
HWND rb = FindWindowExW(hWnd, NULL, L"ReBarWindow32", NULL);
if(rb != NULL)
{
WindhawkUtils::SetWindowSubclassFromAnyThread(rb, RebarSubclassProc, NULL);
g_subclassedRebars.push_back(rb);
}
}

return CBSInitializeOriginal(pThis, hWnd);
}

LRESULT CALLBACK ListviewSubclassProc(_In_ HWND hWnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam,
_In_ DWORD_PTR dwRefData)
{
if(uMsg == WM_DESTROY)
{
g_subclassedListviews.erase(std::remove_if(
g_subclassedListviews.begin(), g_subclassedListviews.end(),
[hWnd](HWND &h)
{
return h == hWnd;
}));
return 0;
}
// This is less than surgical, but it appears to have no adverse effects.
if(uMsg == WM_SETREDRAW)
{
wParam = true;
}

return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}

typedef long (*__cdecl CLVHCreateControl_t)(void*, HWND, void*, void*);
CLVHCreateControl_t CLVHCreateControlOriginal;
long __cdecl CLVHCreateControlHook(void* pThis, HWND hWnd, void* a, void* b)
{
long ret = CLVHCreateControlOriginal(pThis, hWnd, a, b);
HWND listview = GetWindow(hWnd, GW_CHILD);
if(listview != NULL)
{
wchar_t name[32];
GetClassNameW(listview, name, 32);
if(lstrcmpW(name, L"SysListView32") == 0)
{
WindhawkUtils::SetWindowSubclassFromAnyThread(listview, ListviewSubclassProc, NULL);
g_subclassedListviews.push_back(listview);
}
}
return ret;
}

typedef long(*__cdecl CEFWndProc_t)(void*, HWND, unsigned int, WPARAM, LPARAM);
CEFWndProc_t CEFWndProcOriginal;
long __cdecl CEFWndProcHook(void* pThis, HWND hWnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam)
{
if(g_settingFixCWCBackground && uMsg == WM_ERASEBKGND)
{
HDC hdc = (HDC)wParam;
RECT rc;
GetClientRect(hWnd, &rc);
HBRUSH hbr = (HBRUSH)(COLOR_WINDOW + 1);
FillRect(hdc, &rc, hbr);
return 1;
}
return CEFWndProcOriginal(pThis, hWnd, uMsg, wParam, lParam);
}

BOOL Wh_ModInit()
{
Wh_Log(L"Explorerframe fixes for Win11 22H2+ Init");

HMODULE hExplorerFrame = LoadLibraryW(L"explorerframe.dll");

if (!hExplorerFrame)
{
Wh_Log(L"Failed to load explorerframe.dll");
return FALSE;
}

WindhawkUtils::SYMBOL_HOOK explorerframe_dll_hooks[] =
{
{ {
L"private: virtual __int64 __cdecl CExplorerFrame::v_WndProc(struct HWND__ *,unsigned int,unsigned __int64,__int64)"
},
(void**)&CEFWndProcOriginal,
(void*)CEFWndProcHook,
FALSE
},
{ {
L"protected: virtual long __cdecl CBandSite::_Initialize(struct HWND__ *)"
},
(void**)&CBSInitializeOriginal,
(void*)CBSInitializeHook,
FALSE
}
};

if (!WindhawkUtils::HookSymbols(hExplorerFrame, explorerframe_dll_hooks, 2))
{
Wh_Log(L"Failed install explorerframe hooks");
return FALSE;
}

HMODULE hShell32 = LoadLibraryW(L"shell32.dll");

if (!hShell32)
{
Wh_Log(L"Failed to load shell32.dll");
return FALSE;
}

WindhawkUtils::SYMBOL_HOOK shell32_dll_hooks[] =
{
{ {
L"public: virtual long __cdecl CListViewHost::CreateControl(struct HWND__ *,struct IListControlHost *,struct IViewSettings *)"
},
(void**)&CLVHCreateControlOriginal,
(void*)CLVHCreateControlHook,
FALSE
}

};

if (!WindhawkUtils::HookSymbols(hShell32, shell32_dll_hooks, 1))
{
Wh_Log(L"Failed to hook CListViewHost::CreateControl");
return FALSE;
}

g_settingDisplayMenuBar = Wh_GetIntSetting(L"DisplayMenuBar");
g_settingFixCWCBackground = Wh_GetIntSetting(L"ClassicBackgroundColor");

return TRUE;
}

void Wh_ModUninit()
{
Wh_Log(L"Explorerframe fixes for Win11 22H2+ Uninit");
Wh_Log(L"Removing subclasses from %i rebars.", g_subclassedRebars.size());
for(HWND& h : g_subclassedRebars)
{
WindhawkUtils::RemoveWindowSubclassFromAnyThread(h, RebarSubclassProc);
}
Wh_Log(L"Removing subclasses from %i listviews.", g_subclassedListviews.size());
for(HWND& h : g_subclassedListviews)
{
WindhawkUtils::RemoveWindowSubclassFromAnyThread(h, ListviewSubclassProc);
}
}

void Wh_ModSettingsChanged()
{
g_settingDisplayMenuBar = Wh_GetIntSetting(L"DisplayMenuBar");
g_settingFixCWCBackground = Wh_GetIntSetting(L"ClassicBackgroundColor");
}

0 comments on commit 441cbdf

Please sign in to comment.