Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ PublishScripts/
*.nupkg
# NuGet Symbol Packages
*.snupkg
# Temporary working files
.codex-tmp/
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
Expand Down
23 changes: 22 additions & 1 deletion ExplorerPatcher/StartMenu.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,28 @@
#include "StartMenu.h"

// One-shot target monitor for the next Start menu invocation. Set by OpenStartOnMonitor() right
// before the Start menu is opened on a specific monitor and atomically consumed by
// CStartExperienceManager_GetMonitorInformationHook() (TwinUIPatches.cpp), so it only ever
// applies to a single Start open and never lingers.
static volatile HMONITOR g_hStartMenuTargetMonitor = NULL;

void SetStartMenuTargetMonitor(HMONITOR monitor)
{
InterlockedExchangePointer((volatile PVOID*)&g_hStartMenuTargetMonitor, monitor);
}

HMONITOR ConsumeStartMenuTargetMonitor(void)
{
return (HMONITOR)InterlockedExchangePointer((volatile PVOID*)&g_hStartMenuTargetMonitor, NULL);
}

void OpenStartOnMonitor(HMONITOR monitor)
{
// Remember the monitor the Start menu is expected to open on, so that
// CStartExperienceManager::GetMonitorInformation() (hooked in TwinUIPatches.cpp) can use it
// instead of the potentially stale monitor reported by the launcher.
SetStartMenuTargetMonitor(monitor);

HRESULT hr = S_OK;
IUnknown* pImmersiveShell = NULL;
hr = CoCreateInstance(
Expand Down Expand Up @@ -854,4 +875,4 @@ DWORD GetStartMenuPosition(SHRegGetValueFromHKCUHKLM_t SHRegGetValueFromHKCUHKLM
}

return dwTaskbarAl;
}
}
6 changes: 6 additions & 0 deletions ExplorerPatcher/StartMenu.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ EXTERN_C NTSYSAPI PIMAGE_NT_HEADERS NTAPI RtlImageNtHeader(PVOID);
extern DWORD bMonitorOverride;
extern DWORD bOpenAtLogon;

// One-shot Start menu target monitor override (implemented in StartMenu.c). Set right before the
// Start menu is opened on a specific monitor; consumed (read + cleared) atomically by the
// CStartExperienceManager::GetMonitorInformation hook, so it applies to a single Start open only.
void SetStartMenuTargetMonitor(HMONITOR monitor);
HMONITOR ConsumeStartMenuTargetMonitor(void);

DEFINE_GUID(SID_IImmersiveMonitorService,
0x47094e3a,
0x0cf2, 0x430f, 0x80, 0x6f,
Expand Down
59 changes: 54 additions & 5 deletions ExplorerPatcher/TwinUIPatches.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1575,6 +1575,13 @@ BOOL Moment2PatchHardwareConfirmator(HMODULE hHardwareConfirmator, PBYTE pSearch
#pragma region "Fix broken Windows 10 start menu positioning issues caused by 44656322"

// Reverts 44656322's effects on the start menu
// One-shot target monitor override for the next Start menu invocation. Set by
// OpenStartOnMonitor() (StartMenu.c) right before the Start menu is opened on a specific
// monitor, and atomically consumed by the hook below, so it only ever applies to a single
// Start open and never lingers.
extern "C" void SetStartMenuTargetMonitor(HMONITOR monitor);
extern "C" HMONITOR ConsumeStartMenuTargetMonitor(void);

extern "C" HRESULT CStartExperienceManager_GetMonitorInformationHook(void* _this, CSingleViewShellExperience* experience, RECT* rcOutWorkArea, EDGEUI_TRAYSTUCKPLACE* outTrayStuckPlace, bool* bOutRtl, HMONITOR* hOutMonitor)
{
*rcOutWorkArea = {};
Expand All @@ -1589,18 +1596,60 @@ extern "C" HRESULT CStartExperienceManager_GetMonitorInformationHook(void* _this
ComPtr<IImmersiveLauncher> spImmersiveLauncher;
RETURN_IF_FAILED(spImmersiveShellServiceProvider->QueryService(SID_ImmersiveLauncher, IID_PPV_ARGS(&spImmersiveLauncher)));

// Official default path: the monitor currently connected to the launcher.
ComPtr<IImmersiveMonitor> spImmersiveMonitor;
HRESULT hr = spImmersiveLauncher->GetMonitor(&spImmersiveMonitor);
if (FAILED(hr))
return hr;

HMONITOR hMonitor = nullptr;
if (hOutMonitor)
hr = spImmersiveMonitor->GetHandle(&hMonitor);

HMONITOR hLauncherMonitor = nullptr;
hr = spImmersiveMonitor->GetHandle(&hLauncherMonitor);
if (FAILED(hr))
return hr;

// One-shot explicit target monitor, set by OpenStartOnMonitor() for taskbar button
// invocations; atomically consumed so it only ever applies to this Start open.
HMONITOR hRequestedMonitor = ConsumeStartMenuTargetMonitor();

// Fall back to the monitor under the cursor. This covers Win key invocations, which open
// the Start menu without going through OpenStartOnMonitor(), so the menu follows the mouse.
HMONITOR hCursorMonitor = nullptr;
POINT pt;
if (GetCursorPos(&pt))
{
hCursorMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
}

// Explicit target > cursor monitor > launcher monitor (official behavior).
HMONITOR hTargetMonitor = hRequestedMonitor ? hRequestedMonitor : (hCursorMonitor ? hCursorMonitor : hLauncherMonitor);

// Swap the monitor object only when the target actually differs from the launcher's, and
// only for this invocation. Any failure falls back to the launcher monitor (official path).
if (hTargetMonitor && hTargetMonitor != hLauncherMonitor)
{
ComPtr<IImmersiveMonitorManager> spImmersiveMonitorManager;
HRESULT hrGetFromHandle = E_FAIL;
if (SUCCEEDED(spImmersiveShellServiceProvider->QueryService(SID_IImmersiveMonitorService, IID_PPV_ARGS(&spImmersiveMonitorManager))))
{
ComPtr<IImmersiveMonitor> spOverrideMonitor;
hrGetFromHandle = spImmersiveMonitorManager->GetFromHandle(hTargetMonitor, &spOverrideMonitor);
if (SUCCEEDED(hrGetFromHandle) && spOverrideMonitor)
{
spImmersiveMonitor = spOverrideMonitor;
}
else
{
hTargetMonitor = hLauncherMonitor;
}
}
else
{
hTargetMonitor = hLauncherMonitor;
}
printf("[EP] Start monitor select: requested=%p cursor=%p launcher=%p final=%p GetFromHandle=0x%08lX\n",
(void*)hRequestedMonitor, (void*)hCursorMonitor, (void*)hLauncherMonitor, (void*)hTargetMonitor, (unsigned long)hrGetFromHandle);
}

ComPtr<IEdgeUiManager> spEdgeUiManager;
hr = IUnknown_QueryService(spImmersiveMonitor.Get(), SID_EdgeUi, IID_PPV_ARGS(&spEdgeUiManager));
if (FAILED(hr))
Expand All @@ -1625,7 +1674,7 @@ extern "C" HRESULT CStartExperienceManager_GetMonitorInformationHook(void* _this
*outTrayStuckPlace = trayStuckPlace;
*bOutRtl = Mirror_IsThreadRTL() != FALSE;
if (hOutMonitor)
*hOutMonitor = hMonitor;
*hOutMonitor = hTargetMonitor;

return S_OK;
}
Expand Down