Skip to content

Commit

Permalink
Taskbar classic context menu v1.0.1 (#1125)
Browse files Browse the repository at this point in the history
* Fixed the mod not working in some cases. Specifically, if the Windows TaskbarShiftRightClickCrash feature flag was enabled, right click acted as a left click instead of showing the classic context menu.
* The "Customize the old taskbar on Windows 11" option no longer needs to be enabled for the mod to work with the ExplorerPatcher taskbar.
  • Loading branch information
m417z authored Oct 22, 2024
1 parent c04dfbc commit 5edf7a5
Showing 1 changed file with 64 additions and 17 deletions.
81 changes: 64 additions & 17 deletions mods/taskbar-classic-menu.wh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// @id taskbar-classic-menu
// @name Taskbar classic context menu
// @description Show the classic context menu when right-clicking on taskbar items
// @version 1.0
// @version 1.0.1
// @author m417z
// @github https://github.com/m417z
// @twitter https://twitter.com/m417z
Expand Down Expand Up @@ -71,6 +71,26 @@ std::atomic<bool> g_explorerPatcherInitialized;

std::atomic<DWORD> g_CTaskListWnd__HandleContextMenuThreadId;
std::atomic<DWORD> g_TaskbarResources_OnTaskListButtonContextRequestedThreadId;
DWORD g_lastContextRequestedTickCount;

void* CTaskListWnd_vftable_CImpWndProc;
void* CTaskListWnd_vftable_ITaskListSite;

void* QueryViaVtable(void* object, void* vtable) {
void* ptr = object;
while (*(void**)ptr != vtable) {
ptr = (void**)ptr + 1;
}
return ptr;
}

void* QueryViaVtableBackwards(void* object, void* vtable) {
void* ptr = object;
while (*(void**)ptr != vtable) {
ptr = (void**)ptr - 1;
}
return ptr;
}

using CTaskListWnd__HandleContextMenu_t = void(WINAPI*)(void* pThis,
int param1,
Expand Down Expand Up @@ -124,24 +144,33 @@ HRESULT WINAPI CTaskListWnd_HandleClick_Hook(void* pThis,
Wh_Log(L">");

if (g_TaskbarResources_OnTaskListButtonContextRequestedThreadId ==
GetCurrentThreadId()) {
GetCurrentThreadId() ||
GetTickCount() - g_lastContextRequestedTickCount <= 200) {
g_lastContextRequestedTickCount = 0;
Wh_Log(L"Showing classic context menu");

POINT pt{};
GetCursorPos(&pt);

void* pThis2 = (void**)pThis + 1;
HWND hTaskListWnd = CTaskListWnd_GetWindow_Original(pThis2);
void* pThis_CImpWndProc =
QueryViaVtableBackwards(pThis, CTaskListWnd_vftable_CImpWndProc);
void* pThis_ITaskListSite = QueryViaVtable(
pThis_CImpWndProc, CTaskListWnd_vftable_ITaskListSite);

HWND hTaskListWnd =
CTaskListWnd_GetWindow_Original(pThis_ITaskListSite);

if (!taskItem && taskGroup) {
void* taskBtnGroup = CTaskListWnd__GetTBGroupFromGroup_Original(
(void**)pThis - 5, taskGroup, nullptr);
pThis_CImpWndProc, taskGroup, nullptr);
if (taskBtnGroup &&
CTaskBtnGroup_GetGroupType_Original(taskBtnGroup) == 1) {
taskItem = CTaskBtnGroup_GetTaskItem_Original(taskBtnGroup, 0);
}
}

CTaskListWnd_OnContextMenu_Original(pThis2, pt, hTaskListWnd, false,
taskGroup, taskItem);
CTaskListWnd_OnContextMenu_Original(
pThis_ITaskListSite, pt, hTaskListWnd, false, taskGroup, taskItem);
return S_OK;
}

Expand Down Expand Up @@ -187,6 +216,12 @@ TaskbarResources_OnTaskListButtonContextRequested_Hook(void* pThis,
void* param2) {
Wh_Log(L">");

// Normally, CTaskListWnd::HandleClick is called synchronously and this flag
// isn't necessary, but if the TaskbarShiftRightClickCrash feature flag is
// enabled, then it's dispatched asynchronously. Use this flag to be able to
// show the context menu in that case as well.
g_lastContextRequestedTickCount = GetTickCount();

g_TaskbarResources_OnTaskListButtonContextRequestedThreadId =
GetCurrentThreadId();

Expand Down Expand Up @@ -273,6 +308,10 @@ bool HookExplorerPatcherSymbols(HMODULE explorerPatcherModule) {
return true;
}

if (g_winVersion >= WinVersion::Win11) {
g_winVersion = WinVersion::Win10;
}

struct EXPLORER_PATCHER_HOOK {
PCSTR symbol;
void** pOriginalFunction;
Expand Down Expand Up @@ -418,6 +457,14 @@ bool HookWin11TaskbarSymbols() {
{LR"(public: virtual void __cdecl CTaskListWnd::OnContextMenu(struct tagPOINT,struct HWND__ *,bool,struct ITaskGroup *,struct ITaskItem *))"},
&CTaskListWnd_OnContextMenu_Original,
},
{
{LR"(const CTaskListWnd::`vftable'{for `CImpWndProc'})"},
&CTaskListWnd_vftable_CImpWndProc,
},
{
{LR"(const CTaskListWnd::`vftable'{for `ITaskListSite'})"},
&CTaskListWnd_vftable_ITaskListSite,
},
};

return HookSymbols(module, taskbarDllHooks, ARRAYSIZE(taskbarDllHooks));
Expand Down Expand Up @@ -478,15 +525,6 @@ BOOL Wh_ModInit() {
if (hasWin10Taskbar && !HookWin10TaskbarSymbols()) {
return FALSE;
}

HandleLoadedExplorerPatcher();

HMODULE kernelBaseModule = GetModuleHandle(L"kernelbase.dll");
FARPROC pKernelBaseLoadLibraryExW =
GetProcAddress(kernelBaseModule, "LoadLibraryExW");
Wh_SetFunctionHook((void*)pKernelBaseLoadLibraryExW,
(void*)LoadLibraryExW_Hook,
(void**)&LoadLibraryExW_Original);
} else if (g_winVersion >= WinVersion::Win11) {
if (!HookWin11TaskbarSymbols()) {
return FALSE;
Expand All @@ -501,6 +539,15 @@ BOOL Wh_ModInit() {
}
}

HandleLoadedExplorerPatcher();

HMODULE kernelBaseModule = GetModuleHandle(L"kernelbase.dll");
FARPROC pKernelBaseLoadLibraryExW =
GetProcAddress(kernelBaseModule, "LoadLibraryExW");
Wh_SetFunctionHook((void*)pKernelBaseLoadLibraryExW,
(void*)LoadLibraryExW_Hook,
(void**)&LoadLibraryExW_Original);

Wh_SetFunctionHook((void*)GetKeyState, (void*)GetKeyState_Hook,
(void**)&GetKeyState_Original);

Expand All @@ -514,7 +561,7 @@ void Wh_ModAfterInit() {

// Try again in case there's a race between the previous attempt and the
// LoadLibraryExW hook.
if (g_settings.oldTaskbarOnWin11 && !g_explorerPatcherInitialized) {
if (!g_explorerPatcherInitialized) {
HandleLoadedExplorerPatcher();
}
}
Expand Down

0 comments on commit 5edf7a5

Please sign in to comment.