From 201a7e5bed356b2d0bfa13a275e5f55617d05e28 Mon Sep 17 00:00:00 2001 From: Amrsatrio Date: Sun, 14 Sep 2025 20:00:15 +0700 Subject: [PATCH] Start10: Revise CStartExperienceManager::Hide() patching on ARM64. Now works on 27881+. --- ExplorerPatcher/TwinUIPatches.cpp | 7182 ++++++++++++++--------------- ExplorerPatcher/utility.h | 2073 ++++----- 2 files changed, 4633 insertions(+), 4622 deletions(-) diff --git a/ExplorerPatcher/TwinUIPatches.cpp b/ExplorerPatcher/TwinUIPatches.cpp index 2ec9219..8983ce4 100644 --- a/ExplorerPatcher/TwinUIPatches.cpp +++ b/ExplorerPatcher/TwinUIPatches.cpp @@ -1,3591 +1,3591 @@ -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include "ArchiveMenu.h" -#include "utility.h" -#include "hooking.h" -#include "symbols.h" -#include "NativeString.h" -#include "RefCountedObject.h" -#include "SimpleArray.h" - -// #define USE_REIMPLEMENTED_CLauncherTipContextMenu - -using namespace Microsoft::WRL; - - -#pragma region "Types and utilities" - -enum ContextMenuPaddingType -{ - CMPT_NONE = 0x0, - CMPT_TOP_PADDING = 0x1, - CMPT_BOTTOM_PADDING = 0x2, - CMPT_TOUCH_INPUT = 0x4, -}; - -DEFINE_ENUM_FLAG_OPERATORS(ContextMenuPaddingType); - -namespace DPIToPPIHelpers -{ -enum class ScaleType -{ - DPI, - PPI -}; - -enum class ScaleModifier -{ - None, - CorrectBadDPI -}; -} - -struct ContextMenuRenderingData -{ - CoTaskMemNativeString spszText; - DWORD uMenuFlags; - SHSTOCKICONID siid = SIID_MAX_ICONS; - HBITMAP hbmpItem; - HBITMAP hbmpChecked; - HBITMAP hbmpUnchecked; - ContextMenuPaddingType cmpt; - DPIToPPIHelpers::ScaleType scaletype; - UINT xDpi; - bool fUseDarkTheme; - bool fUseSystemPadding; - BOOL fForceAccelerators; - CSimplePointerArrayNewMem* prgParentArray; - -#ifdef _DEBUG -private: - void* operator new(size_t stAllocateBlock) = delete; - -public: - void* operator new(size_t stAllocateBlock, const std::nothrow_t&) - { - return HeapAlloc(GetProcessHeap(), 0, stAllocateBlock); - } - - void operator delete(void* pvMem) - { - operator delete(pvMem, std::nothrow); - } - - void operator delete(void* pvMem, const std::nothrow_t&) - { - if (pvMem) - { - HeapFree(GetProcessHeap(), 0, pvMem); - } - } -#endif -}; - -enum ImmersiveContextMenuOptions -{ - ICMO_NONE = 0x0, - ICMO_USEPPI = 0x1, - ICMO_OVERRIDECOMPATCHECK = 0x2, - ICMO_FORCEMOUSESTYLING = 0x4, - ICMO_USESYSTEMTHEME = 0x8, - ICMO_ICMBRUSHAPPLIED = 0x10, -}; - -DEFINE_ENUM_FLAG_OPERATORS(ImmersiveContextMenuOptions); - -DEFINE_GUID(SID_EdgeUi, 0x0D189B30, 0xF12B, 0x4B13, 0x94, 0xCF, 0x53, 0xCB, 0x0E, 0x0E, 0x24, 0x0D); // 0d189b30-f12b-4b13-94cf-53cb0e0e240d - -interface IImmersiveApplication; -interface IEdgeUiInvocationProvider; - -enum EDGEUI_COMPONENT -{ - EUICMP_UNKNOWN = -1, - EUICMP_SWITCHER = 0, - EUICMP_CHARMSBAR, - EUICMP_APPBAR, - EUICMP_TASKBAR, - EUICMP_TITLEBAR, - EUICMP_TABLETMODEVIEWMANAGER, - EUICMP_ACTIONCENTER, - EUICMP_TOTALCOUNT, -}; - -enum DISMISSED_UI_FLAGS -{ - DUF_NONE = 0x0, - DUF_FORCEOBSERVATIONOFF = 0x1, -}; - -enum EDGEUI_TRAYSTUCKPLACE -{ - EUITSP_UNKNOWN = -1, - EUITSP_LEFT = 0, - EUITSP_TOP, - EUITSP_RIGHT, - EUITSP_BOTTOM, -}; - -MIDL_INTERFACE("6e6c3c52-5a5e-4b4b-a0f8-7fe12621a93e") -IEdgeUiManager : IUnknown -{ - virtual HRESULT STDMETHODCALLTYPE GetTargetApplicationFromPoint(POINT, int, IImmersiveApplication**) = 0; - virtual HRESULT STDMETHODCALLTYPE DismissedUI(EDGEUI_COMPONENT, DISMISSED_UI_FLAGS) = 0; - virtual HRESULT STDMETHODCALLTYPE HandleEdgeGesturePrefChanged(HWND) = 0; - virtual HRESULT STDMETHODCALLTYPE DiscreteInvokeForApp(EDGEUI_COMPONENT, IImmersiveApplication*) = 0; - virtual HRESULT STDMETHODCALLTYPE BeginInputObservation(EDGEUI_COMPONENT) = 0; - virtual HRESULT STDMETHODCALLTYPE GetRegionForCornerOrEdge(EDGEUI_COMPONENT, HRGN*) = 0; - virtual HRESULT STDMETHODCALLTYPE NotifyTrayStuckPlaceChanged(EDGEUI_TRAYSTUCKPLACE) = 0; - virtual HRESULT STDMETHODCALLTYPE GetTrayStuckPlace(EDGEUI_TRAYSTUCKPLACE*) = 0; - virtual HRESULT STDMETHODCALLTYPE NotifyTraySearchBoxVisibilityChanged(BOOL) = 0; - virtual HRESULT STDMETHODCALLTYPE GetTraySearchBoxVisibility(BOOL*) = 0; - virtual HRESULT STDMETHODCALLTYPE NotifyPearlRectChanged(RECT) = 0; - virtual HRESULT STDMETHODCALLTYPE GetPearlRect(RECT*) = 0; - virtual HRESULT STDMETHODCALLTYPE UpdateEdgeWindowZorder() = 0; - virtual HRESULT STDMETHODCALLTYPE ShowStandardSystemOverlays(IImmersiveApplication*) = 0; - virtual HRESULT STDMETHODCALLTYPE OverrideInvocation(IEdgeUiInvocationProvider*) = 0; - virtual HRESULT STDMETHODCALLTYPE NotifyAutohideImmuneWorkAreaMayHaveChanged(RECT) = 0; - virtual HRESULT STDMETHODCALLTYPE GetAutohideImmuneWorkArea(RECT*) = 0; - virtual HRESULT STDMETHODCALLTYPE TaskbarRaised() = 0; - virtual HRESULT STDMETHODCALLTYPE GetTrayRect(RECT*) = 0; -}; - -enum IMMERSIVE_MONITOR_FILTER_FLAGS -{ - IMMERSIVE_MONITOR_FILTER_FLAGS_NONE = 0x0, - IMMERSIVE_MONITOR_FILTER_FLAGS_DISABLE_TRAY = 0x1, -}; - -DEFINE_ENUM_FLAG_OPERATORS(IMMERSIVE_MONITOR_FILTER_FLAGS); - -MIDL_INTERFACE("880b26f8-9197-43d0-8045-8702d0d72000") -IImmersiveMonitor : IUnknown -{ - virtual HRESULT STDMETHODCALLTYPE GetIdentity(DWORD*) = 0; - virtual HRESULT STDMETHODCALLTYPE ConnectObject(IUnknown*) = 0; - virtual HRESULT STDMETHODCALLTYPE GetHandle(HMONITOR*) = 0; - virtual HRESULT STDMETHODCALLTYPE IsConnected(BOOL*) = 0; - virtual HRESULT STDMETHODCALLTYPE IsPrimary(BOOL*) = 0; - virtual HRESULT STDMETHODCALLTYPE IsImmersiveDisplayDevice(BOOL*) = 0; - virtual HRESULT STDMETHODCALLTYPE GetDisplayRect(RECT*) = 0; - virtual HRESULT STDMETHODCALLTYPE GetOrientation(DWORD*) = 0; - virtual HRESULT STDMETHODCALLTYPE GetWorkArea(RECT*) = 0; - virtual HRESULT STDMETHODCALLTYPE IsEqual(IImmersiveMonitor*, BOOL*) = 0; - virtual HRESULT STDMETHODCALLTYPE IsImmersiveCapable(BOOL*) = 0; - virtual HRESULT STDMETHODCALLTYPE GetEffectiveDpi(UINT*, UINT*) = 0; - virtual HRESULT STDMETHODCALLTYPE GetFilterFlags(IMMERSIVE_MONITOR_FILTER_FLAGS*) = 0; -}; - -DEFINE_GUID(SID_IImmersiveMonitorService, 0x47094E3A, 0x0CF2, 0x430F, 0x80, 0x6F, 0xCF, 0x9E, 0x4F, 0x0F, 0x12, 0xDD); // 47094e3a-0cf2-430f-806f-cf9e4f0f12dd - -enum IMMERSIVE_MONITOR_MOVE_DIRECTION -{ - IMMD_PREVIOUS, - IMMD_NEXT, -}; - -interface IImmersiveMonitorFilter; - -MIDL_INTERFACE("4d4c1e64-e410-4faa-bafa-59ca069bfec2") -IImmersiveMonitorManager : IUnknown -{ - virtual HRESULT STDMETHODCALLTYPE GetCount(UINT*) = 0; - virtual HRESULT STDMETHODCALLTYPE GetConnectedCount(UINT*) = 0; - virtual HRESULT STDMETHODCALLTYPE GetAt(UINT, IImmersiveMonitor**) = 0; - virtual HRESULT STDMETHODCALLTYPE GetFromHandle(HMONITOR, IImmersiveMonitor**) = 0; - virtual HRESULT STDMETHODCALLTYPE GetFromIdentity(DWORD, IImmersiveMonitor**) = 0; - virtual HRESULT STDMETHODCALLTYPE GetImmersiveProxyMonitor(IImmersiveMonitor**) = 0; - virtual HRESULT STDMETHODCALLTYPE QueryService(HMONITOR, REFGUID, REFGUID, void**) = 0; - virtual HRESULT STDMETHODCALLTYPE QueryServiceByIdentity(DWORD, REFGUID, REFGUID, void**) = 0; - virtual HRESULT STDMETHODCALLTYPE QueryServiceFromWindow(HWND, REFGUID, REFGUID, void**) = 0; - virtual HRESULT STDMETHODCALLTYPE QueryServiceFromPoint(const POINT*, REFGUID, REFGUID, void**) = 0; - virtual HRESULT STDMETHODCALLTYPE GetNextImmersiveMonitor(IMMERSIVE_MONITOR_MOVE_DIRECTION, IImmersiveMonitor*, IImmersiveMonitor**) = 0; - virtual HRESULT STDMETHODCALLTYPE GetMonitorArray(IObjectArray**) = 0; - virtual HRESULT STDMETHODCALLTYPE SetFilter(IImmersiveMonitorFilter*) = 0; -}; - -DEFINE_GUID(SID_ImmersiveLauncher, 0x6F86E01C, 0xC649, 0x4D61, 0xBE, 0x23, 0xF1, 0x32, 0x2D, 0xDE, 0xCA, 0x9D); // 6f86e01c-c649-4d61-be23-f1322ddeca9d - -enum IMMERSIVELAUNCHERSHOWMETHOD -{ - ILSM_INVALID = 0, - ILSM_HSHELLTASKMAN = 1, - ILSM_IMMERSIVEBACKGROUND = 4, - ILSM_APPCLOSED = 6, - ILSM_STARTBUTTON = 11, - ILSM_RETAILDEMO_EDUCATIONAPP = 12, - ILSM_BACK = 13, - ILSM_SESSIONONUNLOCK = 14, -}; - -enum IMMERSIVELAUNCHERSHOWFLAGS -{ - ILSF_NONE = 0x0, - ILSF_IGNORE_SET_FOREGROUND_ERROR = 0x4, -}; - -DEFINE_ENUM_FLAG_OPERATORS(IMMERSIVELAUNCHERSHOWFLAGS); - -enum IMMERSIVELAUNCHERDISMISSMETHOD -{ - ILDM_INVALID = 0, - ILDM_HSHELLTASKMAN = 1, - ILDM_STARTCHARM = 2, - ILDM_BACKGESTURE = 3, - ILDM_ESCAPEKEY = 4, - ILDM_SHOWDESKTOP = 5, - ILDM_STARTTIP = 6, - ILDM_GENERIC_NONANIMATING = 7, - ILDM_SEARCH_OPENING = 8, - ILDM_DRAG = 9, -}; - -MIDL_INTERFACE("d8d60399-a0f1-f987-5551-321fd1b49864") -IImmersiveLauncher : IUnknown -{ - virtual HRESULT STDMETHODCALLTYPE ShowStartView(IMMERSIVELAUNCHERSHOWMETHOD, IMMERSIVELAUNCHERSHOWFLAGS) = 0; - virtual HRESULT STDMETHODCALLTYPE Dismiss(IMMERSIVELAUNCHERDISMISSMETHOD) = 0; - virtual HRESULT STDMETHODCALLTYPE DismissToLastDesktopApplication(IMMERSIVELAUNCHERDISMISSMETHOD) = 0; - virtual HRESULT STDMETHODCALLTYPE DismissSynchronouslyWithoutTransition() = 0; - virtual HRESULT STDMETHODCALLTYPE IsVisible(BOOL*) = 0; - virtual HRESULT STDMETHODCALLTYPE OnStartButtonPressed(IMMERSIVELAUNCHERSHOWMETHOD, IMMERSIVELAUNCHERDISMISSMETHOD) = 0; - virtual HRESULT STDMETHODCALLTYPE SetForeground() = 0; - virtual HRESULT STDMETHODCALLTYPE ConnectToMonitor(IImmersiveMonitor*) = 0; - virtual HRESULT STDMETHODCALLTYPE GetMonitor(IImmersiveMonitor**) = 0; - virtual HRESULT STDMETHODCALLTYPE OnFirstSignAnimationFinished() = 0; - virtual HRESULT STDMETHODCALLTYPE Prelaunch() = 0; -}; - -MIDL_INTERFACE("b8c1db5f-cbb3-48bc-afd9-ce6b880c79ed") -ILauncherTipContextMenu : IUnknown -{ - virtual HRESULT STDMETHODCALLTYPE ShowLauncherTipContextMenu(POINT*) = 0; - virtual HRESULT STDMETHODCALLTYPE GetMenuItemsAsync(RECT, IUnknown**) = 0; // New in 11 21H2, no GUID change -}; - -inline BOOL IsBiDiLocale(LCID locale) -{ - int info; - int charsRead = GetLocaleInfoW( - locale, - LOCALE_IREADINGLAYOUT | LOCALE_RETURN_NUMBER, - (LPWSTR)&info, - sizeof(info) / sizeof(WCHAR) - ); - return charsRead > 0 ? info == 1 : false; -} - -BOOL Mirror_IsThreadRTL() -{ - return IsBiDiLocale(GetThreadUILanguage()); -} - -enum ZBID : int; -enum ACCENT_STATE : int; - -class CSingleViewShellExperience; - -class SingleViewShellExperiencePersonality; - -class CSingleViewShellExperience -{ -public: - enum class Border - { - None = 0, - Left = 1, - Top = 2, - Right = 4, - Bottom = 8 - }; - - HRESULT SetPosition(const RECT* rect); - - Wrappers::HString _args; - Wrappers::HString _aumid; - Wrappers::HString _experience; - void* _viewWrapper; - ComPtr _propertySet; - int _viewState; - ABI::Windows::Foundation::Size _desiredSize; - BOOLEAN _fullScreen; - bool _isSessionIdle; - DWORD _pid; - ZBID _zbidDefault; - int _pendingViewAction; - int _pendingViewShowFlags; - int _navLevelOverrideHelper[2]; - wistd::unique_ptr m_personality; - // ... -}; - -class SingleViewShellExperiencePersonality -{ -public: - virtual ~SingleViewShellExperiencePersonality() = 0; - virtual bool IsPersonality(void*) = 0; - virtual HRESULT Initialize(IServiceProvider*) = 0; - virtual HRESULT EnableSessionIdleNotifications(IServiceProvider*) = 0; - virtual HRESULT OnViewWrapperChanged() = 0; - virtual HRESULT ShowView() = 0; - virtual HRESULT HideView() = 0; - virtual HRESULT IsViewVisible(bool*) = 0; - virtual HRESULT SetWindowBand(ZBID) = 0; - virtual HRESULT BringToForeground() = 0; - virtual HRESULT BringToFocus() = 0; - virtual HRESULT ShowBorder(CSingleViewShellExperience::Border, ACCENT_STATE, DWORD, const RECT*) = 0; - virtual HRESULT SetPosition(const RECT*) = 0; -}; - -HRESULT CSingleViewShellExperience::SetPosition(const RECT* rect) -{ - RETURN_HR(m_personality->SetPosition(rect)); -} - -namespace ExperienceManagerUtils -{ - void ScaleByDPI(const ABI::Windows::Foundation::Size* size, int dpi, int* outWidth, int* outHeight) - { - *outWidth = MulDiv((int)size->Width, dpi, 96); - *outHeight = MulDiv((int)size->Height, dpi, 96); - } -} - -// Before using this, please make sure that the vtable is in the real module not a stub. -#define REPLACE_VTABLE_ENTRY(vtable, index, name) \ - { \ - auto ppfn = (decltype(&name##Func))&vtable[index]; \ - if (*ppfn != name##Hook) \ - { \ - name##Func = *ppfn; \ - DWORD dwOldProtectLocal; \ - if (VirtualProtect(ppfn, sizeof(void*), PAGE_EXECUTE_READWRITE, &dwOldProtectLocal)) \ - { \ - *ppfn = name##Hook; \ - VirtualProtect(ppfn, sizeof(void*), dwOldProtectLocal, &dwOldProtectLocal); \ - } \ - } \ - } - -#pragma endregion - - -#pragma region "Stuff from dllmain" - -extern "C" -{ - -extern HMODULE hModule; -extern HWND archivehWnd; -extern DWORD bOldTaskbar; -extern DWORD bSkinMenus; -extern DWORD bClockFlyoutOnWinC; -extern DWORD bPropertiesInWinX; -extern DWORD bNoMenuAccelerator; -extern DWORD dwAltTabSettings; -extern DWORD dwSnapAssistSettings; -extern DWORD dwStartShowClassicMode; -extern HANDLE hWin11AltTabInitialized; - -typedef HRESULT(*ImmersiveContextMenuHelper_ApplyOwnerDrawToMenu_t)(HMENU hmenu, HWND hWnd, POINT* pptOrigin, unsigned int icmoFlags, void* srgRenderingData); -extern ImmersiveContextMenuHelper_ApplyOwnerDrawToMenu_t ImmersiveContextMenuHelper_ApplyOwnerDrawToMenuFunc; -typedef void(*ImmersiveContextMenuHelper_RemoveOwnerDrawFromMenu_t)(HMENU hmenu, HWND hwnd); -extern ImmersiveContextMenuHelper_RemoveOwnerDrawFromMenu_t ImmersiveContextMenuHelper_RemoveOwnerDrawFromMenuFunc; -typedef LRESULT(*CImmersiveContextMenuOwnerDrawHelper_s_ContextMenuWndProcFunc_t)(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); -extern CImmersiveContextMenuOwnerDrawHelper_s_ContextMenuWndProcFunc_t CImmersiveContextMenuOwnerDrawHelper_s_ContextMenuWndProcFunc; - -BOOL VnPatchIAT_NonInline(HMODULE hMod, const char* libName, const char* funcName, uintptr_t hookAddr); -POINT GetDefaultWinXPosition(BOOL bUseRcWork, BOOL* lpBottom, BOOL* lpRight, BOOL bAdjust, BOOL bToRight); -BOOL InvokeClockFlyout(); -void ReportSuccessfulAnimationPatching(); -BOOL IsCrashCounterEnabled(); - -} // extern "C" - -#pragma endregion - - -#pragma region "twinui.pcshell.dll hooks" - -#define LAUNCHERTIP_CLASS_NAME L"LauncherTipWnd" -#define WINX_ADJUST_X 5 -#define WINX_ADJUST_Y 5 - -class DECLSPEC_UUID("51d1268c-d0a5-47cc-a514-547f346f45e8") -CLauncherTipContextMenu; - -enum LTCMITEMFLAGS -{ - LTCMIF_DEFAULT = 0x0, - LTCMIF_RUNAS = 0x1, - LTCMIF_SWITCHTODESKTOP = 0x2, - LTCMIF_INVOKEARGS = 0x4, - LTCMIF_SHOWDESKTOPCOMMAND = 0x8, - LTCMIF_MOBILITYCENTER = 0x10, - LTCMIF_SEARCHCOMMAND = 0x20, - LTCMIF_PRIMARY_CMD = 0x40, - LTCMIF_SECONDARY_CMD = 0x80, - LTCMIF_POWERSHELLCOMMAND = 0x100, - LTCMIF_SUPPRESSONCLOUD = 0x200, - LTCMIF_ACTIVITIESCOMMAND = 0x400, - LTCMIF_TERMINALCOMMAND = 0x800, // Cobalt -}; - -struct LauncherTipMenuCommand -{ - LauncherTipMenuCommand(); - - bool fSeparator; - CoTaskMemNativeString spszCommandName; - CoTaskMemNativeString spszCommandPath; - CoTaskMemNativeString spszCommandTargetArguments; - CoTaskMemNativeString spszVerb; - DWORD ltcmif; -}; - -struct LauncherTipShutdownMenuCommand -{ - DWORD choice; - CoTaskMemNativeString spszCommandName; -}; - -static HRESULT(*winrt_Windows_Internal_Shell_implementation_MeetAndChatManager_OnMessageFunc)(void* _this, UINT uMsg, WPARAM wParam, LPARAM lParam) = nullptr; -static HRESULT(*CLauncherTipContextMenu_ShowLauncherTipContextMenuFunc)(ILauncherTipContextMenu* _this, POINT* pptLocation) = nullptr; -static void(*CLauncherTipContextMenu_ExecuteCommandFunc)(void* _this, ComPtr> spCommand) = nullptr; -static void(*CLauncherTipContextMenu_ExecuteShutdownCommandFunc)(void* _this, ComPtr> spCommand, const RECT* prcDockTo) = nullptr; - -HWND hWinXWnd; -HANDLE hIsWinXShown; -HANDLE hWinXThread; - -HRESULT CLauncherTipContextMenu_ShowLauncherTipContextMenuHook(ILauncherTipContextMenu* _this, POINT* pt); - -HRESULT (STDMETHODCALLTYPE *CLauncherTipContextMenu_CreateInstance_IClassFactory_Func)( - IClassFactory* This, IUnknown* pUnkOuter, REFIID riid, void** ppvObject); -HRESULT STDMETHODCALLTYPE CLauncherTipContextMenu_CreateInstance_IClassFactory_Hook( - IClassFactory* This, IUnknown* pUnkOuter, REFIID riid, void** ppvObject) -{ -#if defined(USE_REIMPLEMENTED_CLauncherTipContextMenu) - *ppvObject = nullptr; - ComPtr spLTCM; - HRESULT hr = MakeAndInitialize(&spLTCM); - if (SUCCEEDED(hr)) - { - hr = spLTCM.CopyTo(riid, ppvObject); - } - return hr; -#else - HRESULT hr = CLauncherTipContextMenu_CreateInstance_IClassFactory_Func(This, pUnkOuter, riid, ppvObject); - if (SUCCEEDED(hr)) - { - ILauncherTipContextMenu* pLTCM = nullptr; - if (SUCCEEDED(((IUnknown*)*ppvObject)->QueryInterface(IID_PPV_ARGS(&pLTCM)))) // Don't influence hr: if this fails, black screen - { - void** vtable = *(void***)pLTCM; - REPLACE_VTABLE_ENTRY(vtable, 3, CLauncherTipContextMenu_ShowLauncherTipContextMenu); - pLTCM->Release(); - } - } - return hr; -#endif -} - -extern "C" LRESULT CALLBACK CLauncherTipContextMenu_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - LRESULT result; - - if (hWnd == archivehWnd && !ArchiveMenuWndProc( - hWnd, uMsg, wParam, lParam, - ImmersiveContextMenuHelper_ApplyOwnerDrawToMenuFunc, - ImmersiveContextMenuHelper_RemoveOwnerDrawFromMenuFunc - )) - { - return 0; - } - - if (uMsg == WM_NCCREATE) - { - CREATESTRUCT* pCs = (CREATESTRUCT*)lParam; - if (pCs->lpCreateParams) - { - *((HWND*)((char*)pCs->lpCreateParams + 0x78)) = hWnd; - SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pCs->lpCreateParams); - result = DefWindowProcW(hWnd, uMsg, wParam, lParam); - } - else - { - result = DefWindowProcW(hWnd, uMsg, wParam, lParam); - //result = 0; - } - } - else - { - void* _this = (void*)GetWindowLongPtrW(hWnd, GWLP_USERDATA); - if ((uMsg == WM_DRAWITEM || uMsg == WM_MEASUREITEM) && - CImmersiveContextMenuOwnerDrawHelper_s_ContextMenuWndProcFunc && - CImmersiveContextMenuOwnerDrawHelper_s_ContextMenuWndProcFunc(hWnd, uMsg, wParam, lParam)) - { - result = 0; - } - else - { - result = DefWindowProcW(hWnd, uMsg, wParam, lParam); - } - if (_this) - { - if (uMsg == WM_NCDESTROY) - { - SetWindowLongPtrW(hWnd, GWLP_USERDATA, 0); - *((HWND*)((char*)_this + 0x78)) = nullptr; - } - } - } - return result; -} - -struct ShowLauncherTipContextMenuParameters -{ - ILauncherTipContextMenu* _this; - POINT point; - ComPtr spOperation; - bool bShouldCenterWinXHorizontally; - - ShowLauncherTipContextMenuParameters(ILauncherTipContextMenu* _this, POINT point, IUnknown* pOperation, bool bShouldCenterWinXHorizontally) - : _this(_this) - , point(point) - , spOperation(pOperation) - , bShouldCenterWinXHorizontally(bShouldCenterWinXHorizontally) - { - } -}; - -DWORD ShowLauncherTipContextMenu(LPVOID lpParams) -{ - ShowLauncherTipContextMenuParameters* params = (ShowLauncherTipContextMenuParameters*)lpParams; - - // Adjust this based on info from: CLauncherTipContextMenu::SetSite - // and CLauncherTipContextMenu::CLauncherTipContextMenu - // 22000.739: 0xe8 - // 22000.778: 0xf0 - // What has happened, between .739 and .778 is that the launcher tip - // context menu object now implements a new interface, ILauncherTipContextMenuMigration; - // thus, members have shifted 8 bytes (one 64-bit value which will hold the - // address of the vtable for this intf at runtime) to the right; - // all this intf seems to do, as of now, is to remove some "obsolete" links - // from the menu (check out "CLauncherTipContextMenu::RunMigrationTasks"); it - // seems you can disable this by setting a DWORD "WinXMigrationLevel" = 1 in - // HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced - int offset_in_class = 0; - if (global_rovi.dwBuildNumber >= 22621 || (global_rovi.dwBuildNumber == 22000 && global_ubr >= 778)) - { - offset_in_class = 8; - } - - char* pClassBase = (char*)params->_this - 0x58; - - struct - { - // ComPtr _spScheduler; - // ComPtr _spWindowMessageService; - // ComPtr _spLauncher; - // ComPtr _spSystemMode; - // ComPtr _spMonitorManager; - CCoSimpleArray>> _rgCommands; - CCoSimpleArray>> _rgShutdownCommands; - RTL_CRITICAL_SECTION _csEnumeration; - RTL_CRITICAL_SECTION _csContextMenuDisplay; - bool _fAreCommandsPopulated; - bool _fCommandPopulationInProgress; - bool _fTasksCancelled; - HMENU _hMenu; - HMENU _hMenuShutdown; - bool _fIsRTL; - bool _fReplacePrimaryCommandsWithSecondary; - }& fields = *(std::remove_reference_t*)(pClassBase + offset_in_class + 0xA8); // Begin at _rgCommands - - static ATOM windowRegistrationAtom = 0; - if (windowRegistrationAtom == 0) - { - WNDCLASS wc = { - .style = CS_DBLCLKS, - .lpfnWndProc = CLauncherTipContextMenu_WndProc, - .hInstance = GetModuleHandleW(nullptr), - .hCursor = LoadCursorW(nullptr, IDC_ARROW), - .hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH), - .lpszClassName = LAUNCHERTIP_CLASS_NAME - }; - ATOM atom = RegisterClassW(&wc); - if (atom) - windowRegistrationAtom = atom; - } - - hWinXWnd = CreateWindowInBand( - 0, - MAKEINTATOM(windowRegistrationAtom), - nullptr, - WS_POPUP, - 0, 0, 0, 0, - nullptr, nullptr, - GetModuleHandle(nullptr), - pClassBase, - 7 // ZBID_IMMERSIVE_EDGY - ); - // DO NOT USE ShowWindow here; it breaks the window order - // and renders the desktop toggle unusable; but leave - // SetForegroundWindow as is so that the menu gets dismissed - // when the user clicks outside it - // - // ShowWindow(hWinXWnd, SW_SHOW); - SetForegroundWindow(hWinXWnd); - - while (!fields._fAreCommandsPopulated) - { - Sleep(1); - } - auto finalize = wil::scope_exit([&]() -> void - { - SendMessageW(hWinXWnd, WM_CLOSE, 0, 0); - hIsWinXShown = nullptr; - delete params; - }); - if (!fields._rgCommands.GetSize()) - { - return 0; - } - - // Check if Windows Terminal is installed - bool fHasTerminal = false; - { - ComPtr spLocalAppDataItem; - HRESULT hr = SHGetKnownFolderItem(FOLDERID_LocalAppData, KF_FLAG_DEFAULT, nullptr, IID_PPV_ARGS(&spLocalAppDataItem)); - if (SUCCEEDED(hr)) - { - ComPtr spTerminalFolderItem; - if (SUCCEEDED(SHCreateItemFromRelativeName(spLocalAppDataItem.Get(), L"Microsoft\\WindowsApps\\wt.exe", nullptr, IID_PPV_ARGS(&spTerminalFolderItem)))) - { - fHasTerminal = true; - } - } - } - - // Do not use the _hMenu built by CLauncherTipContextMenu, it contains *both* PowerShell and Terminal entries. - // When Windows Terminal gets installed/uninstalled, the menu entries should be shown/hidden accordingly without - // restarting Explorer. Win32 does not support hiding menu entries. If we DeleteMenuW the Terminal entries in the - // provided menu due to Terminal not being installed, it will not reappear after Terminal is reinstalled. - // - // We build the menu ourselves to avoid those issues. - // - // Implementation based on: - // - CLauncherTipContextMenu::_EnumerateAndBuildMenu() - // - CLauncherTipContextMenu::_EnumerateAndBuildShutdownMenu() - - wil::unique_hmenu hMenu(CreatePopupMenu()); - wil::unique_hmenu hMenuShutdown; - HRESULT hr = ResultFromWin32Bool(hMenu.is_valid()); - if (SUCCEEDED(hr)) - { - size_t iPlusOne = fields._rgCommands.GetSize(); - if (iPlusOne) - { - for (; iPlusOne; --iPlusOne) - { - size_t iContextMenuCommand = iPlusOne - 1; - ComPtr>& spCommand = fields._rgCommands[iContextMenuCommand]; - - if ((spCommand->ltcmif & LTCMIF_POWERSHELLCOMMAND) != 0 && fHasTerminal - || (spCommand->ltcmif & LTCMIF_TERMINALCOMMAND) != 0 && !fHasTerminal) - { - // Skip if this is PowerShell and Windows Terminal is installed - // or if this is Windows Terminal and Windows Terminal is not installed - continue; - } - - AppendMenuW(hMenu.get(), spCommand->fSeparator ? MF_SEPARATOR : 0, iContextMenuCommand + 1, spCommand->spszCommandName.Get()); - if (iContextMenuCommand == 1) - { - hMenuShutdown.reset(CreatePopupMenu()); - hr = ResultFromWin32Bool(hMenuShutdown != nullptr); - if (SUCCEEDED(hr)) - { - CoTaskMemNativeString spShutdownName; - hr = spShutdownName.Initialize(GetModuleHandleW(L"twinui.pcshell.dll"), 10930); // Sh&ut down or sign out - if (SUCCEEDED(hr)) - { - AppendMenuW(hMenu.get(), MF_POPUP, (DWORD)(UINT_PTR)hMenuShutdown.get(), spShutdownName.Get()); - } - - UINT_PTR uIDNewItem = 4000; - for (size_t i = 0; i < fields._rgShutdownCommands.GetSize(); ++i) - { - ComPtr>& spShutdownCommand = fields._rgShutdownCommands[i]; - AppendMenuW(hMenuShutdown.get(), MF_STRING, uIDNewItem++, spShutdownCommand->spszCommandName.Get()); - } - } - } - } - /*if (ShouldPowershellReplaceCmd()) - { - LauncherTipContextMenuTelemetry::LauncherTipContextMenuDefaultConsole(!_fReplacePrimaryCommandsWithSecondary); - }*/ - } - } - - TCHAR buffer[260]; - LoadStringW(GetModuleHandleW(L"ExplorerFrame.dll"), 50222, buffer + (bNoMenuAccelerator ? 0 : 1), 260); - if (!bNoMenuAccelerator) - { - buffer[0] = L'&'; - } - wchar_t* p = wcschr(buffer, L'('); - if (p) - { - p--; - if (*p == L' ') - { - *p = 0; - } - else - { - p++; - *p = 0; - } - } - - BOOL bCreatedMenu = FALSE; - MENUITEMINFOW menuInfo; - ZeroMemory(&menuInfo, sizeof(MENUITEMINFOW)); - menuInfo.cbSize = sizeof(MENUITEMINFOW); - menuInfo.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA; - menuInfo.wID = 3999; - menuInfo.dwItemData = 0; - menuInfo.fType = MFT_STRING; - menuInfo.dwTypeData = buffer; - menuInfo.cch = (UINT)wcslen(buffer); - if (bPropertiesInWinX) - { - InsertMenuItemW( - hMenu.get(), - GetMenuItemCount(hMenu.get()) - 1, - TRUE, - &menuInfo - ); - bCreatedMenu = TRUE; - } - - CSimplePointerArrayNewMem srgRenderingData; - if (bSkinMenus && ImmersiveContextMenuHelper_ApplyOwnerDrawToMenuFunc) - { - ImmersiveContextMenuHelper_ApplyOwnerDrawToMenuFunc( - hMenu.get(), - hWinXWnd, - ¶ms->point, - ICMO_FORCEMOUSESTYLING | ICMO_USESYSTEMTHEME, - &srgRenderingData - ); - } - - BOOL res = TrackPopupMenu( - hMenu.get(), - TPM_RETURNCMD | TPM_RIGHTBUTTON | (params->bShouldCenterWinXHorizontally ? TPM_CENTERALIGN : 0), - params->point.x, - params->point.y, - 0, - hWinXWnd, - nullptr - ); - - if (bSkinMenus && ImmersiveContextMenuHelper_RemoveOwnerDrawFromMenuFunc) - { - ImmersiveContextMenuHelper_RemoveOwnerDrawFromMenuFunc(hMenu.get(), hWinXWnd); - } - - if (bCreatedMenu) - { - RemoveMenu(hMenu.get(), 3999, MF_BYCOMMAND); - } - - if (res > 0) - { - if (bCreatedMenu && res == 3999) - { - LaunchPropertiesGUI(hModule); - } - else if (res >= 4000) - { - if (CLauncherTipContextMenu_ExecuteShutdownCommandFunc) - { - RECT rcAnchor; - rcAnchor.left = params->point.x; - rcAnchor.top = params->point.y - 1; - rcAnchor.right = rcAnchor.left + 1; - rcAnchor.bottom = rcAnchor.top + 1; - CLauncherTipContextMenu_ExecuteShutdownCommandFunc(pClassBase, fields._rgShutdownCommands[res - 4000], &rcAnchor); - } - } - else - { - if (CLauncherTipContextMenu_ExecuteCommandFunc) - { - CLauncherTipContextMenu_ExecuteCommandFunc(pClassBase, fields._rgCommands[res - 1]); - } - } - } - - return 0; -} - -HRESULT CLauncherTipContextMenu_ShowLauncherTipContextMenuHook(ILauncherTipContextMenu* _this, POINT* pt) -{ - HRESULT hr = S_OK; - - if (hWinXThread) - { - WaitForSingleObject(hWinXThread, INFINITE); - CloseHandle(hWinXThread); - hWinXThread = nullptr; - } - - if (!hIsWinXShown) - { - bool bShouldCenterWinXHorizontally = false; - POINT point; - if (pt) - { - point = *pt; - BOOL bBottom, bRight; - POINT dPt = GetDefaultWinXPosition(FALSE, &bBottom, &bRight, FALSE, FALSE); - POINT posCursor; - GetCursorPos(&posCursor); - RECT rcHitZone; - rcHitZone.left = pt->x - 5; - rcHitZone.right = pt->x + 5; - rcHitZone.top = pt->y - 5; - rcHitZone.bottom = pt->y + 5; - //printf("%d %d = %d %d %d %d\n", posCursor.x, posCursor.y, rcHitZone.left, rcHitZone.right, rcHitZone.top, rcHitZone.bottom); - if (bBottom && IsThemeActive() && PtInRect(&rcHitZone, posCursor) && GetClassWord(WindowFromPoint(point), GCW_ATOM) == RegisterWindowMessageW(L"Start")) - { - HMONITOR hMonitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY); - MONITORINFO mi; - mi.cbSize = sizeof(MONITORINFO); - GetMonitorInfoW(hMonitor, &mi); - HWND hWndUnder = WindowFromPoint(*pt); - TCHAR wszClassName[100]; - ZeroMemory(wszClassName, 100); - GetClassNameW(hWndUnder, wszClassName, 100); - if (!wcscmp(wszClassName, L"Shell_TrayWnd") || !wcscmp(wszClassName, L"Shell_SecondaryTrayWnd")) - { - hWndUnder = FindWindowExW(hWndUnder, nullptr, L"Start", nullptr); - } - RECT rcUnder; - GetWindowRect(hWndUnder, &rcUnder); - if (mi.rcMonitor.left != rcUnder.left) - { - bShouldCenterWinXHorizontally = true; - point.x = rcUnder.left + (rcUnder.right - rcUnder.left) / 2; - point.y = rcUnder.top; - } - else - { - UINT dpiX, dpiY; - GetDpiForMonitor(hMonitor, MDT_DEFAULT, &dpiX, &dpiY); - double dx = dpiX / 96.0, dy = dpiY / 96.0; - BOOL xo = FALSE, yo = FALSE; - if ((int)(point.x - WINX_ADJUST_X * dx) < mi.rcMonitor.left) - { - xo = TRUE; - } - if ((int)(point.y + WINX_ADJUST_Y * dy) > mi.rcMonitor.bottom) - { - yo = TRUE; - } - POINT ptCursor; - GetCursorPos(&ptCursor); - if (xo) - { - ptCursor.x += (int)((WINX_ADJUST_X * 2) * dx); - } - else - { - point.x -= (int)(WINX_ADJUST_X * dx); - } - if (yo) - { - ptCursor.y -= (int)((WINX_ADJUST_Y * 2) * dy); - } - else - { - point.y += (int)(WINX_ADJUST_Y * dy); - } - SetCursorPos(ptCursor.x, ptCursor.y); - } - } - } - else - { - point = GetDefaultWinXPosition(FALSE, nullptr, nullptr, TRUE, FALSE); - } - - RECT rc = {}; - ComPtr spOperation; - hr = _this->GetMenuItemsAsync(rc, &spOperation); - if (SUCCEEDED(hr)) - { - ShowLauncherTipContextMenuParameters* params = new(std::nothrow) ShowLauncherTipContextMenuParameters(_this, point, spOperation.Get(), bShouldCenterWinXHorizontally); - hIsWinXShown = CreateThread(nullptr, 0, ShowLauncherTipContextMenu, params, 0, nullptr); - hWinXThread = hIsWinXShown; - } - } - - if (SUCCEEDED(hr) && CLauncherTipContextMenu_ShowLauncherTipContextMenuFunc) - { - hr = CLauncherTipContextMenu_ShowLauncherTipContextMenuFunc(_this, pt); - } - - return hr; -} - -extern "C" void ToggleLauncherTipContextMenu() -{ - if (hIsWinXShown) - { - SendMessageW(hWinXWnd, WM_CLOSE, 0, 0); - return; - } - - HWND hWnd = FindWindowExW(nullptr, nullptr, L"Shell_TrayWnd", nullptr); - if (!hWnd) - return; - - hWnd = FindWindowExW(hWnd, nullptr, L"Start", nullptr); - if (!hWnd) - return; - - POINT pt = GetDefaultWinXPosition(FALSE, nullptr, nullptr, TRUE, FALSE); - // Finally implemented a variation of - // https://github.com/valinet/ExplorerPatcher/issues/3 - // inspired by how the real Start button activates this menu - // (CPearl::_GetLauncherTipContextMenu) - // This also works when auto hide taskbar is on (#63) - ComPtr pImmersiveShell; - if (SUCCEEDED(CoCreateInstance(CLSID_ImmersiveShell, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pImmersiveShell)))) - { - ComPtr pMonitorService; - if (SUCCEEDED(pImmersiveShell->QueryService(SID_IImmersiveMonitorService, IID_PPV_ARGS(&pMonitorService)))) - { - ComPtr pMenu; - if (SUCCEEDED(pMonitorService->QueryServiceFromWindow(hWnd, __uuidof(ILauncherTipContextMenu), IID_PPV_ARGS(&pMenu)))) - { - pMenu->ShowLauncherTipContextMenu(&pt); - } - } - } -} - -LSTATUS twinuipcshell_RegGetValueW( - HKEY hkey, - LPCWSTR lpSubKey, - LPCWSTR lpValue, - DWORD dwFlags, - LPDWORD pdwType, - PVOID pvData, - LPDWORD pcbData -) -{ - LSTATUS lRes = RegGetValueW(hkey, lpSubKey, lpValue, dwFlags, pdwType, pvData, pcbData); - - if (!lstrcmpW(lpValue, L"AltTabSettings")) - { - if (lRes == ERROR_SUCCESS && *(DWORD*)pvData) - { - if (*(DWORD*)pvData == 3) - { - *(DWORD*)pvData = 0; - } - else - { - *(DWORD*)pvData = 1; - } - } - - if (!bOldTaskbar && hWin11AltTabInitialized) - { - SetEvent(hWin11AltTabInitialized); - CloseHandle(hWin11AltTabInitialized); - hWin11AltTabInitialized = nullptr; - } - - lRes = ERROR_SUCCESS; - } - - return lRes; -} - -HRESULT winrt_Windows_Internal_Shell_implementation_MeetAndChatManager_OnMessageHook(void* _this, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - if (!bClockFlyoutOnWinC) - { - if (winrt_Windows_Internal_Shell_implementation_MeetAndChatManager_OnMessageFunc) - { - return winrt_Windows_Internal_Shell_implementation_MeetAndChatManager_OnMessageFunc(_this, uMsg, wParam, lParam); - } - return S_OK; - } - if (uMsg == 0x2C2 && wParam == 107) - { - InvokeClockFlyout(); - } - return S_OK; -} - -#pragma endregion - - -#pragma region "Enable old Alt+Tab" - -INT64(*twinui_pcshell_IsUndockedAssetAvailableFunc)(INT a1, INT64 a2, INT64 a3, const char* a4); -INT64 twinui_pcshell_IsUndockedAssetAvailableHook(INT a1, INT64 a2, INT64 a3, const char* a4) -{ - // if IsAltTab and AltTabSettings == Windows 10 or sws (Precision Touchpad gesture) - if (a1 == 1 && (dwAltTabSettings == 3 || dwAltTabSettings == 2)) - { - return 0; - } - // if IsSnapAssist and SnapAssistSettings == Windows 10 - else if (a1 == 4 && dwSnapAssistSettings == 3 && !IsWindows11Version22H2OrHigher()) - { - return 0; - } - // else, show Windows 11 style basically - else - { - if (twinui_pcshell_IsUndockedAssetAvailableFunc) - return twinui_pcshell_IsUndockedAssetAvailableFunc(a1, a2, a3, a4); - return 1; - } -} - -INT64(*twinui_pcshell_CMultitaskingViewManager__CreateDCompMTVHostFunc)(INT64 _this, unsigned int a2, INT64 a3, INT64 a4, INT64* a5); -INT64(*twinui_pcshell_CMultitaskingViewManager__CreateXamlMTVHostFunc)(INT64 _this, unsigned int a2, INT64 a3, INT64 a4, INT64* a5); -INT64 twinui_pcshell_CMultitaskingViewManager__CreateXamlMTVHostHook(INT64 _this, unsigned int a2, INT64 a3, INT64 a4, INT64* a5) -{ - if (!twinui_pcshell_IsUndockedAssetAvailableHook(a2, 0, 0, nullptr)) - return twinui_pcshell_CMultitaskingViewManager__CreateDCompMTVHostFunc(_this, a2, a3, a4, a5); - return twinui_pcshell_CMultitaskingViewManager__CreateXamlMTVHostFunc(_this, a2, a3, a4, a5); -} - -#pragma endregion - - -#pragma region "Fixes related to the removal of STTest feature flag (22621.2134+)" - -HRESULT(*twinui_pcshell_PenMenuSystemTrayManager__GetDynamicSystemTrayHeightForMonitorFunc)(IInspectable* _this, HMONITOR hMonitor, float* outHeight); -HRESULT twinui_pcshell_PenMenuSystemTrayManager__GetDynamicSystemTrayHeightForMonitorHook(IInspectable* _this, HMONITOR hMonitor, float* outHeight) -{ - if (bOldTaskbar) - { - MONITORINFO mi; - mi.cbSize = sizeof(MONITORINFO); - GetMonitorInfoW(hMonitor, &mi); - *outHeight = (float)(mi.rcMonitor.bottom - mi.rcWork.bottom); - return S_OK; - } - return twinui_pcshell_PenMenuSystemTrayManager__GetDynamicSystemTrayHeightForMonitorFunc(_this, hMonitor, outHeight); -} - -static struct -{ - int coroInstance_rcOut; // 22621.1992: 0x10 - int coroInstance_pHardwareConfirmatorHost; // 22621.1992: 0xFD - int hardwareConfirmatorHost_bIsInLockScreen; // 22621.1992: 0xEC -} g_Moment2PatchOffsets; - -#if defined(_M_X64) -inline PBYTE GetTargetOfJzBeforeMe(PBYTE anchor) -{ - // Check big jz - if (*(anchor - 6) == 0x0F && *(anchor - 5) == 0x84) - return anchor + *(int*)(anchor - 4); - // Check small jz - if (*(anchor - 2) == 0x74) - return anchor + *(char*)(anchor - 1); - return nullptr; -} -#endif - -// CActionCenterExperienceManager::GetViewPosition() patcher -BOOL Moment2PatchActionCenter(LPMODULEINFO mi) -{ -#if defined(_M_X64) - // Step 1: - // Scan within the DLL for `*a2 = mi.rcMonitor`. - // ```0F 10 45 ?? F3 0F 7F ?? 80 ?? ?? ?? 00 00 00 // movups - movdqu - cmp``` - // 22621.1992: 7E2F0 - // 22621.2283: 140D5 - PBYTE rcMonitorAssignment = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x0F\x10\x45\x00\xF3\x0F\x7F\x00\x80\x00\x00\x00\x00\x00\x00", "xxx?xxx?x???xxx"); - if (!rcMonitorAssignment) return FALSE; - printf("[AC] rcMonitorAssignment = %llX\n", rcMonitorAssignment - (PBYTE)mi->lpBaseOfDll); - - // 22621.1992 has a different compiled code structure than 22621.2283 therefore we have to use a different approach: - // Short circuiting the `if (26008830 is enabled)`. - // 22621.1992: 7E313 - if (!IsWindows11Version22H2Build2134OrHigher()) // We're on 1413-1992 - { -#if USE_MOMENT_3_FIXES_ON_MOMENT_2 - PBYTE featureCheckJz = rcMonitorAssignment + 35; - if (*featureCheckJz != 0x0F && *(featureCheckJz + 1) != 0x84) return FALSE; - - DWORD dwOldProtect = 0; - PBYTE jzAddr = featureCheckJz + 6 + *(DWORD*)(featureCheckJz + 2); - if (!VirtualProtect(featureCheckJz, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect)) return FALSE; - featureCheckJz[0] = 0xE9; - *(DWORD*)(featureCheckJz + 1) = (DWORD)(jzAddr - featureCheckJz - 5); - VirtualProtect(featureCheckJz, 5, dwOldProtect, &dwOldProtect); - goto done; -#else - return FALSE; -#endif - } - - // Step 2: - // Copy `*a2 = mi.rcMonitor` into right after the first jz starting from step 1. - // Find within couple bytes from step 1: - // ```48 8D // lea``` - // Then offset the first ?? so that it points to mi.rcWork which is 16 bytes after mi.rcMonitor. - // 22621.2283: 140E6 - PBYTE blockBegin = (PBYTE)FindPattern(rcMonitorAssignment + 1, 32, "\x48\x8D", "xx"); - if (!blockBegin) return FALSE; - printf("[AC] blockBegin = %llX\n", blockBegin - (PBYTE)mi->lpBaseOfDll); - - // Step 3: - // Exit the block by writing a long jmp into the address referenced by the jz right before step 3, into right after - // the 8 bytes `rcMonitor = mi.rcWork` we've written. - PBYTE blockEnd = GetTargetOfJzBeforeMe(blockBegin); - if (!blockEnd) return FALSE; - printf("[AC] blockEnd = %llX\n", blockEnd - (PBYTE)mi->lpBaseOfDll); - - // Execution - DWORD dwOldProtect = 0; - if (!VirtualProtect(blockBegin, 8 /**a2 = mi.rcWork*/ + 5 /*jmp*/, PAGE_EXECUTE_READWRITE, &dwOldProtect)) return FALSE; - - // Step 2 - memcpy(blockBegin, rcMonitorAssignment, 8); - blockBegin[3] += offsetof(MONITORINFO, rcWork) - offsetof(MONITORINFO, rcMonitor); - - // Step 3 - PBYTE jmpToEnd = blockBegin + 8; - jmpToEnd[0] = 0xE9; - *(DWORD*)(jmpToEnd + 1) = (DWORD)(blockEnd - jmpToEnd - 5); - - VirtualProtect(blockBegin, 8 + 5, dwOldProtect, &dwOldProtect); - goto done; - -done: - printf("[AC] Patched!\n"); - return TRUE; -#else - return FALSE; -#endif -} - -// CControlCenterExperienceManager::PositionView() patcher -BOOL Moment2PatchControlCenter(LPMODULEINFO mi) -{ -#if defined(_M_X64) - // Step 1: - // Scan within the DLL for `rcMonitor = mi.rcMonitor`. - // ```0F 10 44 24 ?? F3 0F 7F 44 24 ?? 80 // movups - movdqu - cmp``` - // 22621.1992: 4B35B - // 22621.2283: 65C5C - PBYTE rcMonitorAssignment = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x0F\x10\x44\x24\x00\xF3\x0F\x7F\x44\x24\x00\x80", "xxxx?xxxxx?x"); - if (!rcMonitorAssignment) return FALSE; - printf("[CC] rcMonitorAssignment = %llX\n", rcMonitorAssignment - (PBYTE)mi->lpBaseOfDll); - - // Step 2: - // Scan within the function for the 10 bytes long `rcMonitor = mi.rcWork`. - // This pattern applies to both ControlCenter and ToastCenter. - // ```0F 10 45 ?? F3 0F 7F 44 24 ?? 48 // movups - movdqu - test``` - // 22621.1992: 4B3FD and 4B418 (The second one is compiled out in later builds) - // 22621.2283: 65CE6 - PBYTE rcWorkAssignment = (PBYTE)FindPattern(rcMonitorAssignment + 1, 256, "\x0F\x10\x45\x00\xF3\x0F\x7F\x44\x24\x00\x48", "xxx?xxxxx?x"); - if (!rcWorkAssignment) return FALSE; - printf("[CC] rcWorkAssignment = %llX\n", rcWorkAssignment - (PBYTE)mi->lpBaseOfDll); - - // Step 3: - // Copy the `rcMonitor = mi.rcWork` into right after the first jz starting from step 1. - // Find within couple bytes from step 1: - // ```48 8D // lea``` - // 22621.1992: 4B373 - // 22621.2283: 65C74 - PBYTE blockBegin = (PBYTE)FindPattern(rcMonitorAssignment + 1, 32, "\x48\x8D", "xx"); - if (!blockBegin) return FALSE; - printf("[CC] blockBegin = %llX\n", blockBegin - (PBYTE)mi->lpBaseOfDll); - - // Step 4: - // Exit the block by writing a long jmp into the address referenced by the jz right before step 3, into right after - // the 10 bytes `rcMonitor = mi.rcWork` we've written. - PBYTE blockEnd = GetTargetOfJzBeforeMe(blockBegin); - if (!blockEnd) return FALSE; - printf("[CC] blockEnd = %llX\n", blockEnd - (PBYTE)mi->lpBaseOfDll); - - // Execution - DWORD dwOldProtect = 0; - if (!VirtualProtect(blockBegin, 10 /*rcMonitor = mi.rcWork*/ + 5 /*jmp*/, PAGE_EXECUTE_READWRITE, &dwOldProtect)) return FALSE; - - // Step 2 - memcpy(blockBegin, rcWorkAssignment, 10); - - // Step 3 - PBYTE jmpToEnd = blockBegin + 10; - jmpToEnd[0] = 0xE9; - *(DWORD*)(jmpToEnd + 1) = (DWORD)(blockEnd - jmpToEnd - 5); - - VirtualProtect(blockBegin, 10 + 5, dwOldProtect, &dwOldProtect); - - printf("[CC] Patched!\n"); - return TRUE; -#else - return FALSE; -#endif -} - -// CToastCenterExperienceManager::PositionView() patcher -BOOL Moment2PatchToastCenter(LPMODULEINFO mi) -{ -#if defined(_M_X64) - // Step 1: - // Scan within the DLL for `rcMonitor = mi.rcMonitor`. - // - // Pattern 1: - // Will have a match if CToastCenterExperienceManager::ShouldShowWithinWorkArea() is present. - // ```0F 10 45 ?? ?? 0F 7F 44 24 ?? 48 8B CF // movups - movdqu - mov``` - // 22621.1992: 40CE8 - // 22621.2283: 501DB - // - // Pattern 2: - // Will have a match if CToastCenterExperienceManager::ShouldShowWithinWorkArea() is inlined. - // ```0F 10 45 ?? ?? 0F 7F 44 24 ?? 44 38 // movups - movdqu - cmp``` - // 25951.1000: 36B2C4 - // - // Pattern 3: - // Same as pattern 1, but different length of the movdqu instruction. - // ```0F 10 45 ?? ?? 0F 7F 45 ?? 48 8B CF // movups - movdqu - mov``` - // 22621.3066: 3DC340 - // - // Pattern 4: - // Same as pattern 2, but different length of the movdqu instruction. - // ```0F 10 45 ?? ?? 0F 7F 45 ?? 44 38 // movups - movdqu - cmp``` - // No matches yet, just in case. - int assignmentSize = 10; - PBYTE rcMonitorAssignment = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x0F\x10\x45\x00\x00\x0F\x7F\x44\x24\x00\x48\x8B\xCF", "xxx??xxxx?xxx"); - if (!rcMonitorAssignment) - { - rcMonitorAssignment = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x0F\x10\x45\x00\x00\x0F\x7F\x44\x24\x00\x44\x38", "xxx??xxxx?xx"); - if (!rcMonitorAssignment) - { - assignmentSize = 9; - rcMonitorAssignment = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x0F\x10\x45\x00\x00\x0F\x7F\x45\x00\x48\x8B\xCF", "xxx??xxx?xxx"); - if (!rcMonitorAssignment) - { - rcMonitorAssignment = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x0F\x10\x45\x00\x00\x0F\x7F\x45\x00\x44\x38", "xxx??xxx?xx"); - if (!rcMonitorAssignment) return FALSE; - } - } - } - printf("[TC] rcMonitorAssignment = %llX\n", rcMonitorAssignment - (PBYTE)mi->lpBaseOfDll); - - // Step 2: - // Copy the `rcMonitor = mi.rcMonitor` into right after the first jz starting from step 1. - // Find within couple bytes from step 1: - // ```48 8D // lea``` - // Then offset the first ?? so that it points to mi.rcWork which is 16 bytes after mi.rcMonitor. - // 22621.1992: 40D02 - // 22621.2283: 501F5 - PBYTE blockBegin = (PBYTE)FindPattern(rcMonitorAssignment + 1, 32, "\x48\x8D", "xx"); - if (!blockBegin) return FALSE; - printf("[TC] blockBegin = %llX\n", blockBegin - (PBYTE)mi->lpBaseOfDll); - - // Step 3: - // Exit the block by writing a long jmp into the address referenced by the jz right before step 3, into right after - // the bytes `rcMonitor = mi.rcWork` we've written. - // - // Note: We are skipping EdgeUI calls here. - PBYTE blockEnd = GetTargetOfJzBeforeMe(blockBegin); - if (!blockEnd) return FALSE; - printf("[TC] blockEnd = %llX\n", blockEnd - (PBYTE)mi->lpBaseOfDll); - - // Execution - DWORD dwOldProtect = 0; - if (!VirtualProtect(blockBegin, assignmentSize /*rcMonitor = mi.rcWork*/ + 5 /*jmp*/, PAGE_EXECUTE_READWRITE, &dwOldProtect)) return FALSE; - - // Step 2 - memcpy(blockBegin, rcMonitorAssignment, assignmentSize); - blockBegin[3] += offsetof(MONITORINFO, rcWork) - offsetof(MONITORINFO, rcMonitor); - - // Step 3 - PBYTE jmpToEnd = blockBegin + assignmentSize; - jmpToEnd[0] = 0xE9; - *(DWORD*)(jmpToEnd + 1) = (DWORD)(blockEnd - jmpToEnd - 5); - - VirtualProtect(blockBegin, assignmentSize + 5, dwOldProtect, &dwOldProtect); - - printf("[TC] Patched!\n"); - return TRUE; -#else - return FALSE; -#endif -} - -// TaskViewFrame::RuntimeClassInitialize() patcher -BOOL Moment2PatchTaskView(LPMODULEINFO mi) -{ -#if defined(_M_X64) - /*** - If we're using the old taskbar, it'll be stuck in an infinite loading since it's waiting for the new one to respond. - Let's safely skip those by NOPing the `TaskViewFrame::UpdateWorkAreaAsync()` and `WaitForCompletion()` calls, and - turning off the COM object cleanup. - - Step 1: - Scan within the DLL to find the beginning, which is the preparation of the 1st call. - It should be 4C 8B or 4D 8B (mov r8, ...). - For the patterns, they're +1 from the result since it can be either of those. - - Pattern 1: - ```8B ?? 48 8D 55 ?? 48 8B ?? E8 ?? ?? ?? ?? 48 8B 08 E8``` - 22621.1992: 7463C - 22621.2134: 3B29C - - Pattern 2: - ```8B ?? 48 8D 54 24 ?? 48 8B ?? E8 ?? ?? ?? ?? 48 8B 08 E8``` - 22621.2283: 24A1D2 - - Step 2: - In place of the 1st call's call op (E8), overwrite it with a code to set the value of the com_ptr passed into the - 2nd argument (rdx) to 0. This is to skip the cleanup that happens right after the 2nd call. - ```48 C7 02 00 00 00 00 mov qword ptr [rdx], 0``` - Start from -13 of the byte after 2nd call's end. - 22621.1992: 74646 - 22621.2134: 3B2A6 - 22621.2283: 24A1DD - - Step 3: - NOP the rest of the 2nd call. - - Summary: - ``` - 48 8B ?? 48 8D 55 ?? 48 8B ?? E8 ?? ?? ?? ?? 48 8B 08 E8 ?? ?? ?? ?? // Pattern 1 - 48 8B ?? 48 8D 54 24 ?? 48 8B ?? E8 ?? ?? ?? ?? 48 8B 08 E8 ?? ?? ?? ?? // Pattern 2 - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ - 1st: TaskViewFrame::UpdateWorkAreaAsync() 2nd: WaitForCompletion() - 48 8B ?? 48 8D 54 24 ?? 48 8B ?? 48 C7 02 00 00 00 00 90 90 90 90 90 90 // Result according to Pattern 2 - -------------------------------- xxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx - We need rdx Step 2 Step 3 - ``` - - Notes: - - In 22621.1992 and 22621.2134, `~AsyncOperationCompletedHandler()` is inlined, while it is not in 22621.2283. We - can see `unconditional_release_ref()` calls right in `RuntimeClassInitialize()` of 1992 and 2134. - - In 22621.2134, there is `33 FF xor edi, edi` before the jz for the inlined cleanup. The value of edi is used in - two more cleanup calls after our area of interest (those covered by twoCallsLength), therefore we can't just NOP - everything. And I think detecting such things is too much work. - ***/ - - int twoCallsLength = 1 + 18 + 4; // 4C/4D + pattern length + 4 bytes for the 2nd call's call address - PBYTE firstCallPrep = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x8B\x00\x48\x8D\x55\x00\x48\x8B\x00\xE8\x00\x00\x00\x00\x48\x8B\x08\xE8", "x?xxx?xx?x????xxxx"); - if (!firstCallPrep) - { - twoCallsLength += 1; // Add 1 to the pattern length - firstCallPrep = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x8B\x00\x48\x8D\x54\x24\x00\x48\x8B\x00\xE8\x00\x00\x00\x00\x48\x8B\x08\xE8", "x?xxxx?xx?x????xxxx"); - if (!firstCallPrep) return FALSE; - } - firstCallPrep -= 1; // Point to the 4C/4D - printf("[TV] firstCallPrep = %llX\n", firstCallPrep - (PBYTE)mi->lpBaseOfDll); - - PBYTE firstCallCall = firstCallPrep + twoCallsLength - 13; - printf("[TV] firstCallCall = %llX\n", firstCallCall - (PBYTE)mi->lpBaseOfDll); - - PBYTE nopBegin = firstCallCall + 7; - - // Execution - DWORD dwOldProtect = 0; - if (!VirtualProtect(firstCallPrep, twoCallsLength, PAGE_EXECUTE_READWRITE, &dwOldProtect)) return FALSE; - const BYTE step2Payload[] = { 0x48, 0xC7, 0x02, 0x00, 0x00, 0x00, 0x00 }; - memcpy(firstCallCall, step2Payload, sizeof(step2Payload)); - memset(nopBegin, 0x90, twoCallsLength - (nopBegin - firstCallPrep)); - VirtualProtect(firstCallPrep, twoCallsLength, dwOldProtect, &dwOldProtect); - - printf("[TV] Patched!\n"); - return TRUE; -#else - return FALSE; -#endif -} - -// Reimplementation of HardwareConfirmatorHost::GetDisplayRect() -void WINAPI HardwareConfirmatorShellcode(PBYTE pCoroInstance) -{ - PBYTE pHardwareConfirmatorHost = *(PBYTE*)(pCoroInstance + g_Moment2PatchOffsets.coroInstance_pHardwareConfirmatorHost); - - RECT rc; - HMONITOR hMonitor = MonitorFromRect(&rc, MONITOR_DEFAULTTOPRIMARY); - - ComPtr pImmersiveShell; - if (SUCCEEDED(CoCreateInstance(CLSID_ImmersiveShell, nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&pImmersiveShell)))) - { - ComPtr pMonitorService; - if (SUCCEEDED(pImmersiveShell->QueryService(SID_IImmersiveMonitorService, IID_PPV_ARGS(&pMonitorService)))) - { - ComPtr pEdgeUiManager; - if (SUCCEEDED(pMonitorService->QueryService(hMonitor, SID_EdgeUi, IID_PPV_ARGS(&pEdgeUiManager)))) - { - if (*(pHardwareConfirmatorHost + g_Moment2PatchOffsets.hardwareConfirmatorHost_bIsInLockScreen)) - { - // Lock screen - MONITORINFO mi; - mi.cbSize = sizeof(MONITORINFO); - if (GetMonitorInfoW(hMonitor, &mi)) - rc = mi.rcMonitor; - } - else - { - // Desktop - LOG_IF_FAILED(pEdgeUiManager->GetAutohideImmuneWorkArea(&rc)); - } - - ABI::Windows::Foundation::Rect* out = (ABI::Windows::Foundation::Rect*)(pCoroInstance + g_Moment2PatchOffsets.coroInstance_rcOut); - out->X = (float)rc.left; - out->Y = (float)rc.top; - out->Width = (float)(rc.right - rc.left); - out->Height = (float)(rc.bottom - rc.top); - } - } - } -} - -// [HardwareConfirmatorHost::GetDisplayRectAsync$_ResumeCoro$1() patcher -BOOL Moment2PatchHardwareConfirmator(LPMODULEINFO mi) -{ -#if defined(_M_X64) - // Find required offsets - - // pHardwareConfirmatorHost and bIsInLockScreen: - // Find in GetDisplayRectAsync$_ResumeCoro$1, inside `case 4:` - // - // 48 8B 83 ED 00 00 00 mov rax, [rbx+0EDh] - // ^^^^^^^^^^^ pHardwareConfirmatorHost - // 8A 80 EC 00 00 00 mov al, [rax+0ECh] - // ^^^^^^^^^^^ bIsInLockScreen - // - // if ( ADJ(this)->pHardwareConfirmatorHost->bIsInLockScreen ) - // if ( *(_BYTE *)(*(_QWORD *)(this + 237) + 236i64) ) // 22621.2283 - // ^ HCH ^ bIsInLockScreen - // - // 22621.2134: 1D55D - PBYTE match1 = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x48\x8B\x83\x00\x00\x00\x00\x8A\x80", "xxx????xx"); - printf("[HC] match1 = %llX\n", match1 - (PBYTE)mi->lpBaseOfDll); - if (!match1) return FALSE; - g_Moment2PatchOffsets.coroInstance_pHardwareConfirmatorHost = *(int*)(match1 + 3); - g_Moment2PatchOffsets.hardwareConfirmatorHost_bIsInLockScreen = *(int*)(match1 + 9); - - // coroInstance_rcOut: - // Also in GetDisplayRectAsync$_ResumeCoro$1, through `case 4:` - // We also use this as the point to jump to, which is the code to set the rect and finish the coroutine. - // - // v27 = *(_OWORD *)(this + 16); - // *(_OWORD *)(this - 16) = v27; - // if ( winrt_suspend_handler ) ... - // - // 0F 10 43 10 movups xmm0, xmmword ptr [rbx+10h] - // ^^ coroInstance_rcOut - // 0F 11 84 24 D0 00 00 00 movups [rsp+158h+var_88], xmm0 - // - // 22621.2134: 1D624 - PBYTE match2 = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x0F\x10\x43\x00\x0F\x11\x84\x24", "xxx?xxxx"); - printf("[HC] match2 = %llX\n", match2 - (PBYTE)mi->lpBaseOfDll); - if (!match2) return FALSE; - g_Moment2PatchOffsets.coroInstance_rcOut = *(match2 + 3); - - // Find where to put the shellcode - // We'll overwrite from this position: - // - // *(_OWORD *)(this + 32) = 0i64; - // *(_QWORD *)(this + 48) = MonitorFromRect((LPCRECT)(this + 32), 1u); - // - // 22621.2134: 1D21E - PBYTE writeAt = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x48\x8D\x4B\x00\x0F", "xxx?x"); - if (!writeAt) return FALSE; - printf("[HC] writeAt = %llX\n", writeAt - (PBYTE)mi->lpBaseOfDll); - - // In 22621.2134+, after our jump location there is a cleanup for something we skipped. NOP them. - // From match2, bytes +17 until +37, which is 21 bytes to be NOP'd. - // 22621.2134: 1D635-1D64A - PBYTE cleanupBegin = nullptr, cleanupEnd = nullptr; - if (IsWindows11Version22H2Build2134OrHigher()) - { - cleanupBegin = match2 + 17; - cleanupEnd = match2 + 38; // Exclusive - printf("[HC] cleanup = %llX-%llX\n", cleanupBegin - (PBYTE)mi->lpBaseOfDll, cleanupEnd - (PBYTE)mi->lpBaseOfDll); - if (*cleanupBegin != 0x49 || *cleanupEnd != 0x90 /*Already NOP here*/) return FALSE; - } - - // Craft the shellcode - BYTE shellcode[] = { - // lea rcx, [rbx+0] ; rbx is the `this` which is the instance of the coro, we pass it to our function - 0x48, 0x8D, 0x0B, - // mov rax, 1111111111111111h ; placeholder for the address of HardwareConfirmatorShellcode - 0x48, 0xB8, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - // call rax - 0xFF, 0xD0 - }; - - uintptr_t pattern = 0x1111111111111111; - *(uintptr_t*)(memmem(shellcode, sizeof(shellcode), &pattern, sizeof(uintptr_t))) = (uintptr_t)HardwareConfirmatorShellcode; - - // Execution - DWORD dwOldProtect = 0; - SIZE_T totalSize = sizeof(shellcode) + 5; - if (!VirtualProtect(writeAt, totalSize, PAGE_EXECUTE_READWRITE, &dwOldProtect)) return FALSE; - memcpy(writeAt, shellcode, sizeof(shellcode)); - PBYTE jmpLoc = writeAt + sizeof(shellcode); - jmpLoc[0] = 0xE9; - *(DWORD*)(jmpLoc + 1) = (DWORD)(match2 - jmpLoc - 5); - VirtualProtect(writeAt, totalSize, dwOldProtect, &dwOldProtect); - - if (cleanupBegin) - { - dwOldProtect = 0; - if (!VirtualProtect(cleanupBegin, cleanupEnd - cleanupBegin, PAGE_EXECUTE_READWRITE, &dwOldProtect)) return FALSE; - memset(cleanupBegin, 0x90, cleanupEnd - cleanupBegin); - VirtualProtect(cleanupBegin, cleanupEnd - cleanupBegin, dwOldProtect, &dwOldProtect); - } - - printf("[HC] Patched!\n"); - return TRUE; -#else - return FALSE; -#endif -} - -#pragma endregion - - -#pragma region "Fix broken Windows 10 start menu positioning issues caused by 44656322" - -// Reverts 44656322's effects on the start menu -extern "C" HRESULT CStartExperienceManager_GetMonitorInformationHook(void* _this, CSingleViewShellExperience* experience, RECT* rcOutWorkArea, EDGEUI_TRAYSTUCKPLACE* outTrayStuckPlace, bool* bOutRtl, HMONITOR* hOutMonitor) -{ - *rcOutWorkArea = {}; - *outTrayStuckPlace = EUITSP_BOTTOM; - *bOutRtl = false; - if (hOutMonitor) - *hOutMonitor = nullptr; - - ComPtr spImmersiveShellServiceProvider; - RETURN_IF_FAILED(CoCreateInstance(CLSID_ImmersiveShell, nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&spImmersiveShellServiceProvider))); - - ComPtr spImmersiveLauncher; - RETURN_IF_FAILED(spImmersiveShellServiceProvider->QueryService(SID_ImmersiveLauncher, IID_PPV_ARGS(&spImmersiveLauncher))); - - ComPtr spImmersiveMonitor; - HRESULT hr = spImmersiveLauncher->GetMonitor(&spImmersiveMonitor); - if (FAILED(hr)) - return hr; - - HMONITOR hMonitor = nullptr; - if (hOutMonitor) - hr = spImmersiveMonitor->GetHandle(&hMonitor); - - if (FAILED(hr)) - return hr; - - ComPtr spEdgeUiManager; - hr = IUnknown_QueryService(spImmersiveMonitor.Get(), SID_EdgeUi, IID_PPV_ARGS(&spEdgeUiManager)); - if (FAILED(hr)) - return hr; - - EDGEUI_TRAYSTUCKPLACE trayStuckPlace; - RETURN_IF_FAILED(spEdgeUiManager->GetTrayStuckPlace(&trayStuckPlace)); - - HWND hwndTray = FindWindowW(L"Shell_TrayWnd", nullptr); - - RECT rcWork; - if (hwndTray && GetPropW(hwndTray, L"IsAutoHideEnabled")) - { - RETURN_IF_FAILED(spEdgeUiManager->GetAutohideImmuneWorkArea(&rcWork)); - } - else - { - RETURN_IF_FAILED(spImmersiveMonitor->GetWorkArea(&rcWork)); - } - - *rcOutWorkArea = rcWork; - *outTrayStuckPlace = trayStuckPlace; - *bOutRtl = Mirror_IsThreadRTL() != FALSE; - if (hOutMonitor) - *hOutMonitor = hMonitor; - - return S_OK; -} - -#pragma endregion - - -#pragma region "Fix Windows 10 start menu animation on 22000.65+" - -static struct -{ - int startExperienceManager_IStartExperienceManager; - int startExperienceManager_SingleViewShellExperienceEventHandler; - int startExperienceManager_singleViewShellExperience; - int startExperienceManager_openingAnimation; - int startExperienceManager_closingAnimation; - int startExperienceManager_bTransitioningToCortana; -} g_SMAnimationPatchOffsets; - -// Names taken from Windows.UI.Xaml.pdb, only defining the used ones -enum DWMTRANSITION_TARGET -{ - DWMTARGET_LAUNCHERFLYOUTTOLEFT = 0x4D, - DWMTARGET_LAUNCHERFLYOUTTORIGHT = 0x4E, - DWMTARGET_LAUNCHERFLYOUTTOTOP = 0x4F, - DWMTARGET_LAUNCHERFLYOUTTOBOTTOM = 0x50, - DWMTARGET_LAUNCHERFLYOUT = 0x51, - DWMTARGET_LAUNCHERFULLSCREEN = 0x52, -}; - -DEFINE_ENUM_FLAG_OPERATORS(DWMTRANSITION_TARGET); - -extern HRESULT CStartExperienceManager_GetMonitorInformationHook(void* _this, CSingleViewShellExperience* experience, RECT* rcOutWorkArea, EDGEUI_TRAYSTUCKPLACE* outTrayStuckPlace, bool* bOutRtl, HMONITOR* hOutMonitor); -HRESULT(*CStartExperienceManager_GetMonitorInformationFunc)(void* _this, void* experience, RECT* rcOutWorkArea, EDGEUI_TRAYSTUCKPLACE* outTrayStuckPlace, bool* bOutRtl, HMONITOR* hOutMonitor); -HRESULT(*CExperienceManagerAnimationHelper_BeginFunc)(void* _this, void* pViewWrapper, DWMTRANSITION_TARGET target, const RECT* prcBeginSource, const RECT* prcBeginDestination, const RECT* prcEndSource, const RECT* prcEndDestination, const RECT* prcClip); -HRESULT(*CExperienceManagerAnimationHelper_EndFunc)(void* _this); - -HRESULT(*CStartExperienceManager_OnViewUncloakingFunc)(void* eventHandler, CSingleViewShellExperience* pSender); -HRESULT CStartExperienceManager_OnViewUncloakingHook(void* eventHandler, CSingleViewShellExperience* pSender) -{ - PBYTE _this = (PBYTE)eventHandler - g_SMAnimationPatchOffsets.startExperienceManager_SingleViewShellExperienceEventHandler; - - RECT rcWorkArea; - EDGEUI_TRAYSTUCKPLACE tsp; - bool bRtl; - if (SUCCEEDED(CStartExperienceManager_GetMonitorInformationHook(_this, pSender, &rcWorkArea, &tsp, &bRtl, NULL)) && dwStartShowClassicMode) - { - DWMTRANSITION_TARGET target = DWMTARGET_LAUNCHERFLYOUT; - if (pSender->_fullScreen) - target = DWMTARGET_LAUNCHERFULLSCREEN; - else if (tsp == EUITSP_LEFT) - target = DWMTARGET_LAUNCHERFLYOUTTORIGHT; - else if (tsp == EUITSP_TOP) - target = DWMTARGET_LAUNCHERFLYOUTTOBOTTOM; - else if (tsp == EUITSP_RIGHT) - target = DWMTARGET_LAUNCHERFLYOUTTOLEFT; - else if (tsp == EUITSP_BOTTOM) - target = DWMTARGET_LAUNCHERFLYOUTTOTOP; - - CExperienceManagerAnimationHelper_BeginFunc( - _this + g_SMAnimationPatchOffsets.startExperienceManager_openingAnimation, - pSender->_viewWrapper, - (DWMTRANSITION_TARGET)(target | 0x200000), nullptr, nullptr, nullptr, nullptr, &rcWorkArea); - } - - if (global_rovi.dwBuildNumber >= 25169) - { - // Patch hardcoded EUITSP_BOTTOM present in the original function with the correct value -#if defined(_M_X64) - static int* rgpConstants[2]; - if (!rgpConstants[0] && rgpConstants[0] != (int*)-1) - { - // 03 00 00 00 - PBYTE match = (PBYTE)FindPattern(CStartExperienceManager_OnViewUncloakingFunc, 80, "\x03\x00\x00\x00", "xxxx"); - rgpConstants[0] = match ? (int*)match : (int*)-1; - if (match) - { - match = (PBYTE)FindPattern(match + 4, 40, "\x03\x00\x00\x00", "xxxx"); - rgpConstants[1] = match ? (int*)match : (int*)-1; - } - } - for (int i = 0; i < ARRAYSIZE(rgpConstants); i++) - { - if (rgpConstants[i] && rgpConstants[i] != (int*)-1) - { - DWORD dwOldProtect; - if (VirtualProtect(rgpConstants[i], 4, PAGE_EXECUTE_READWRITE, &dwOldProtect)) - { - *rgpConstants[i] = tsp; - VirtualProtect(rgpConstants[i], 4, dwOldProtect, &dwOldProtect); - } - } - } -#elif defined(_M_ARM64) - static DWORD* rgpInsnMovs[2]; - if (!rgpInsnMovs[0] && rgpInsnMovs[0] != (DWORD*)-1) - { - // 68 00 80 52 - PBYTE match = (PBYTE)FindPattern(CStartExperienceManager_OnViewUncloakingFunc, 160, "\x68\x00\x80\x52", "xxxx"); - rgpInsnMovs[0] = match ? (DWORD*)match : (DWORD*)-1; - if (match) - { - match = (PBYTE)FindPattern(match + 4, 40, "\x68\x00\x80\x52", "xxxx"); - rgpInsnMovs[1] = match ? (DWORD*)match : (DWORD*)-1; - } - } - for (int i = 0; i < ARRAYSIZE(rgpInsnMovs); i++) - { - if (rgpInsnMovs[i] && rgpInsnMovs[i] != (DWORD*)-1) - { - DWORD dwOldProtect; - if (VirtualProtect(rgpInsnMovs[i], 4, PAGE_EXECUTE_READWRITE, &dwOldProtect)) - { - if (ARM64_IsInRange(tsp, 16)) - { - DWORD insn = *rgpInsnMovs[i]; - int imm16Mask = ((1 << 16) - 1) << 5; - insn &= ~imm16Mask; // clear imm16 - insn |= (tsp << 5) & imm16Mask; // set imm16 - *rgpInsnMovs[i] = insn; - } - VirtualProtect(rgpInsnMovs[i], 4, dwOldProtect, &dwOldProtect); - } - } - } -#endif - } - - return CStartExperienceManager_OnViewUncloakingFunc(eventHandler, pSender); -} - -HRESULT(*CStartExperienceManager_OnViewUncloakedFunc)(void* eventHandler, CSingleViewShellExperience* pSender); -HRESULT CStartExperienceManager_OnViewUncloakedHook(void* eventHandler, CSingleViewShellExperience* pSender) -{ - PBYTE _this = (PBYTE)eventHandler - g_SMAnimationPatchOffsets.startExperienceManager_SingleViewShellExperienceEventHandler; - - if (dwStartShowClassicMode) - { - CExperienceManagerAnimationHelper_EndFunc(_this + g_SMAnimationPatchOffsets.startExperienceManager_openingAnimation); - } - - return CStartExperienceManager_OnViewUncloakedFunc(eventHandler, pSender); -} - -HRESULT(*CStartExperienceManager_OnViewCloakingFunc)(void* eventHandler, CSingleViewShellExperience* pSender); -HRESULT CStartExperienceManager_OnViewCloakingHook(void* eventHandler, CSingleViewShellExperience* pSender) -{ - PBYTE _this = (PBYTE)eventHandler - g_SMAnimationPatchOffsets.startExperienceManager_SingleViewShellExperienceEventHandler; - - bool bTransitioningToCortana = *(_this + g_SMAnimationPatchOffsets.startExperienceManager_bTransitioningToCortana); - if (!bTransitioningToCortana && dwStartShowClassicMode) - { - RECT rcWorkArea; - EDGEUI_TRAYSTUCKPLACE tsp; - bool bRtl; - HMONITOR hMonitor; - if (SUCCEEDED(CStartExperienceManager_GetMonitorInformationHook(_this, pSender, &rcWorkArea, &tsp, &bRtl, &hMonitor))) - { - DWMTRANSITION_TARGET target = DWMTARGET_LAUNCHERFLYOUT; - if (pSender->_fullScreen) - target = DWMTARGET_LAUNCHERFULLSCREEN; - else if (tsp == EUITSP_LEFT) - target = DWMTARGET_LAUNCHERFLYOUTTOLEFT; - else if (tsp == EUITSP_TOP) - target = DWMTARGET_LAUNCHERFLYOUTTOTOP; - else if (tsp == EUITSP_RIGHT) - target = DWMTARGET_LAUNCHERFLYOUTTORIGHT; - else if (tsp == EUITSP_BOTTOM) - target = DWMTARGET_LAUNCHERFLYOUTTOBOTTOM; - - CExperienceManagerAnimationHelper_BeginFunc( - _this + g_SMAnimationPatchOffsets.startExperienceManager_closingAnimation, - pSender->_viewWrapper, - (DWMTRANSITION_TARGET)(target | 0x200000), nullptr, nullptr, nullptr, nullptr, &rcWorkArea); - } - } - - return CStartExperienceManager_OnViewCloakingFunc(eventHandler, pSender); -} - -HRESULT(*CStartExperienceManager_OnViewHiddenFunc)(void* eventHandler, CSingleViewShellExperience* pSender); -HRESULT CStartExperienceManager_OnViewHiddenHook(void* eventHandler, CSingleViewShellExperience* pSender) -{ - PBYTE _this = (PBYTE)eventHandler - g_SMAnimationPatchOffsets.startExperienceManager_SingleViewShellExperienceEventHandler; - - bool bTransitioningToCortana = *(_this + g_SMAnimationPatchOffsets.startExperienceManager_bTransitioningToCortana); - if (!bTransitioningToCortana && dwStartShowClassicMode) - { - CExperienceManagerAnimationHelper_EndFunc(_this + g_SMAnimationPatchOffsets.startExperienceManager_closingAnimation); - } - - return CStartExperienceManager_OnViewHiddenFunc(eventHandler, pSender); -} - -BOOL FixStartMenuAnimation(LPMODULEINFO mi) -{ - // The idea here is to re-add the code that got removed in 22000.65+. We can see that "STest03" is the feature flag - // that experiments with the new start menu. So, because in 22000.51 one can enable the old start menu with proper - // behavior by setting the Start_ShowClassicMode registry value to 1, and there is a convenient function called - // `StartDocked::ShouldUseStartDocked()`, we crosscheck the removed code and piece together a patch for proper - // animations on 22000.65+. - - g_SMAnimationPatchOffsets.startExperienceManager_IStartExperienceManager = 0x28; - g_SMAnimationPatchOffsets.startExperienceManager_SingleViewShellExperienceEventHandler = 0x60; - - // ### CStartExperienceManager::`vftable'{for `SingleViewShellExperienceEventHandler'} -#if defined(_M_X64) - // ``` - // 48 89 46 48 48 8D 05 ?? ?? ?? ?? 48 89 46 60 48 8D 4E 68 E8 - // ^^^^^^^^^^^ - // ``` - // Ref: CStartExperienceManager::CStartExperienceManager() - PBYTE matchVtable = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x48\x89\x46\x48\x48\x8D\x05\x00\x00\x00\x00\x48\x89\x46\x60\x48\x8D\x4E\x68\xE8", - "xxxxxxx????xxxxxxxxx" - ); - if (matchVtable) - { - matchVtable += 4; - matchVtable += 7 + *(int*)(matchVtable + 3); - } -#elif defined(_M_ARM64) - // * Pattern for Nickel - // ``` - // 69 A2 03 A9 ?? ?? 00 ?? 08 ?? ?? 91 ?? ?? 00 ?? 29 ?? ?? 91 68 32 00 F9 - // ^^^^^^^^^^^+^^^^^^^^^^^ - // ``` - // Ref: CStartExperienceManager::CStartExperienceManager() - PBYTE matchVtable = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x69\xA2\x03\xA9\x00\x00\x00\x00\x08\x00\x00\x91\x00\x00\x00\x00\x29\x00\x00\x91\x68\x32\x00\xF9", - "xxxx??x?x??x??x?x??xxxxx" - ); - if (matchVtable) - { - matchVtable += 4; - matchVtable = (PBYTE)ARM64_DecodeADRL((UINT_PTR)matchVtable, *(DWORD*)matchVtable, *(DWORD*)(matchVtable + 4)); - } - else - { - // * Pattern for Germanium - // ``` - // ?? 22 04 A9 ?? ?? 00 ?? 08 ?? ?? 91 ?? A2 01 91 ?? 32 00 F9 - // ^^^^^^^^^^^+^^^^^^^^^^^ - // ``` - // Ref: CStartExperienceManager::CStartExperienceManager() - matchVtable = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x22\x04\xA9\x00\x00\x00\x00\x08\x00\x00\x91\x00\xA2\x01\x91\x00\x32\x00\xF9", - "xxx??x?x??x?xxx?xxx" - ); - if (matchVtable) - { - matchVtable += 3; - matchVtable = (PBYTE)ARM64_DecodeADRL((UINT_PTR)matchVtable, *(DWORD*)matchVtable, *(DWORD*)(matchVtable + 4)); - } - } -#endif - if (matchVtable) - { - printf("[SMA] matchVtable = %llX\n", matchVtable - (PBYTE)mi->lpBaseOfDll); - } - - // ### Offset of SingleViewShellExperience instance and its event handler -#if defined(_M_X64) - // ``` - // 48 8D 8E ?? ?? ?? ?? 44 8D 45 41 48 8D 56 60 E8 - // ^^^^^^^^^^^ SVSE ^^ SVSEEH (hardcoded to 0x60, included in pattern for sanity check) - // ``` - // Ref: CStartExperienceManager::CStartExperienceManager() - PBYTE matchSingleViewShellExperienceFields = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x48\x8D\x8E\x00\x00\x00\x00\x44\x8D\x45\x41\x48\x8D\x56\x60\xE8", - "xxx????xxxxxxxxx" - ); - if (matchSingleViewShellExperienceFields) - { - g_SMAnimationPatchOffsets.startExperienceManager_singleViewShellExperience = *(int*)(matchSingleViewShellExperienceFields + 3); - } -#elif defined(_M_ARM64) - // ``` - // 22 08 80 52 ?? 82 01 91 ?? ?? ?? 91 ?? ?? ?? ?? 1F 20 03 D5 - // ^^^SVSEEH^^ ^^^^^^^^^^^ SVSE - // ``` - // Ref: CStartExperienceManager::CStartExperienceManager() - PBYTE matchSingleViewShellExperienceFields = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x22\x08\x80\x52\x00\x82\x01\x91\x00\x00\x00\x91\x00\x00\x00\x00\x1F\x20\x03\xD5", - "xxxx?xxx???x????xxxx" - ); - if (matchSingleViewShellExperienceFields) - { - g_SMAnimationPatchOffsets.startExperienceManager_singleViewShellExperience = (int)ARM64_DecodeADD(*(DWORD*)(matchSingleViewShellExperienceFields + 8)); - } -#endif - if (matchSingleViewShellExperienceFields) - { - printf("[SMA] matchSingleViewShellExperienceFields = %llX\n", matchSingleViewShellExperienceFields - (PBYTE)mi->lpBaseOfDll); - } - - // ### Offsets of Animation Helpers - PBYTE matchAnimationHelperFields = nullptr; -#if defined(_M_X64) - // ``` - // 40 88 AE ?? ?? ?? ?? C7 86 ?? ?? ?? ?? 38 00 00 00 - // ^^^^^^^^^^^ AH1 - // ``` - // Ref: CStartExperienceManager::CStartExperienceManager() - // AH2 is located right after AH1. AH is 32 bytes - if (matchSingleViewShellExperienceFields) - { - matchAnimationHelperFields = (PBYTE)FindPattern( - matchSingleViewShellExperienceFields + 16, - 128, - "\x40\x88\xAE\x00\x00\x00\x00\xC7\x86\x00\x00\x00\x00\x38\x00\x00\x00", - "xxx????xx????xxxx" - ); - } - if (matchAnimationHelperFields) - { - g_SMAnimationPatchOffsets.startExperienceManager_openingAnimation = *(int*)(matchAnimationHelperFields + 3); - g_SMAnimationPatchOffsets.startExperienceManager_closingAnimation = g_SMAnimationPatchOffsets.startExperienceManager_openingAnimation + 32; - } -#elif defined(_M_ARM64) - // ``` - // 08 07 80 52 ?? ?? ?? 39 ?? ?? ?? B9 - // ^^^^^^^^^^^ AH1 - // ``` - // Ref: CStartExperienceManager::CStartExperienceManager() - // AH2 is located right after AH1. AH is 32 bytes - if (matchSingleViewShellExperienceFields) - { - matchAnimationHelperFields = (PBYTE)FindPattern( - matchSingleViewShellExperienceFields + 20, - 128, - "\x08\x07\x80\x52\x00\x00\x00\x39\x00\x00\x00\xB9", - "xxxx???x???x" - ); - } - if (matchAnimationHelperFields) - { - int openingAnimation = (int)ARM64_DecodeSTRBIMM(*(DWORD*)(matchAnimationHelperFields + 4)); - if (openingAnimation != -1) - { - g_SMAnimationPatchOffsets.startExperienceManager_openingAnimation = openingAnimation; - g_SMAnimationPatchOffsets.startExperienceManager_closingAnimation = g_SMAnimationPatchOffsets.startExperienceManager_openingAnimation + 32; - } - else - { - matchAnimationHelperFields = nullptr; - } - } -#endif - if (matchAnimationHelperFields) - { - printf( - "[SMA] matchAnimationHelperFields = %llX, +0x%X, +0x%X\n", - matchAnimationHelperFields - (PBYTE)mi->lpBaseOfDll, - g_SMAnimationPatchOffsets.startExperienceManager_openingAnimation, - g_SMAnimationPatchOffsets.startExperienceManager_closingAnimation - ); - } - - // ### Offset of bTransitioningToCortana -#if defined(_M_X64) - // ``` - // 80 B9 ?? ?? ?? ?? 00 75 ?? 48 83 C1 D8 - // ^^^^^^^^^^^ bTransitioningToCortana - // ``` - // Ref: CStartExperienceManager::DimStart() - PBYTE matchTransitioningToCortanaField = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x80\xB9\x00\x00\x00\x00\x00\x75\x00\x48\x83\xC1\xD8", - "xx????xx?xxxx" - ); - if (matchTransitioningToCortanaField) - { - g_SMAnimationPatchOffsets.startExperienceManager_bTransitioningToCortana = g_SMAnimationPatchOffsets.startExperienceManager_IStartExperienceManager + *(int*)(matchTransitioningToCortanaField + 2); - } -#elif defined(_M_ARM64) - // ``` - // ?? ?? ?? 39 E8 00 00 35 ?? ?? ?? ?? 01 ?? ?? 91 22 00 80 52 - // ^^^^^^^^^^^ bTransitioningToCortana - // ``` - // Ref: CStartExperienceManager::DimStart() - PBYTE matchTransitioningToCortanaField = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x39\xE8\x00\x00\x35\x00\x00\x00\x00\x01\x00\x00\x91\x22\x00\x80\x52", - "xxxxx????x??xxxxx" - ); - if (matchTransitioningToCortanaField) - { - int off = (int)ARM64_DecodeLDRBIMM(*(DWORD*)(matchTransitioningToCortanaField - 3)); - if (off != -1) - { - g_SMAnimationPatchOffsets.startExperienceManager_bTransitioningToCortana = g_SMAnimationPatchOffsets.startExperienceManager_IStartExperienceManager + off; - } - else - { - matchTransitioningToCortanaField = nullptr; - } - } -#endif - if (matchTransitioningToCortanaField) - { - printf("[SMA] matchTransitioningToCortanaField = %llX, +0x%X\n", matchTransitioningToCortanaField - (PBYTE)mi->lpBaseOfDll, g_SMAnimationPatchOffsets.startExperienceManager_bTransitioningToCortana); - } - - // ### Offset of CStartExperienceManager::GetMonitorInformation() -#if defined(_M_X64) - // ``` - // 48 8B ?? E8 ?? ?? ?? ?? 8B ?? 85 C0 0F 88 ?? ?? ?? ?? C6 44 24 ?? 01 - // ^^^^^^^^^^^ - // ``` - // Ref: CStartExperienceManager::PositionMenu() - PBYTE matchGetMonitorInformation = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x48\x8B\x00\xE8\x00\x00\x00\x00\x8B\x00\x85\xC0\x0F\x88\x00\x00\x00\x00\xC6\x44\x24\x00\x01", - "xx?x????x?xxxx????xxx?x" - ); - if (matchGetMonitorInformation) - { - matchGetMonitorInformation += 3; - matchGetMonitorInformation += 5 + *(int*)(matchGetMonitorInformation + 1); - } -#elif defined(_M_ARM64) - // * Pattern for 226xx - // ``` - // E3 ?? 00 91 E2 ?? 00 91 E0 03 13 AA ?? ?? ?? ?? F4 03 00 2A - // ^^^^^^^^^^^ - // ``` - // Ref: CStartExperienceManager::PositionMenu() - PBYTE matchGetMonitorInformation = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\xE3\x00\x00\x91\xE2\x00\x00\x91\xE0\x03\x13\xAA\x00\x00\x00\x00\xF4\x03\x00\x2A", - "x?xxx?xxxxxx????xxxx" - ); - if (matchGetMonitorInformation) - { - matchGetMonitorInformation += 12; - matchGetMonitorInformation = (PBYTE)ARM64_FollowBL((DWORD*)matchGetMonitorInformation); - } - if (!matchGetMonitorInformation) - { - // * Pattern for 26100.1, 265, 470, 560, 670, 712, 751, 863, 1000, 1150 - // ``` - // E2 82 00 91 E1 03 13 AA E0 03 14 AA ?? ?? ?? ?? - // ^^^^^^^^^^^ - // ``` - // Ref: CStartExperienceManager::PositionMenu() - matchGetMonitorInformation = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\xE2\x82\x00\x91\xE1\x03\x13\xAA\xE0\x03\x14\xAA", - "xxxxxxxxxxxx" - ); - if (matchGetMonitorInformation) - { - matchGetMonitorInformation += 12; - matchGetMonitorInformation = (PBYTE)ARM64_FollowBL((DWORD*)matchGetMonitorInformation); - } - } - if (!matchGetMonitorInformation) - { - // * Pattern for 26100.961, 1252, 1301, 1330, 1340, 1350, 1591, ... - // ``` - // FF 02 00 39 E2 82 00 91 E0 03 13 AA ?? ?? ?? ?? - // ^^^^^^^^^^^ - // ``` - // Ref: CStartExperienceManager::PositionMenu() - matchGetMonitorInformation = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\xFF\x02\x00\x39\xE2\x82\x00\x91\xE0\x03\x13\xAA", - "xxxxxxxxxxx" - ); - if (matchGetMonitorInformation) - { - matchGetMonitorInformation += 12; - matchGetMonitorInformation = (PBYTE)ARM64_FollowBL((DWORD*)matchGetMonitorInformation); - } - } -#endif - if (matchGetMonitorInformation) - { - CStartExperienceManager_GetMonitorInformationFunc = (decltype(CStartExperienceManager_GetMonitorInformationFunc))matchGetMonitorInformation; - printf("[SMA] CStartExperienceManager::GetMonitorInformation() = %llX\n", matchGetMonitorInformation - (PBYTE)mi->lpBaseOfDll); - } - - // ### Offset of CExperienceManagerAnimationHelper::Begin() -#if defined(_M_X64) - // * Pattern 1, used when all arguments are available: - // ``` - // 44 8B C7 E8 ?? ?? ?? ?? 85 C0 79 19 - // ^^^^^^^^^^^ - // ``` - // * Pattern 2, used when a4, a5, and a6 are optimized out (e.g. 26020, 26058): - // ``` - // 44 8B C7 48 8D 8B ?? ?? ?? ?? E8 ?? ?? ?? ?? 85 C0 79 19 - // ^^^^^^^^^^^ - // ``` - // Ref: CJumpViewExperienceManager::OnViewUncloaking() - PBYTE matchAnimationBegin = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x44\x8B\xC7\xE8\x00\x00\x00\x00\x85\xC0\x79\x19", - "xxxx????xxxx" - ); - if (matchAnimationBegin) - { - matchAnimationBegin += 3; - matchAnimationBegin += 5 + *(int*)(matchAnimationBegin + 1); - } - else - { - matchAnimationBegin = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x44\x8B\xC7\x48\x8D\x8B\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x85\xC0\x79\x19", - "xxxxxx????x????xxxx" - ); - if (matchAnimationBegin) - { - matchAnimationBegin += 10; - matchAnimationBegin += 5 + *(int*)(matchAnimationBegin + 1); - } - } -#elif defined(_M_ARM64) - // * Pattern 1, used when all arguments are available: - // ``` - // 04 00 80 D2 03 00 80 D2 60 C2 05 91 ?? ?? ?? ?? E3 03 00 2A - // ^^^^^^^^^^^ - // ``` - // Ref: CJumpViewExperienceManager::OnViewUncloaking() - PBYTE matchAnimationBegin = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x04\x00\x80\xD2\x03\x00\x80\xD2\x60\xC2\x05\x91\x00\x00\x00\x00\xE3\x03\x00\x2A", - "xxxxxxxxxxxx????xxxx" - ); - if (matchAnimationBegin) - { - matchAnimationBegin += 12; - matchAnimationBegin = (PBYTE)ARM64_FollowBL((DWORD*)matchAnimationBegin); - } - else - { - // * Pattern 2, used when a4, a5, and a6 are optimized out (e.g. 26020, 26058): - // ``` - // ?? 02 0B 32 ?? ?? ?? 91 ?? ?? ?? 91 ?? ?? ?? ?? E3 03 00 2A - // ^^^^^^^^^^^ - // ``` - // Ref: CJumpViewExperienceManager::OnViewUncloaking() - matchAnimationBegin = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x02\x0B\x32\00\x00\x00\x91\x00\x00\x00\x91\x00\x00\x00\x00\xE3\x03\x00\x2A", - "xxx???x???x????xxxx" - ); - if (matchAnimationBegin) - { - matchAnimationBegin += 11; - matchAnimationBegin = (PBYTE)ARM64_FollowBL((DWORD*)matchAnimationBegin); - } - } -#endif - if (matchAnimationBegin) - { - CExperienceManagerAnimationHelper_BeginFunc = (decltype(CExperienceManagerAnimationHelper_BeginFunc))matchAnimationBegin; - printf("[SMA] CExperienceManagerAnimationHelper::Begin() = %llX\n", matchAnimationBegin - (PBYTE)mi->lpBaseOfDll); - } - - // ### Offset of CExperienceManagerAnimationHelper::End() -#if defined(_M_X64) - // ``` - // 40 53 48 83 EC 20 80 39 00 74 - // ``` - PBYTE matchAnimationEnd = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x40\x53\x48\x83\xEC\x20\x80\x39\x00\x74", - "xxxxxxxxxx" - ); -#elif defined(_M_ARM64) - // ``` - // 7F 23 03 D5 F3 0F 1F F8 FD 7B BF A9 FD 03 00 91 08 00 40 39 - // ----------- PACIBSP, don't scan for this because it's everywhere - // ``` - PBYTE matchAnimationEnd = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\xF3\x0F\x1F\xF8\xFD\x7B\xBF\xA9\xFD\x03\x00\x91\x08\x00\x40\x39", - "xxxxxxxxxxxxxxxx" - ); - if (matchAnimationEnd) - { - matchAnimationEnd -= 4; - } -#endif - if (matchAnimationEnd) - { - CExperienceManagerAnimationHelper_EndFunc = (decltype(CExperienceManagerAnimationHelper_EndFunc))matchAnimationEnd; - printf("[SMA] CExperienceManagerAnimationHelper::End() = %llX\n", matchAnimationEnd - (PBYTE)mi->lpBaseOfDll); - } - - // ### CStartExperienceManager::Hide() -#if defined(_M_X64) - // * Pattern 1, mov [rbx+2A3h], r12b: - // ``` - // 74 ?? ?? 03 00 00 00 44 88 - // ^^ Turn jz into jmp - // ``` - // * Pattern 2, mov byte ptr [rbx+2A3h], 1: - // ``` - // 74 ?? ?? 03 00 00 00 C6 83 - // ^^ Turn jz into jmp - // ``` - // Perform on exactly two matches - PBYTE matchHideA = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x74\x00\x00\x03\x00\x00\x00\x44\x88", - "x??xxxxxx" - ); - PBYTE matchHideB = nullptr; - if (matchHideA) - { - printf("[SMA] matchHideA in CStartExperienceManager::Hide() = %llX\n", matchHideA - (PBYTE)mi->lpBaseOfDll); - matchHideB = (PBYTE)FindPattern( - matchHideA + 14, - mi->SizeOfImage - (matchHideA + 14 - (PBYTE)mi->lpBaseOfDll), - "\x74\x00\x00\x03\x00\x00\x00\x44\x88", - "x??xxxxxx" - ); - if (matchHideB) - { - printf("[SMA] matchHideB in CStartExperienceManager::Hide() = %llX\n", matchHideB - (PBYTE)mi->lpBaseOfDll); - } - } - - if (!matchHideA || !matchHideB) - { - matchHideA = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x74\x00\x00\x03\x00\x00\x00\xC6\x83", - "x??xxxxxx" - ); - matchHideB = nullptr; - if (matchHideA) - { - printf("[SMA] matchHideA in CStartExperienceManager::Hide() = %llX\n", matchHideA - (PBYTE)mi->lpBaseOfDll); - matchHideB = (PBYTE)FindPattern( - matchHideA + 14, - mi->SizeOfImage - (matchHideA + 14 - (PBYTE)mi->lpBaseOfDll), - "\x74\x00\x00\x03\x00\x00\x00\xC6\x83", - "x??xxxxxx" - ); - if (matchHideB) - { - printf("[SMA] matchHideB in CStartExperienceManager::Hide() = %llX\n", matchHideB - (PBYTE)mi->lpBaseOfDll); - } - } - } -#elif defined(_M_ARM64) - // ``` - // ?? ?? ?? 34 ?? 00 80 52 ?? 8E 0A 39 - // ^^^^^^^^^^^ Turn CBZ into B - // ``` - // Perform on exactly two matches - PBYTE matchHideA = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x34\x00\x00\x80\x52\x00\x8E\x0A\x39", - "x?xxx?xxx" - ); - PBYTE matchHideB = nullptr; - if (matchHideA) - { - matchHideA -= 3; - printf("[SMA] matchHideA in CStartExperienceManager::Hide() = %llX (Pattern A)\n", matchHideA - (PBYTE)mi->lpBaseOfDll); - matchHideB = (PBYTE)FindPattern( - matchHideA + 12, - mi->SizeOfImage - (matchHideA + 12 - (PBYTE)mi->lpBaseOfDll), - "\x34\x00\x00\x80\x52\x00\x8E\x0A\x39", - "x?xxx?xxx" - ); - if (matchHideB) - { - matchHideB -= 3; - printf("[SMA] matchHideB in CStartExperienceManager::Hide() = %llX (Pattern A)\n", matchHideB - (PBYTE)mi->lpBaseOfDll); - } - } - else - { - // ``` - // ?? ?? ?? 34 ?? 00 80 52 ?? 4E 0B 39 - // ^^^^^^^^^^^ Turn CBZ into B - // ``` - // Perform on exactly two matches - matchHideA = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x34\x00\x00\x80\x52\x00\x4E\x0B\x39", - "x?xxx?xxx" - ); - if (matchHideA) - { - matchHideA -= 3; - printf("[SMA] matchHideA in CStartExperienceManager::Hide() = %llX (Pattern B)\n", matchHideA - (PBYTE)mi->lpBaseOfDll); - matchHideB = (PBYTE)FindPattern( - matchHideA + 12, - mi->SizeOfImage - (matchHideA + 12 - (PBYTE)mi->lpBaseOfDll), - "\x34\x00\x00\x80\x52\x00\x4E\x0B\x39", - "x?xxx?xxx" - ); - if (matchHideB) - { - matchHideB -= 3; - printf("[SMA] matchHideB in CStartExperienceManager::Hide() = %llX (Pattern B)\n", matchHideB - (PBYTE)mi->lpBaseOfDll); - } - } - } -#endif - - if (!matchVtable - || !matchSingleViewShellExperienceFields - || !matchAnimationHelperFields - || !matchTransitioningToCortanaField - || !matchGetMonitorInformation - || !matchAnimationBegin - || !matchAnimationEnd - || !matchHideA - || !matchHideB) - { - printf("[SMA] Not all offsets were found, cannot perform patch\n"); - return FALSE; - } - - void** vtable = (void**)matchVtable; - REPLACE_VTABLE_ENTRY(vtable, 4, CStartExperienceManager_OnViewUncloaking); - REPLACE_VTABLE_ENTRY(vtable, 5, CStartExperienceManager_OnViewUncloaked); - REPLACE_VTABLE_ENTRY(vtable, 6, CStartExperienceManager_OnViewCloaking); - REPLACE_VTABLE_ENTRY(vtable, 10, CStartExperienceManager_OnViewHidden); - - if (dwStartShowClassicMode) - { - DWORD dwOldProtect = 0; -#if defined(_M_X64) - if (VirtualProtect(matchHideA, 1, PAGE_EXECUTE_READWRITE, &dwOldProtect)) - { - matchHideA[0] = 0xEB; - VirtualProtect(matchHideA, 1, dwOldProtect, &dwOldProtect); - - dwOldProtect = 0; - if (VirtualProtect(matchHideB, 1, PAGE_EXECUTE_READWRITE, &dwOldProtect)) - { - matchHideB[0] = 0xEB; - VirtualProtect(matchHideB, 1, dwOldProtect, &dwOldProtect); - } - } -#elif defined(_M_ARM64) - if (VirtualProtect(matchHideA, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect)) - { - DWORD newInsn = ARM64_CBZWToB(*(DWORD*)matchHideA); - if (newInsn) - *(DWORD*)matchHideA = newInsn; - VirtualProtect(matchHideA, 4, dwOldProtect, &dwOldProtect); - - dwOldProtect = 0; - if (VirtualProtect(matchHideB, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect)) - { - newInsn = ARM64_CBZWToB(*(DWORD*)matchHideB); - if (newInsn) - *(DWORD*)matchHideB = newInsn; - VirtualProtect(matchHideB, 4, dwOldProtect, &dwOldProtect); - } - } -#endif - } - - int rv = -1; - if (CStartExperienceManager_GetMonitorInformationFunc) - { - rv = funchook_prepare( - funchook, - (void**)&CStartExperienceManager_GetMonitorInformationFunc, - CStartExperienceManager_GetMonitorInformationHook - ); - } - if (rv != 0) - { - printf("Failed to hook CStartExperienceManager::GetMonitorInformation(). rv = %d\n", rv); - } - - return TRUE; -} - -#pragma endregion - - -#pragma region "Fix broken taskbar jump list positioning caused by 40874676" - -class RoVariant -{ - enum States - { - StateIsNull = 0, - StateIsObjNoRef = 1, - StateIsObj = 3, - StateIsPV = 7 - }; - - static bool StateHasRefcount(HRESULT hrState) - { - return hrState == StateIsPV || hrState == StateIsObj; - } - - class Accessor - { - IInspectable* _pI; - HRESULT _hrState; - - ABI::Windows::Foundation::IPropertyValue* _PV() const - { - return (ABI::Windows::Foundation::IPropertyValue*)_pI; - } - - HRESULT VerifyPV() const - { - if (_hrState == StateIsPV) - return S_OK; - if (SUCCEEDED(_hrState)) - return TYPE_E_TYPEMISMATCH; - return _hrState; - } - - public: - Accessor(IInspectable* pI, HRESULT hr) : _pI(pI), _hrState(hr) {} - Accessor* operator->() { return this; } - HRESULT get_Type(ABI::Windows::Foundation::PropertyType* type) const; - - #define GETTER(name, type) HRESULT Get##name(type* value) const \ - { \ - if (!value) \ - return E_POINTER; \ - *value = {}; \ - HRESULT hr = VerifyPV(); \ - if (SUCCEEDED(hr)) \ - hr = _PV()->Get##name(value); \ - return hr; \ - } - - GETTER(UInt8, UINT8); - GETTER(Int16, INT16); - GETTER(UInt16, UINT16); - GETTER(Int32, INT32); - GETTER(UInt32, UINT32); - GETTER(Int64, INT64); - GETTER(UInt64, UINT64); - GETTER(Single, float); - GETTER(Double, double); - GETTER(Char16, WCHAR); - GETTER(Boolean, BOOLEAN); - GETTER(String, HSTRING); - GETTER(Guid, GUID); - GETTER(DateTime, ABI::Windows::Foundation::DateTime); - GETTER(TimeSpan, ABI::Windows::Foundation::TimeSpan); - GETTER(Point, ABI::Windows::Foundation::Point); - GETTER(Size, ABI::Windows::Foundation::Size); - GETTER(Rect, ABI::Windows::Foundation::Rect); - - #undef GETTER - - HRESULT GetInspectable(IInspectable** value) const - { - if (!value) - return E_POINTER; - *value = nullptr; - HRESULT hr = _hrState; - if (SUCCEEDED(hr)) - { - if (hr != StateIsNull && (hr == StateIsObj || hr == StateIsObjNoRef)) - { - *value = _pI; - _pI->AddRef(); - hr = S_OK; - } - else - { - hr = TYPE_E_TYPEMISMATCH; - } - } - return hr; - } - - #define GETTER_ARRAY(name, type) HRESULT Get##name##Array(UINT* length, type** value) const \ - { \ - if (!length || !value) \ - return E_POINTER; \ - *length = 0; \ - *value = nullptr; \ - HRESULT hr = VerifyPV(); \ - if (SUCCEEDED(hr)) \ - hr = _PV()->Get##name##Array(length, value); \ - return hr; \ - } - - GETTER_ARRAY(UInt8, UINT8); - GETTER_ARRAY(Int16, INT16); - GETTER_ARRAY(UInt16, UINT16); - GETTER_ARRAY(Int32, INT32); - GETTER_ARRAY(UInt32, UINT32); - GETTER_ARRAY(Int64, INT64); - GETTER_ARRAY(UInt64, UINT64); - GETTER_ARRAY(Single, float); - GETTER_ARRAY(Double, double); - GETTER_ARRAY(Char16, WCHAR); - GETTER_ARRAY(Boolean, BOOLEAN); - GETTER_ARRAY(String, HSTRING); - GETTER_ARRAY(Inspectable, IInspectable*); - GETTER_ARRAY(Guid, GUID); - GETTER_ARRAY(DateTime, ABI::Windows::Foundation::DateTime); - GETTER_ARRAY(TimeSpan, ABI::Windows::Foundation::TimeSpan); - GETTER_ARRAY(Point, ABI::Windows::Foundation::Point); - GETTER_ARRAY(Size, ABI::Windows::Foundation::Size); - GETTER_ARRAY(Rect, ABI::Windows::Foundation::Rect); - - #undef GETTER_ARRAY - }; - - class OutRef - { - RoVariant* _pOwner; - IInspectable* _pI; - - public: - OutRef(RoVariant* pOwner) : _pOwner(pOwner), _pI(nullptr) {} - operator ABI::Windows::Foundation::IPropertyValue**() { return (ABI::Windows::Foundation::IPropertyValue**)&_pI; } - operator IInspectable**() { return &_pI; } - ~OutRef() { _pOwner->Attach(_pI); } - }; - - IInspectable* _pI = nullptr; - HRESULT _hrState = StateIsNull; - -public: - RoVariant() = default; - RoVariant(RoVariant*); - RoVariant(RoVariant&); - RoVariant(ABI::Windows::Foundation::IPropertyValue*, bool); - -private: - RoVariant(IInspectable* pI, bool fAddRefInspectable, bool attach) - { - if (pI) - { - ABI::Windows::Foundation::IPropertyValue* pPV; - HRESULT hr = pI->QueryInterface(IID_PPV_ARGS(&pPV)); - if (SUCCEEDED(hr)) - { - _pI = pPV; - if (attach) - pI->Release(); - _hrState = StateIsPV; - } - else if (hr != E_NOINTERFACE) - { - _pI = nullptr; - _hrState = hr; - if (attach) - pI->Release(); - } - else - { - _pI = pI; - if (fAddRefInspectable && !attach) - _pI->AddRef(); - _hrState = fAddRefInspectable ? StateIsObj : StateIsObjNoRef; - } - } - else - { - _pI = nullptr; - _hrState = StateIsNull; - } - } - -public: - RoVariant(IInspectable* pI, bool attach) - { - RoVariant tmp(pI, true, attach); - Swap(tmp); - } - - RoVariant(void*); - - ~RoVariant() - { - if (_pI && StateHasRefcount(_hrState)) - _pI->Release(); - } - - RoVariant& operator=(RoVariant other) - { - Swap(other); - return *this; - } - - void Swap(RoVariant& other) - { - IInspectable* pI = _pI; - _pI = other._pI; - other._pI = pI; - - HRESULT hrState = _hrState; - _hrState = other._hrState; - other._hrState = hrState; - } - - operator IInspectable*() const { return Get(); } - IInspectable* Get() const { return _pI; } - IInspectable* Detach(); - void Attach(ABI::Windows::Foundation::IPropertyValue*); - - void Attach(IInspectable* pI) - { - RoVariant tmp = RoVariant(pI, true, true); - Swap(tmp); - } - - Accessor operator*() const { return Accessor(_pI, _hrState); } - Accessor operator->() const { return Accessor(_pI, _hrState); } - OutRef operator&() { return ReleaseAndGetAddressOf(); } - - struct USE_INSTEAD_ReleaseAndGetAddressOf - { - }; - - USE_INSTEAD_ReleaseAndGetAddressOf GetAddressOf() { return USE_INSTEAD_ReleaseAndGetAddressOf(); } - OutRef ReleaseAndGetAddressOf() { return OutRef(this); } - bool operator!(); - static RoVariant Wrap(ABI::Windows::Foundation::IPropertyValue*); - static RoVariant Wrap(IInspectable* pI) { return RoVariant(pI, false, false); } - HRESULT CopyTo(ABI::Windows::Foundation::IPropertyValue**); - HRESULT CopyTo(IInspectable**); -}; - -namespace ABI::Windows::UI::Xaml -{ - enum HorizontalAlignment - { - HorizontalAlignment_Left = 0, - HorizontalAlignment_Center = 1, - HorizontalAlignment_Right = 2, - HorizontalAlignment_Stretch = 3, - }; - - enum VerticalAlignment - { - VerticalAlignment_Top = 0, - VerticalAlignment_Center = 1, - VerticalAlignment_Bottom = 2, - VerticalAlignment_Stretch = 3, - }; -} - -static struct -{ - int jumpViewExperienceManager_rcWorkArea; -} g_JVPositioningPatchOffsets; - -HRESULT CJumpViewExperienceManager_CalcWindowPosition( - RECT rcWork, - POINT ptAnchor, - int width, - int height, - ABI::Windows::UI::Xaml::HorizontalAlignment hAlign, - ABI::Windows::UI::Xaml::VerticalAlignment vAlign, - RECT& result) -{ - using namespace ABI::Windows::UI::Xaml; - - if (false) // Feature_40874676 - { - result.bottom = max(min(ptAnchor.y, rcWork.bottom), rcWork.top); - int desiredTop = result.bottom - height; - result.top = max(desiredTop, rcWork.top); - int desiredLeft = ptAnchor.x - (width / 2); - result.left = min(max(desiredLeft, rcWork.left), rcWork.right); - result.right = min(result.left + width, rcWork.right); - return S_OK; - } - - switch (vAlign) - { - case VerticalAlignment_Center: - { - int desiredTopPre = (height / -2) + ptAnchor.y; - result.bottom = min(height + max(desiredTopPre, rcWork.top), rcWork.bottom); - int desiredTop = result.bottom - height; - result.top = max(desiredTop, rcWork.top); - break; - } - case VerticalAlignment_Top: - { - int desiredTopPre = ptAnchor.y; - result.bottom = min(height + max(desiredTopPre, rcWork.top), rcWork.bottom); - int desiredTop = result.bottom - height; - result.top = max(desiredTop, rcWork.top); - break; - } - case VerticalAlignment_Bottom: - { - int top = max(min(ptAnchor.y, rcWork.bottom) - height, rcWork.top); - result.bottom = min(top + height, rcWork.bottom); - result.top = top; - break; - } - default: - { - RETURN_HR(E_NOTIMPL); - } - } - - switch (hAlign) - { - case HorizontalAlignment_Center: - { - int desiredLeftPre = (width / -2) + ptAnchor.x; - result.right = min(width + max(desiredLeftPre, rcWork.left), rcWork.right); - int desiredLeft = result.right - width; - result.left = max(desiredLeft, rcWork.left); - break; - } - case HorizontalAlignment_Left: - { - int desiredLeftPre = ptAnchor.x; - result.right = min(width + max(desiredLeftPre, rcWork.left), rcWork.right); - int desiredLeft = result.right - width; - result.left = max(desiredLeft, rcWork.left); - break; - } - case HorizontalAlignment_Right: - { - result.left = max(min(ptAnchor.x, rcWork.right) - width, rcWork.left); - result.right = min(result.left + width, rcWork.right); - break; - } - default: - { - RETURN_HR(E_NOTIMPL); - } - } - - return S_OK; -} - -HRESULT CJumpViewExperienceManager_GetMonitorInformation(void* _this, POINT ptAnchor, RECT* prcOutWorkArea, UINT* outDpi, EDGEUI_TRAYSTUCKPLACE* outStuckPlace) -{ - HMONITOR hMonitor = MonitorFromPoint(ptAnchor, MONITOR_DEFAULTTONEAREST); - RETURN_LAST_ERROR_IF(hMonitor == INVALID_HANDLE_VALUE); - - MONITORINFO mi = { sizeof(mi) }; - RETURN_IF_WIN32_BOOL_FALSE(GetMonitorInfoW(hMonitor, &mi)); - *prcOutWorkArea = mi.rcWork; - - UINT dpiY; - RETURN_IF_FAILED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, outDpi, &dpiY)); // 884 - - ComPtr spImmersiveShellServiceProvider; - RETURN_IF_FAILED(CoCreateInstance(CLSID_ImmersiveShell, nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&spImmersiveShellServiceProvider))); - - ComPtr spImmersiveMonitorManager; - RETURN_IF_FAILED(spImmersiveShellServiceProvider->QueryService(SID_IImmersiveMonitorService, IID_PPV_ARGS(&spImmersiveMonitorManager))); // 886 - - ComPtr spEdgeUiManager; - RETURN_IF_FAILED(spImmersiveMonitorManager->QueryService(hMonitor, SID_EdgeUi, IID_PPV_ARGS(&spEdgeUiManager))); // 887 - RETURN_IF_FAILED(spEdgeUiManager->GetTrayStuckPlace(outStuckPlace)); // 888 - - return S_OK; -} - -HRESULT(*CJumpViewExperienceManager_EnsureWindowPositionFunc)(void* _this, CSingleViewShellExperience* experience); -HRESULT CJumpViewExperienceManager_EnsureWindowPositionHook(void* _this, CSingleViewShellExperience* experience) -{ - if (!experience->_viewWrapper) - return S_OK; - - ComPtr> properties; - RETURN_IF_FAILED(experience->_propertySet.As(&properties)); // 813 - - POINT ptAnchor; - { - RoVariant variant; - RETURN_IF_FAILED(properties->Lookup(Wrappers::HStringReference(L"Position").Get(), &variant)); // 816 - - ABI::Windows::Foundation::Point value; - RETURN_IF_FAILED(variant->GetPoint(&value)); // 819 - - ptAnchor.x = (int)value.X; - ptAnchor.y = (int)value.Y; - } - - ABI::Windows::UI::Xaml::HorizontalAlignment hAlign; - { - RoVariant variant; - RETURN_IF_FAILED(properties->Lookup(Wrappers::HStringReference(L"HorizontalAlign").Get(), &variant)); // 828 - - int value; - RETURN_IF_FAILED(variant->GetInt32(&value)); // 831 - hAlign = (ABI::Windows::UI::Xaml::HorizontalAlignment)value; - } - - ABI::Windows::UI::Xaml::VerticalAlignment vAlign; - { - RoVariant variant; - RETURN_IF_FAILED(properties->Lookup(Wrappers::HStringReference(L"VerticalAlign").Get(), &variant)); // 838 - - int value; - RETURN_IF_FAILED(variant->GetInt32(&value)); // 841 - vAlign = (ABI::Windows::UI::Xaml::VerticalAlignment)value; - } - - RECT rcWorkArea; - UINT dpi; - RETURN_IF_FAILED(CJumpViewExperienceManager_GetMonitorInformation( - _this, ptAnchor, &rcWorkArea, &dpi, - (EDGEUI_TRAYSTUCKPLACE*)((PBYTE)_this + 0x1F0))); // 850 - *((RECT*)((PBYTE)_this + g_JVPositioningPatchOffsets.jumpViewExperienceManager_rcWorkArea)) = rcWorkArea; - - int width, height; - ExperienceManagerUtils::ScaleByDPI(&experience->_desiredSize, dpi, &width, &height); - RETURN_HR_IF(E_INVALIDARG, width <= 0 || height <= 0); // 860 - - RECT rcPosition; - RETURN_IF_FAILED(CJumpViewExperienceManager_CalcWindowPosition(rcWorkArea, ptAnchor, width, height, hAlign, vAlign, rcPosition)); - RETURN_IF_FAILED(experience->SetPosition(&rcPosition)); - - return S_OK; -} - -BOOL FixJumpViewPositioning(MODULEINFO* mi) -{ - // Offset sanity checks - - // EDGEUI_TRAYSTUCKPLACE CJumpViewExperienceManager::m_trayStuckPlace -#if defined(_M_X64) - // 8B 8B B0 01 00 00 BF 5C 00 00 00 85 C9 - // ^^^^^^^^^^^ - // Ref: CJumpViewExperienceManager::OnViewUncloaking() - PBYTE matchOffsetTrayStuckPlace = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x8B\x8B\xB0\x01\x00\x00\xBF\x5C\x00\x00\x00\x85\xC9", - "xxxxxxxxxxxxx" - ); -#elif defined(_M_ARM64) - // ?? ?? 41 B9 89 0B 80 52 A8 01 00 34 1F 05 00 71 20 01 00 54 1F 09 00 71 A0 00 00 54 1F 0D 00 71 01 01 00 54 69 0B 80 52 - // ^^^^^^^^^^^ Important instr. to distinguish from MeetNowExperienceManager::OnViewUncloaking() in GE > !!!!!!!!!!! - // Ref: CJumpViewExperienceManager::OnViewCloaking() - PBYTE matchOffsetTrayStuckPlace = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x41\xB9\x89\x0B\x80\x52\xA8\x01\x00\x34\x1F\x05\x00\x71\x20\x01\x00\x54\x1F\x09\x00\x71\xA0\x00\x00\x54\x1F\x0D\x00\x71\x01\x01\x00\x54\x69\x0B\x80\x52", - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - ); -#endif - if (matchOffsetTrayStuckPlace) - { - printf("[JVP] matchOffsetTrayStuckPlace = %llX\n", matchOffsetTrayStuckPlace - (PBYTE)mi->lpBaseOfDll); - } - - // RECT CJumpViewExperienceManager::m_rcWorkArea - PBYTE matchOffsetRcWorkArea = nullptr; -#if defined(_M_X64) - // 48 8B 53 70 48 8D 83 ?? ?? ?? ?? - // -- ^^^^^^^^^^^ - // Ref: CJumpViewExperienceManager::OnViewUncloaking() - // Note: The ref function belongs to SingleViewShellExperienceEventHandler so `this` is +0x40. - // As long as the above sanity check passes, hardcoding it should be fine. - if (matchOffsetTrayStuckPlace) - { - matchOffsetRcWorkArea = (PBYTE)FindPattern( - matchOffsetTrayStuckPlace + 13, - 256, - "\x48\x8B\x53\x70\x48\x8D\x83", - "xxxxxxx" - ); - if (matchOffsetRcWorkArea) - { - g_JVPositioningPatchOffsets.jumpViewExperienceManager_rcWorkArea = 0x40 + *(int*)(matchOffsetRcWorkArea + 7); - } - } -#elif defined(_M_ARM64) - if (matchOffsetTrayStuckPlace) - { - // Without Feature_TaskbarJumplistOnHover (48980211) - // 01 38 40 F9 07 00 07 91 - // ----------- ^^^^^^^^^^^ - // If this matches then the offset of m_rcWorkArea is +0x200 - // Ref: CJumpViewExperienceManager::OnViewCloaking() - matchOffsetRcWorkArea = (PBYTE)FindPattern( - matchOffsetTrayStuckPlace + 38, - 128, - "\x01\x38\x40\xF9\x07\x00\x07\x91", - "xxxxxxxx" - ); - if (matchOffsetRcWorkArea) - { - g_JVPositioningPatchOffsets.jumpViewExperienceManager_rcWorkArea = 0x200; - } - if (!matchOffsetRcWorkArea) - { - // With Feature_TaskbarJumplistOnHover (48980211) - // 22 01 03 32 67 32 07 91 - // ^^^^^^^^^^^ - // If this matches then the offset of m_rcWorkArea is +0x20C - // Ref: CJumpViewExperienceManager::OnViewCloaking() - matchOffsetRcWorkArea = (PBYTE)FindPattern( - matchOffsetTrayStuckPlace + 38, - 128, - "\x22\x01\x03\x32\x67\x32\x07\x91", - "xxxxxxxx" - ); - if (matchOffsetRcWorkArea) - { - g_JVPositioningPatchOffsets.jumpViewExperienceManager_rcWorkArea = 0x20C; - } - } - } -#endif - if (matchOffsetRcWorkArea) - { - printf("[JVP] matchOffsetRcWorkArea = %llX\n", matchOffsetRcWorkArea - (PBYTE)mi->lpBaseOfDll); - } - - // CJumpViewExperienceManager::EnsureWindowPosition() -#if defined(_M_X64) - // Base Nickel and Germanium - // 8D 4E C0 48 8B ?? E8 ?? ?? ?? ?? 8B - // ^^^^^^^^^^^ - // Ref: CJumpViewExperienceManager::OnViewPropertiesChanging() - PBYTE matchEnsureWindowPosition = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x8D\x4E\xC0\x48\x8B\x00\xE8\x00\x00\x00\x00\x8B", - "xxxxx?x????x" - ); - if (matchEnsureWindowPosition) - { - matchEnsureWindowPosition += 6; - matchEnsureWindowPosition += 5 + *(int*)(matchEnsureWindowPosition + 1); - } - if (!matchEnsureWindowPosition) - { - // Nickel with Feature_TaskbarJumplistOnHover (48980211) - // - 22621.3930, 3936, 4000, 4010, 4076, 4082, 4110, 4145, ... - // 4C 8D 76 C0 48 8B D3 49 8B CE E8 ?? ?? ?? ?? 8B - // ^^^^^^^^^^^ - // Ref: CJumpViewExperienceManager::OnViewPropertiesChanging() - matchEnsureWindowPosition = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x4C\x8D\x76\xC0\x48\x8B\xD3\x49\x8B\xCE\xE8\x00\x00\x00\x00\x8B", - "xxxxxxxxxxx????x" - ); - if (matchEnsureWindowPosition) - { - matchEnsureWindowPosition += 10; - matchEnsureWindowPosition += 5 + *(int*)(matchEnsureWindowPosition + 1); - } - } - if (!matchEnsureWindowPosition) - { - // Germanium with Feature_TaskbarJumplistOnHover (48980211) - // - 26100.1350, 1591, ... - // 48 8B D7 49 8D 4E C0 E8 ?? ?? ?? ?? 8B - // ^^^^^^^^^^^ - // Ref: CJumpViewExperienceManager::OnViewPropertiesChanging() - matchEnsureWindowPosition = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\x48\x8B\xD7\x49\x8D\x4E\xC0\xE8\x00\x00\x00\x00\x8B", - "xxxxxxxx????x" - ); - if (matchEnsureWindowPosition) - { - matchEnsureWindowPosition += 7; - matchEnsureWindowPosition += 5 + *(int*)(matchEnsureWindowPosition + 1); - } - } -#elif defined(_M_ARM64) - // E1 03 ?? AA ?? 02 01 D1 ?? ?? ?? ?? ?? 03 00 2A - // !! ^^^^^^^^^^^ - // Do not change this to a wildcard, this byte is important - // Ref: CJumpViewExperienceManager::OnViewPropertiesChanging() - PBYTE matchEnsureWindowPosition = (PBYTE)FindPattern( - mi->lpBaseOfDll, - mi->SizeOfImage, - "\xE1\x03\x00\xAA\x00\x02\x01\xD1\x00\x00\x00\x00\x00\x03\x00\x2A", - "xx?x?xxx?????xxx" - ); - if (matchEnsureWindowPosition) - { - matchEnsureWindowPosition += 8; - matchEnsureWindowPosition = (PBYTE)ARM64_FollowBL((DWORD*)matchEnsureWindowPosition); - } -#endif - if (matchEnsureWindowPosition) - { - printf("[JVP] matchEnsureWindowPosition = %llX\n", matchEnsureWindowPosition - (PBYTE)mi->lpBaseOfDll); - } - - if (!matchOffsetTrayStuckPlace - || !matchOffsetRcWorkArea - || !matchEnsureWindowPosition) - { - printf("[JVP] Not all offsets were found, cannot perform patch\n"); - return FALSE; - } - - CJumpViewExperienceManager_EnsureWindowPositionFunc = (decltype(CJumpViewExperienceManager_EnsureWindowPositionFunc))matchEnsureWindowPosition; - funchook_prepare( - funchook, - (void**)&CJumpViewExperienceManager_EnsureWindowPositionFunc, - CJumpViewExperienceManager_EnsureWindowPositionHook - ); - - return TRUE; -} - -#pragma endregion - - -void TryToFindTwinuiPCShellOffsets(DWORD* pOffsets) -{ - // We read from the file instead of from memory because other tweak software might've modified the functions we're looking for - WCHAR wszPath[MAX_PATH]; - GetSystemDirectoryW(wszPath, MAX_PATH); - wcscat_s(wszPath, MAX_PATH, L"\\twinui.pcshell.dll"); - HANDLE hFile = CreateFileW(wszPath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); - if (hFile == INVALID_HANDLE_VALUE) - { - printf("Failed to open twinui.pcshell.dll\n"); - return; - } - - DWORD dwSize = GetFileSize(hFile, nullptr); - PBYTE pFile = (PBYTE)malloc(dwSize); - DWORD dwRead = 0; - if (!ReadFile(hFile, pFile, dwSize, &dwRead, nullptr) || dwRead != dwSize) - { - printf("Failed to read twinui.pcshell.dll\n"); - goto cleanup; - } - - if (IsWindows11()) - { - // All patterns here have been tested to work on: - // - 22621.1, 22621.1992, 22621.2134, 22621.2283, 22621.2359 (RP) - // - 23545.1000 - // - 25951.1000 - - if (!pOffsets[0] || pOffsets[0] == 0xFFFFFFFF) - { -#if defined(_M_X64) - // 48 8B 49 08 E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 48 8B 89 - // ^^^^^^^^^^^ - // Ref: CMultitaskingViewFrame::v_WndProc() - PBYTE match = (PBYTE)FindPattern( - pFile, dwSize, - "\x48\x8B\x49\x08\xE8\x00\x00\x00\x00\xE9\x00\x00\x00\x00\x48\x8B\x89", - "xxxxx????x????xxx" - ); - if (match) - { - match += 4; - pOffsets[0] = (DWORD)(match + 5 + *(int*)(match + 1) - pFile); - } -#elif defined(_M_ARM64) - // ?? AE 00 71 ?? ?? 00 54 ?? 06 40 F9 E3 03 ?? AA E2 03 ?? AA E1 03 ?? 2A ?? ?? ?? ?? - // ^^^^^^^^^^^ - // Ref: CMultitaskingViewFrame::v_WndProc() - PBYTE match = (PBYTE)FindPattern( - pFile, dwSize, - "\xAE\x00\x71\x00\x00\x00\x54\x00\x06\x40\xF9\xE3\x03\x00\xAA\xE2\x03\x00\xAA\xE1\x03\x00\x2A", - "xxx??xx?xxxxx?xxx?xxx?x" - ); - if (match) - { - match += 23; - pOffsets[0] = (DWORD)FileOffsetToRVA(pFile, (PBYTE)ARM64_FollowBL((DWORD*)match) - pFile); - } -#endif - if (pOffsets[0] && pOffsets[0] != 0xFFFFFFFF) - { - printf("CImmersiveContextMenuOwnerDrawHelper::s_ContextMenuWndProc() = %lX\n", pOffsets[0]); - } - } - if (!pOffsets[1] || pOffsets[1] == 0xFFFFFFFF) - { -#if defined(_M_X64) - // Don't worry if this is too long, this works on 17763 and 25951 - // 40 55 53 56 57 41 54 41 55 41 56 41 57 48 8D AC 24 ? ? ? ? 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 85 ? ? ? ? 4C 8B B5 ? ? ? ? 41 8B C1 - PBYTE match = (PBYTE)FindPattern( - pFile, dwSize, - "\x40\x55\x53\x56\x57\x41\x54\x41\x55\x41\x56\x41\x57\x48\x8D\xAC\x24\x00\x00\x00\x00\x48\x81\xEC\x00\x00\x00\x00\x48\x8B\x05\x00\x00\x00\x00\x48\x33\xC4\x48\x89\x85\x00\x00\x00\x00\x4C\x8B\xB5\x00\x00\x00\x00\x41\x8B\xC1", - "xxxxxxxxxxxxxxxxx????xxx????xxx????xxxxxx????xxx????xxx" - ); - if (match) - { - pOffsets[1] = (DWORD)(match - pFile); - } -#elif defined(_M_ARM64) - // 40 F9 43 03 1C 32 E4 03 15 AA ?? ?? FF 97 - // ^^^^^^^^^^^ - // Ref: ImmersiveContextMenuHelper::ApplyOwnerDrawToMenu() - PBYTE match = (PBYTE)FindPattern( - pFile, dwSize, - "\x40\xF9\x43\x03\x1C\x32\xE4\x03\x15\xAA\x00\x00\xFF\x97", - "xxxxxxxxxx??xx" - ); - if (match) - { - match += 10; - pOffsets[1] = (DWORD)FileOffsetToRVA(pFile, (PBYTE)ARM64_FollowBL((DWORD*)match) - pFile); - } -#endif - if (pOffsets[1] && pOffsets[1] != 0xFFFFFFFF) - { - printf("ImmersiveContextMenuHelper::ApplyOwnerDrawToMenu() = %lX\n", pOffsets[1]); - } - } - if (!pOffsets[2] || pOffsets[2] == 0xFFFFFFFF) - { -#if defined(_M_X64) - // 48 89 5C 24 ? 48 89 7C 24 ? 55 48 8B EC 48 83 EC 60 48 8B FA 48 8B D9 E8 - PBYTE match = (PBYTE)FindPattern( - pFile, dwSize, - "\x48\x89\x5C\x24\x00\x48\x89\x7C\x24\x00\x55\x48\x8B\xEC\x48\x83\xEC\x60\x48\x8B\xFA\x48\x8B\xD9\xE8", - "xxxx?xxxx?xxxxxxxxxxxxxxx" - ); - if (match) - { - pOffsets[2] = (DWORD)(match - pFile); - } -#elif defined(_M_ARM64) - // 7F 23 03 D5 F3 53 BF A9 FD 7B BB A9 FD 03 00 91 F3 03 00 AA F4 03 01 AA ?? ?? ?? ?? FF ?? 03 A9 - // ----------- PACIBSP, don't scan for this because it's everywhere - PBYTE match = (PBYTE)FindPattern( - pFile, dwSize, - "\xF3\x53\xBF\xA9\xFD\x7B\xBB\xA9\xFD\x03\x00\x91\xF3\x03\x00\xAA\xF4\x03\x01\xAA\x00\x00\x00\x00\xFF\x00\x03\xA9", - "xxxxxxxxxxxxxxxxxxxx????x?xx" - ); - if (match) - { - match -= 4; - pOffsets[2] = (DWORD)FileOffsetToRVA(pFile, match - pFile); - } -#endif - if (pOffsets[2] && pOffsets[2] != 0xFFFFFFFF) - { - printf("ImmersiveContextMenuHelper::RemoveOwnerDrawFromMenu() = %lX\n", pOffsets[2]); - } - } - if (!pOffsets[3] || pOffsets[3] == 0xFFFFFFFF) - { -#if defined(_M_X64) - // 48 8B ? E8 ? ? ? ? 4C 8B ? 48 8B ? 48 8B CE E8 ? ? ? ? 90 - // ^^^^^^^ - PBYTE match = (PBYTE)FindPattern( - pFile, dwSize, - "\x48\x8B\x00\xE8\x00\x00\x00\x00\x4C\x8B\x00\x48\x8B\x00\x48\x8B\xCE\xE8\x00\x00\x00\x00\x90", - "xx?x????xx?xx?xxxx????x" - ); - if (match) - { - match += 17; - pOffsets[3] = (DWORD)(match + 5 + *(int*)(match + 1) - pFile); - } -#elif defined(_M_ARM64) - // 82 62 00 91 ?? ?? 00 91 E0 03 ?? AA ?? ?? ?? ?? 1F 20 03 D5 - // ^^^^^^^^^^^ - PBYTE match = (PBYTE)FindPattern( - pFile, dwSize, - "\x82\x62\x00\x91\x00\x00\x00\x91\xE0\x03\x00\xAA\x00\x00\x00\x00\x1F\x20\x03\xD5", - "xxxx??xxxx?x????xxxx" - ); - if (match) - { - match += 12; - pOffsets[3] = (DWORD)FileOffsetToRVA(pFile, (PBYTE)ARM64_FollowBL((DWORD*)match) - pFile); - } -#endif - if (pOffsets[3] && pOffsets[3] != 0xFFFFFFFF) - { - printf("CLauncherTipContextMenu::_ExecuteShutdownCommand() = %lX\n", pOffsets[3]); - } - } - if (!pOffsets[4] || pOffsets[4] == 0xFFFFFFFF) - { -#if defined(_M_X64) - // Cobalt: - // 48 89 46 ? 48 8B CB E8 ? ? ? ? 48 8B D3 48 8B CF E8 ? ? ? ? 90 - // ^^^^^^^ - PBYTE match = (PBYTE)FindPattern( - pFile, dwSize, - "\x48\x89\x46\x00\x48\x8B\xCB\xE8\x00\x00\x00\x00\x48\x8B\xD3\x48\x8B\xCF\xE8\x00\x00\x00\x00\x90", - "xxx?xxxx????xxxxxxx????x" - ); - if (match) - { - match += 18; - pOffsets[4] = (DWORD)(match + 5 + *(int*)(match + 1) - pFile); - } - else - { - // Nickel+: - // 48 89 03 48 8B CB E8 ? ? ? ? 48 8B D3 48 8B CF E8 ? ? ? ? 90 - // ^^^^^^^ - match = (PBYTE)FindPattern( - pFile, dwSize, - "\x48\x89\x03\x48\x8B\xCB\xE8\x00\x00\x00\x00\x48\x8B\xD3\x48\x8B\xCF\xE8\x00\x00\x00\x00\x90", - "xxxxxxx????xxxxxxx????x" - ); - if (match) - { - match += 17; - pOffsets[4] = (DWORD)(match + 5 + *(int*)(match + 1) - pFile); - } - } -#elif defined(_M_ARM64) - // 08 09 40 F9 ?? ?? 00 F9 ?? ?? ?? ?? ?? ?? 00 91 E0 03 ?? AA ?? ?? ?? ?? 1F 20 03 D5 - // ^^^^^^^^^^^ - PBYTE match = (PBYTE)FindPattern( - pFile, dwSize, - "\x08\x09\x40\xF9\x00\x00\x00\xF9\x00\x00\x00\x00\x00\x00\x00\x91\xE0\x03\x00\xAA\x00\x00\x00\x00\x1F\x20\x03\xD5", - "xxxx??xx??????xxxx?x????xxxx" - ); - if (match) - { - match += 20; - pOffsets[4] = (DWORD)FileOffsetToRVA(pFile, (PBYTE)ARM64_FollowBL((DWORD*)match) - pFile); - } -#endif - if (pOffsets[4] && pOffsets[4] != 0xFFFFFFFF) - { - printf("CLauncherTipContextMenu::_ExecuteCommand() = %lX\n", pOffsets[4]); - } - } - if (!pOffsets[5] || pOffsets[5] == 0xFFFFFFFF) - { -#if defined(_M_X64) - // Ref: CMultitaskingViewManager::_CreateMTVHost() - // Inlined GetMTVHostKind() - // 4C 89 74 24 ?? ?? 8B ?? ?? 8B ?? 8B D7 48 8B CE E8 ?? ?? ?? ?? 8B - // ^^^^^^^^^^^ - PBYTE match = (PBYTE)FindPattern( - pFile, dwSize, - "\x4C\x89\x74\x24\x00\x00\x8B\x00\x00\x8B\x00\x8B\xD7\x48\x8B\xCE\xE8\x00\x00\x00\x00\x8B", - "xxxx??x??x?xxxxxx????x" - ); - if (match) - { - match += 16; - pOffsets[5] = (DWORD)(match + 5 + *(int*)(match + 1) - pFile); - } - else - { - // Non-inlined GetMTVHostKind() - // 8B CF E8 ?? ?? ?? ?? ?? 89 ?? 24 ?? ?? 8B ?? ?? 8B ?? 8B D7 48 8B CE 83 F8 01 - match = (PBYTE)FindPattern( - pFile, dwSize, - "\x8B\xCF\xE8\x00\x00\x00\x00\x00\x89\x00\x24\x00\x00\x8B\x00\x00\x8B\x00\x8B\xD7\x48\x8B\xCE\x83\xF8\x01", - "xxx?????x?x??x??x?xxxxxxxx" - ); - if (match) - { - PBYTE target = nullptr; - DWORD jnzSize = 0; - if (FollowJnz(match + 26, &target, &jnzSize)) - { - match += 26 + jnzSize; - if (match[0] == 0xE8) - { - pOffsets[5] = (DWORD)(match + 5 + *(int*)(match + 1) - pFile); - } - } - } - } -#elif defined(_M_ARM64) - // F3 53 BE A9 F5 5B 01 A9 FD 7B ?? A9 FD 03 00 91 30 00 80 92 F5 03 04 AA B0 ?? 00 F9 F3 03 00 AA BF 02 00 F9 68 2E 40 F9 F6 03 03 AA B3 23 02 A9 ?? ?? 00 B5 - PBYTE match = (PBYTE)FindPattern( - pFile, dwSize, - "\xF3\x53\xBE\xA9\xF5\x5B\x01\xA9\xFD\x7B\x00\xA9\xFD\x03\x00\x91\x30\x00\x80\x92\xF5\x03\x04\xAA\xB0\x00\x00\xF9\xF3\x03\x00\xAA\xBF\x02\x00\xF9\x68\x2E\x40\xF9\xF6\x03\x03\xAA\xB3\x23\x02\xA9\x00\x00\x00\xB5", - "xxxxxxxxxx?xxxxxxxxxxxxxx?xxxxxxxxxxxxxxxxxxxxxx??xx" - ); - if (match) - { - pOffsets[5] = (DWORD)FileOffsetToRVA(pFile, match - 4 - pFile); - } -#endif - if (pOffsets[5] && pOffsets[5] != 0xFFFFFFFF) - { - printf("CMultitaskingViewManager::_CreateXamlMTVHost() = %lX\n", pOffsets[5]); - } - } - if (!pOffsets[6] || pOffsets[6] == 0xFFFFFFFF) - { -#if defined(_M_X64) - // Ref: CMultitaskingViewManager::_CreateMTVHost() - // Inlined GetMTVHostKind() - // 4C 89 74 24 ?? ?? 8B ?? ?? 8B ?? 8B D7 48 8B CE E8 ?? ?? ?? ?? 90 - // ^^^^^^^^^^^ - PBYTE match = (PBYTE)FindPattern( - pFile, dwSize, - "\x4C\x89\x74\x24\x00\x00\x8B\x00\x00\x8B\x00\x8B\xD7\x48\x8B\xCE\xE8\x00\x00\x00\x00\x90", - "xxxx??x??x?xxxxxx????x" - ); - if (match) - { - match += 16; - pOffsets[6] = (DWORD)(match + 5 + *(int*)(match + 1) - pFile); - } - else - { - // Non-inlined GetMTVHostKind() - // 8B CF E8 ?? ?? ?? ?? ?? 89 ?? 24 ?? ?? 8B ?? ?? 8B ?? 8B D7 48 8B CE 83 F8 01 - match = (PBYTE)FindPattern( - pFile, dwSize, - "\x8B\xCF\xE8\x00\x00\x00\x00\x00\x89\x00\x24\x00\x00\x8B\x00\x00\x8B\x00\x8B\xD7\x48\x8B\xCE\x83\xF8\x01", - "xxx?????x?x??x??x?xxxxxxxx" - ); - if (match) - { - PBYTE target = nullptr; - DWORD jnzSize = 0; - if (FollowJnz(match + 26, &target, &jnzSize) && target[0] == 0xE8) - { - pOffsets[6] = (DWORD)(target + 5 + *(int*)(target + 1) - pFile); - } - } - } -#elif defined(_M_ARM64) - // F3 53 BC A9 F5 5B 01 A9 F7 13 00 F9 F9 17 00 F9 FB 1B 00 F9 FD 7B BC A9 FD 03 00 91 FF ?? 00 D1 30 00 80 92 FB 03 04 AA - PBYTE match = (PBYTE)FindPattern( - pFile, dwSize, - "\xF3\x53\xBC\xA9\xF5\x5B\x01\xA9\xF7\x13\x00\xF9\xF9\x17\x00\xF9\xFB\x1B\x00\xF9\xFD\x7B\xBC\xA9\xFD\x03\x00\x91\xFF\x00\x00\xD1\x30\x00\x80\x92\xFB\x03\x04\xAA", - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx?xxxxxxxxxx" - ); - if (match) - { - pOffsets[6] = (DWORD)FileOffsetToRVA(pFile, match - 4 - pFile); - } -#endif - if (pOffsets[6] && pOffsets[6] != 0xFFFFFFFF) - { - printf("CMultitaskingViewManager::_CreateDCompMTVHost() = %lX\n", pOffsets[6]); - } - } - } - -cleanup: - free(pFile); - CloseHandle(hFile); -} - -extern "C" void RunTwinUIPCShellPatches(symbols_addr* symbols_PTRS) -{ - HMODULE hTwinuiPcshell = LoadLibraryW(L"twinui.pcshell.dll"); - MODULEINFO miTwinuiPcshell; - GetModuleInformation(GetCurrentProcess(), hTwinuiPcshell, &miTwinuiPcshell, sizeof(MODULEINFO)); - - // ZeroMemory(symbols_PTRS->twinui_pcshell_PTRS, sizeof(symbols_PTRS->twinui_pcshell_PTRS)); // Uncomment for testing - TryToFindTwinuiPCShellOffsets(symbols_PTRS->twinui_pcshell_PTRS); - - if (symbols_PTRS->twinui_pcshell_PTRS[0] && symbols_PTRS->twinui_pcshell_PTRS[0] != 0xFFFFFFFF) - { - CImmersiveContextMenuOwnerDrawHelper_s_ContextMenuWndProcFunc = (decltype(CImmersiveContextMenuOwnerDrawHelper_s_ContextMenuWndProcFunc)) - ((uintptr_t)hTwinuiPcshell + symbols_PTRS->twinui_pcshell_PTRS[0]); - } - - if (symbols_PTRS->twinui_pcshell_PTRS[1] && symbols_PTRS->twinui_pcshell_PTRS[1] != 0xFFFFFFFF) - { - ImmersiveContextMenuHelper_ApplyOwnerDrawToMenuFunc = (decltype(ImmersiveContextMenuHelper_ApplyOwnerDrawToMenuFunc)) - ((uintptr_t)hTwinuiPcshell + symbols_PTRS->twinui_pcshell_PTRS[1]); - } - - if (symbols_PTRS->twinui_pcshell_PTRS[2] && symbols_PTRS->twinui_pcshell_PTRS[2] != 0xFFFFFFFF) - { - ImmersiveContextMenuHelper_RemoveOwnerDrawFromMenuFunc = (decltype(ImmersiveContextMenuHelper_RemoveOwnerDrawFromMenuFunc)) - ((uintptr_t)hTwinuiPcshell + symbols_PTRS->twinui_pcshell_PTRS[2]); - } - - if (symbols_PTRS->twinui_pcshell_PTRS[3] && symbols_PTRS->twinui_pcshell_PTRS[3] != 0xFFFFFFFF) - { - CLauncherTipContextMenu_ExecuteShutdownCommandFunc = (decltype(CLauncherTipContextMenu_ExecuteShutdownCommandFunc)) - ((uintptr_t)hTwinuiPcshell + symbols_PTRS->twinui_pcshell_PTRS[3]); - } - - if (symbols_PTRS->twinui_pcshell_PTRS[4] && symbols_PTRS->twinui_pcshell_PTRS[4] != 0xFFFFFFFF) - { - CLauncherTipContextMenu_ExecuteCommandFunc = (decltype(CLauncherTipContextMenu_ExecuteCommandFunc)) - ((uintptr_t)hTwinuiPcshell + symbols_PTRS->twinui_pcshell_PTRS[4]); - } - - int rv; - - if (IsWindows11()) - { - if (bOldTaskbar) - { - typedef HRESULT (WINAPI *DllGetClassObject_t)(REFCLSID rclsid, REFIID riid, LPVOID* ppv); - DllGetClassObject_t pfnDllGetClassObject = (DllGetClassObject_t)GetProcAddress(hTwinuiPcshell, "DllGetClassObject"); - if (pfnDllGetClassObject) - { - IClassFactory* pFactory; - HRESULT hr = pfnDllGetClassObject(__uuidof(CLauncherTipContextMenu), IID_PPV_ARGS(&pFactory)); - if (SUCCEEDED(hr)) - { - void** vtable = *(void***)pFactory; - REPLACE_VTABLE_ENTRY(vtable, 3, CLauncherTipContextMenu_CreateInstance_IClassFactory_); - pFactory->Release(); - } - } - } - - rv = -1; - if (symbols_PTRS->twinui_pcshell_PTRS[5] && symbols_PTRS->twinui_pcshell_PTRS[5] != 0xFFFFFFFF) - { - twinui_pcshell_CMultitaskingViewManager__CreateDCompMTVHostFunc = (decltype(twinui_pcshell_CMultitaskingViewManager__CreateDCompMTVHostFunc)) - ((uintptr_t)hTwinuiPcshell + symbols_PTRS->twinui_pcshell_PTRS[6]); - twinui_pcshell_CMultitaskingViewManager__CreateXamlMTVHostFunc = (decltype(twinui_pcshell_CMultitaskingViewManager__CreateXamlMTVHostFunc)) - ((uintptr_t)hTwinuiPcshell + symbols_PTRS->twinui_pcshell_PTRS[5]); - rv = funchook_prepare( - funchook, - (void**)&twinui_pcshell_CMultitaskingViewManager__CreateXamlMTVHostFunc, - twinui_pcshell_CMultitaskingViewManager__CreateXamlMTVHostHook - ); - } - if (rv != 0) - { - printf("Failed to hook CMultitaskingViewManager::_CreateXamlMTVHost(). rv = %d\n", rv); - } - } - - /*rv = -1; - if (symbols_PTRS->twinui_pcshell_PTRS[TWINUI_PCSHELL_SB_CNT - 1] && symbols_PTRS->twinui_pcshell_PTRS[TWINUI_PCSHELL_SB_CNT - 1] != 0xFFFFFFFF) - { - winrt_Windows_Internal_Shell_implementation_MeetAndChatManager_OnMessageFunc = (INT64(*)(void*, POINT*)) - ((uintptr_t)hTwinuiPcshell + symbols_PTRS->twinui_pcshell_PTRS[TWINUI_PCSHELL_SB_CNT - 1]); - rv = funchook_prepare( - funchook, - (void**)&winrt_Windows_Internal_Shell_implementation_MeetAndChatManager_OnMessageFunc, - winrt_Windows_Internal_Shell_implementation_MeetAndChatManager_OnMessageHook - ); - } - if (rv != 0) - { - printf("Failed to hook winrt_Windows_Internal_Shell_implementation_MeetAndChatManager_OnMessage(). rv = %d\n", rv); - }*/ - -#if USE_MOMENT_3_FIXES_ON_MOMENT_2 - // Use this only for testing, since the RtlQueryFeatureConfiguration() hook is perfect. - // Only tested on 22621.1992. - BOOL bPerformMoment2Patches = IsWindows11Version22H2Build1413OrHigher(); -#else - // This is the only way to fix stuff since the flag "26008830" and the code when it's not enabled are gone. - // Tested on: - // - 22621.2134, 22621.2283, 22621.2359 (RP) - // - 23545.1000 - BOOL bPerformMoment2Patches = IsWindows11Version22H2Build2134OrHigher(); -#endif - if (bOldTaskbar != 1) - { - bPerformMoment2Patches = FALSE; - } - if (bPerformMoment2Patches) - { - // Fix flyout placement: Our goal with these patches is to get `mi.rcWork` assigned - Moment2PatchActionCenter(&miTwinuiPcshell); - Moment2PatchControlCenter(&miTwinuiPcshell); - Moment2PatchToastCenter(&miTwinuiPcshell); - - // Fix task view - Moment2PatchTaskView(&miTwinuiPcshell); - - // Fix volume and brightness popups - HMODULE hHardwareConfirmator = LoadLibraryW(L"Windows.Internal.HardwareConfirmator.dll"); - MODULEINFO miHardwareConfirmator; - GetModuleInformation(GetCurrentProcess(), hHardwareConfirmator, &miHardwareConfirmator, sizeof(MODULEINFO)); - Moment2PatchHardwareConfirmator(&miHardwareConfirmator); - - // Fix pen menu -#if defined(_M_X64) - // 48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 50 49 8B ? 48 81 C1 - PBYTE match = (PBYTE)FindPattern( - hTwinuiPcshell, - miTwinuiPcshell.SizeOfImage, - "\x48\x89\x5C\x24\x00\x48\x89\x74\x24\x00\x57\x48\x83\xEC\x50\x49\x8B\x00\x48\x81\xC1", - "xxxx?xxxx?xxxxxxx?xxx" - ); -#elif defined(_M_ARM64) - PBYTE match = nullptr; -#endif - rv = -1; - if (match) - { - twinui_pcshell_PenMenuSystemTrayManager__GetDynamicSystemTrayHeightForMonitorFunc = (decltype(twinui_pcshell_PenMenuSystemTrayManager__GetDynamicSystemTrayHeightForMonitorFunc))match; - printf("PenMenuSystemTrayManager::GetDynamicSystemTrayHeightForMonitor() = %llX\n", match - (PBYTE)hTwinuiPcshell); - rv = funchook_prepare( - funchook, - (void**)&twinui_pcshell_PenMenuSystemTrayManager__GetDynamicSystemTrayHeightForMonitorFunc, - twinui_pcshell_PenMenuSystemTrayManager__GetDynamicSystemTrayHeightForMonitorHook - ); - } - if (rv != 0) - { - printf("Failed to hook PenMenuSystemTrayManager::GetDynamicSystemTrayHeightForMonitor(). rv = %d\n", rv); - } - } - - if ((global_rovi.dwBuildNumber > 22000 || global_rovi.dwBuildNumber == 22000 && global_ubr >= 65) // Allow on 22000.65+ - && (bOldTaskbar || dwStartShowClassicMode)) - { - // Make sure crash counter is enabled. If one of the patches make Explorer crash while the start menu is open, - // we don't want to softlock the user. The system reopens the start menu if Explorer terminates while it's open. - if (IsCrashCounterEnabled()) - { - if (FixStartMenuAnimation(&miTwinuiPcshell)) - { - ReportSuccessfulAnimationPatching(); - } - } - } - - if (IsWindows11Version22H2OrHigher() && bOldTaskbar) - { - // Fix broken taskbar jump list positioning caused by 40874676 - FixJumpViewPositioning(&miTwinuiPcshell); - } - - VnPatchIAT_NonInline(hTwinuiPcshell, "API-MS-WIN-CORE-REGISTRY-L1-1-0.DLL", "RegGetValueW", (uintptr_t)twinuipcshell_RegGetValueW); - printf("Setup twinui.pcshell functions done\n"); -} +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "ArchiveMenu.h" +#include "utility.h" +#include "hooking.h" +#include "symbols.h" +#include "NativeString.h" +#include "RefCountedObject.h" +#include "SimpleArray.h" + +// #define USE_REIMPLEMENTED_CLauncherTipContextMenu + +using namespace Microsoft::WRL; + + +#pragma region "Types and utilities" + +enum ContextMenuPaddingType +{ + CMPT_NONE = 0x0, + CMPT_TOP_PADDING = 0x1, + CMPT_BOTTOM_PADDING = 0x2, + CMPT_TOUCH_INPUT = 0x4, +}; + +DEFINE_ENUM_FLAG_OPERATORS(ContextMenuPaddingType); + +namespace DPIToPPIHelpers +{ +enum class ScaleType +{ + DPI, + PPI +}; + +enum class ScaleModifier +{ + None, + CorrectBadDPI +}; +} + +struct ContextMenuRenderingData +{ + CoTaskMemNativeString spszText; + DWORD uMenuFlags; + SHSTOCKICONID siid = SIID_MAX_ICONS; + HBITMAP hbmpItem; + HBITMAP hbmpChecked; + HBITMAP hbmpUnchecked; + ContextMenuPaddingType cmpt; + DPIToPPIHelpers::ScaleType scaletype; + UINT xDpi; + bool fUseDarkTheme; + bool fUseSystemPadding; + BOOL fForceAccelerators; + CSimplePointerArrayNewMem* prgParentArray; + +#ifdef _DEBUG +private: + void* operator new(size_t stAllocateBlock) = delete; + +public: + void* operator new(size_t stAllocateBlock, const std::nothrow_t&) + { + return HeapAlloc(GetProcessHeap(), 0, stAllocateBlock); + } + + void operator delete(void* pvMem) + { + operator delete(pvMem, std::nothrow); + } + + void operator delete(void* pvMem, const std::nothrow_t&) + { + if (pvMem) + { + HeapFree(GetProcessHeap(), 0, pvMem); + } + } +#endif +}; + +enum ImmersiveContextMenuOptions +{ + ICMO_NONE = 0x0, + ICMO_USEPPI = 0x1, + ICMO_OVERRIDECOMPATCHECK = 0x2, + ICMO_FORCEMOUSESTYLING = 0x4, + ICMO_USESYSTEMTHEME = 0x8, + ICMO_ICMBRUSHAPPLIED = 0x10, +}; + +DEFINE_ENUM_FLAG_OPERATORS(ImmersiveContextMenuOptions); + +DEFINE_GUID(SID_EdgeUi, 0x0D189B30, 0xF12B, 0x4B13, 0x94, 0xCF, 0x53, 0xCB, 0x0E, 0x0E, 0x24, 0x0D); // 0d189b30-f12b-4b13-94cf-53cb0e0e240d + +interface IImmersiveApplication; +interface IEdgeUiInvocationProvider; + +enum EDGEUI_COMPONENT +{ + EUICMP_UNKNOWN = -1, + EUICMP_SWITCHER = 0, + EUICMP_CHARMSBAR, + EUICMP_APPBAR, + EUICMP_TASKBAR, + EUICMP_TITLEBAR, + EUICMP_TABLETMODEVIEWMANAGER, + EUICMP_ACTIONCENTER, + EUICMP_TOTALCOUNT, +}; + +enum DISMISSED_UI_FLAGS +{ + DUF_NONE = 0x0, + DUF_FORCEOBSERVATIONOFF = 0x1, +}; + +enum EDGEUI_TRAYSTUCKPLACE +{ + EUITSP_UNKNOWN = -1, + EUITSP_LEFT = 0, + EUITSP_TOP, + EUITSP_RIGHT, + EUITSP_BOTTOM, +}; + +MIDL_INTERFACE("6e6c3c52-5a5e-4b4b-a0f8-7fe12621a93e") +IEdgeUiManager : IUnknown +{ + virtual HRESULT STDMETHODCALLTYPE GetTargetApplicationFromPoint(POINT, int, IImmersiveApplication**) = 0; + virtual HRESULT STDMETHODCALLTYPE DismissedUI(EDGEUI_COMPONENT, DISMISSED_UI_FLAGS) = 0; + virtual HRESULT STDMETHODCALLTYPE HandleEdgeGesturePrefChanged(HWND) = 0; + virtual HRESULT STDMETHODCALLTYPE DiscreteInvokeForApp(EDGEUI_COMPONENT, IImmersiveApplication*) = 0; + virtual HRESULT STDMETHODCALLTYPE BeginInputObservation(EDGEUI_COMPONENT) = 0; + virtual HRESULT STDMETHODCALLTYPE GetRegionForCornerOrEdge(EDGEUI_COMPONENT, HRGN*) = 0; + virtual HRESULT STDMETHODCALLTYPE NotifyTrayStuckPlaceChanged(EDGEUI_TRAYSTUCKPLACE) = 0; + virtual HRESULT STDMETHODCALLTYPE GetTrayStuckPlace(EDGEUI_TRAYSTUCKPLACE*) = 0; + virtual HRESULT STDMETHODCALLTYPE NotifyTraySearchBoxVisibilityChanged(BOOL) = 0; + virtual HRESULT STDMETHODCALLTYPE GetTraySearchBoxVisibility(BOOL*) = 0; + virtual HRESULT STDMETHODCALLTYPE NotifyPearlRectChanged(RECT) = 0; + virtual HRESULT STDMETHODCALLTYPE GetPearlRect(RECT*) = 0; + virtual HRESULT STDMETHODCALLTYPE UpdateEdgeWindowZorder() = 0; + virtual HRESULT STDMETHODCALLTYPE ShowStandardSystemOverlays(IImmersiveApplication*) = 0; + virtual HRESULT STDMETHODCALLTYPE OverrideInvocation(IEdgeUiInvocationProvider*) = 0; + virtual HRESULT STDMETHODCALLTYPE NotifyAutohideImmuneWorkAreaMayHaveChanged(RECT) = 0; + virtual HRESULT STDMETHODCALLTYPE GetAutohideImmuneWorkArea(RECT*) = 0; + virtual HRESULT STDMETHODCALLTYPE TaskbarRaised() = 0; + virtual HRESULT STDMETHODCALLTYPE GetTrayRect(RECT*) = 0; +}; + +enum IMMERSIVE_MONITOR_FILTER_FLAGS +{ + IMMERSIVE_MONITOR_FILTER_FLAGS_NONE = 0x0, + IMMERSIVE_MONITOR_FILTER_FLAGS_DISABLE_TRAY = 0x1, +}; + +DEFINE_ENUM_FLAG_OPERATORS(IMMERSIVE_MONITOR_FILTER_FLAGS); + +MIDL_INTERFACE("880b26f8-9197-43d0-8045-8702d0d72000") +IImmersiveMonitor : IUnknown +{ + virtual HRESULT STDMETHODCALLTYPE GetIdentity(DWORD*) = 0; + virtual HRESULT STDMETHODCALLTYPE ConnectObject(IUnknown*) = 0; + virtual HRESULT STDMETHODCALLTYPE GetHandle(HMONITOR*) = 0; + virtual HRESULT STDMETHODCALLTYPE IsConnected(BOOL*) = 0; + virtual HRESULT STDMETHODCALLTYPE IsPrimary(BOOL*) = 0; + virtual HRESULT STDMETHODCALLTYPE IsImmersiveDisplayDevice(BOOL*) = 0; + virtual HRESULT STDMETHODCALLTYPE GetDisplayRect(RECT*) = 0; + virtual HRESULT STDMETHODCALLTYPE GetOrientation(DWORD*) = 0; + virtual HRESULT STDMETHODCALLTYPE GetWorkArea(RECT*) = 0; + virtual HRESULT STDMETHODCALLTYPE IsEqual(IImmersiveMonitor*, BOOL*) = 0; + virtual HRESULT STDMETHODCALLTYPE IsImmersiveCapable(BOOL*) = 0; + virtual HRESULT STDMETHODCALLTYPE GetEffectiveDpi(UINT*, UINT*) = 0; + virtual HRESULT STDMETHODCALLTYPE GetFilterFlags(IMMERSIVE_MONITOR_FILTER_FLAGS*) = 0; +}; + +DEFINE_GUID(SID_IImmersiveMonitorService, 0x47094E3A, 0x0CF2, 0x430F, 0x80, 0x6F, 0xCF, 0x9E, 0x4F, 0x0F, 0x12, 0xDD); // 47094e3a-0cf2-430f-806f-cf9e4f0f12dd + +enum IMMERSIVE_MONITOR_MOVE_DIRECTION +{ + IMMD_PREVIOUS, + IMMD_NEXT, +}; + +interface IImmersiveMonitorFilter; + +MIDL_INTERFACE("4d4c1e64-e410-4faa-bafa-59ca069bfec2") +IImmersiveMonitorManager : IUnknown +{ + virtual HRESULT STDMETHODCALLTYPE GetCount(UINT*) = 0; + virtual HRESULT STDMETHODCALLTYPE GetConnectedCount(UINT*) = 0; + virtual HRESULT STDMETHODCALLTYPE GetAt(UINT, IImmersiveMonitor**) = 0; + virtual HRESULT STDMETHODCALLTYPE GetFromHandle(HMONITOR, IImmersiveMonitor**) = 0; + virtual HRESULT STDMETHODCALLTYPE GetFromIdentity(DWORD, IImmersiveMonitor**) = 0; + virtual HRESULT STDMETHODCALLTYPE GetImmersiveProxyMonitor(IImmersiveMonitor**) = 0; + virtual HRESULT STDMETHODCALLTYPE QueryService(HMONITOR, REFGUID, REFGUID, void**) = 0; + virtual HRESULT STDMETHODCALLTYPE QueryServiceByIdentity(DWORD, REFGUID, REFGUID, void**) = 0; + virtual HRESULT STDMETHODCALLTYPE QueryServiceFromWindow(HWND, REFGUID, REFGUID, void**) = 0; + virtual HRESULT STDMETHODCALLTYPE QueryServiceFromPoint(const POINT*, REFGUID, REFGUID, void**) = 0; + virtual HRESULT STDMETHODCALLTYPE GetNextImmersiveMonitor(IMMERSIVE_MONITOR_MOVE_DIRECTION, IImmersiveMonitor*, IImmersiveMonitor**) = 0; + virtual HRESULT STDMETHODCALLTYPE GetMonitorArray(IObjectArray**) = 0; + virtual HRESULT STDMETHODCALLTYPE SetFilter(IImmersiveMonitorFilter*) = 0; +}; + +DEFINE_GUID(SID_ImmersiveLauncher, 0x6F86E01C, 0xC649, 0x4D61, 0xBE, 0x23, 0xF1, 0x32, 0x2D, 0xDE, 0xCA, 0x9D); // 6f86e01c-c649-4d61-be23-f1322ddeca9d + +enum IMMERSIVELAUNCHERSHOWMETHOD +{ + ILSM_INVALID = 0, + ILSM_HSHELLTASKMAN = 1, + ILSM_IMMERSIVEBACKGROUND = 4, + ILSM_APPCLOSED = 6, + ILSM_STARTBUTTON = 11, + ILSM_RETAILDEMO_EDUCATIONAPP = 12, + ILSM_BACK = 13, + ILSM_SESSIONONUNLOCK = 14, +}; + +enum IMMERSIVELAUNCHERSHOWFLAGS +{ + ILSF_NONE = 0x0, + ILSF_IGNORE_SET_FOREGROUND_ERROR = 0x4, +}; + +DEFINE_ENUM_FLAG_OPERATORS(IMMERSIVELAUNCHERSHOWFLAGS); + +enum IMMERSIVELAUNCHERDISMISSMETHOD +{ + ILDM_INVALID = 0, + ILDM_HSHELLTASKMAN = 1, + ILDM_STARTCHARM = 2, + ILDM_BACKGESTURE = 3, + ILDM_ESCAPEKEY = 4, + ILDM_SHOWDESKTOP = 5, + ILDM_STARTTIP = 6, + ILDM_GENERIC_NONANIMATING = 7, + ILDM_SEARCH_OPENING = 8, + ILDM_DRAG = 9, +}; + +MIDL_INTERFACE("d8d60399-a0f1-f987-5551-321fd1b49864") +IImmersiveLauncher : IUnknown +{ + virtual HRESULT STDMETHODCALLTYPE ShowStartView(IMMERSIVELAUNCHERSHOWMETHOD, IMMERSIVELAUNCHERSHOWFLAGS) = 0; + virtual HRESULT STDMETHODCALLTYPE Dismiss(IMMERSIVELAUNCHERDISMISSMETHOD) = 0; + virtual HRESULT STDMETHODCALLTYPE DismissToLastDesktopApplication(IMMERSIVELAUNCHERDISMISSMETHOD) = 0; + virtual HRESULT STDMETHODCALLTYPE DismissSynchronouslyWithoutTransition() = 0; + virtual HRESULT STDMETHODCALLTYPE IsVisible(BOOL*) = 0; + virtual HRESULT STDMETHODCALLTYPE OnStartButtonPressed(IMMERSIVELAUNCHERSHOWMETHOD, IMMERSIVELAUNCHERDISMISSMETHOD) = 0; + virtual HRESULT STDMETHODCALLTYPE SetForeground() = 0; + virtual HRESULT STDMETHODCALLTYPE ConnectToMonitor(IImmersiveMonitor*) = 0; + virtual HRESULT STDMETHODCALLTYPE GetMonitor(IImmersiveMonitor**) = 0; + virtual HRESULT STDMETHODCALLTYPE OnFirstSignAnimationFinished() = 0; + virtual HRESULT STDMETHODCALLTYPE Prelaunch() = 0; +}; + +MIDL_INTERFACE("b8c1db5f-cbb3-48bc-afd9-ce6b880c79ed") +ILauncherTipContextMenu : IUnknown +{ + virtual HRESULT STDMETHODCALLTYPE ShowLauncherTipContextMenu(POINT*) = 0; + virtual HRESULT STDMETHODCALLTYPE GetMenuItemsAsync(RECT, IUnknown**) = 0; // New in 11 21H2, no GUID change +}; + +inline BOOL IsBiDiLocale(LCID locale) +{ + int info; + int charsRead = GetLocaleInfoW( + locale, + LOCALE_IREADINGLAYOUT | LOCALE_RETURN_NUMBER, + (LPWSTR)&info, + sizeof(info) / sizeof(WCHAR) + ); + return charsRead > 0 ? info == 1 : false; +} + +BOOL Mirror_IsThreadRTL() +{ + return IsBiDiLocale(GetThreadUILanguage()); +} + +enum ZBID : int; +enum ACCENT_STATE : int; + +class CSingleViewShellExperience; + +class SingleViewShellExperiencePersonality; + +class CSingleViewShellExperience +{ +public: + enum class Border + { + None = 0, + Left = 1, + Top = 2, + Right = 4, + Bottom = 8 + }; + + HRESULT SetPosition(const RECT* rect); + + Wrappers::HString _args; + Wrappers::HString _aumid; + Wrappers::HString _experience; + void* _viewWrapper; + ComPtr _propertySet; + int _viewState; + ABI::Windows::Foundation::Size _desiredSize; + BOOLEAN _fullScreen; + bool _isSessionIdle; + DWORD _pid; + ZBID _zbidDefault; + int _pendingViewAction; + int _pendingViewShowFlags; + int _navLevelOverrideHelper[2]; + wistd::unique_ptr m_personality; + // ... +}; + +class SingleViewShellExperiencePersonality +{ +public: + virtual ~SingleViewShellExperiencePersonality() = 0; + virtual bool IsPersonality(void*) = 0; + virtual HRESULT Initialize(IServiceProvider*) = 0; + virtual HRESULT EnableSessionIdleNotifications(IServiceProvider*) = 0; + virtual HRESULT OnViewWrapperChanged() = 0; + virtual HRESULT ShowView() = 0; + virtual HRESULT HideView() = 0; + virtual HRESULT IsViewVisible(bool*) = 0; + virtual HRESULT SetWindowBand(ZBID) = 0; + virtual HRESULT BringToForeground() = 0; + virtual HRESULT BringToFocus() = 0; + virtual HRESULT ShowBorder(CSingleViewShellExperience::Border, ACCENT_STATE, DWORD, const RECT*) = 0; + virtual HRESULT SetPosition(const RECT*) = 0; +}; + +HRESULT CSingleViewShellExperience::SetPosition(const RECT* rect) +{ + RETURN_HR(m_personality->SetPosition(rect)); +} + +namespace ExperienceManagerUtils +{ + void ScaleByDPI(const ABI::Windows::Foundation::Size* size, int dpi, int* outWidth, int* outHeight) + { + *outWidth = MulDiv((int)size->Width, dpi, 96); + *outHeight = MulDiv((int)size->Height, dpi, 96); + } +} + +// Before using this, please make sure that the vtable is in the real module not a stub. +#define REPLACE_VTABLE_ENTRY(vtable, index, name) \ + { \ + auto ppfn = (decltype(&name##Func))&vtable[index]; \ + if (*ppfn != name##Hook) \ + { \ + name##Func = *ppfn; \ + DWORD dwOldProtectLocal; \ + if (VirtualProtect(ppfn, sizeof(void*), PAGE_EXECUTE_READWRITE, &dwOldProtectLocal)) \ + { \ + *ppfn = name##Hook; \ + VirtualProtect(ppfn, sizeof(void*), dwOldProtectLocal, &dwOldProtectLocal); \ + } \ + } \ + } + +#pragma endregion + + +#pragma region "Stuff from dllmain" + +extern "C" +{ + +extern HMODULE hModule; +extern HWND archivehWnd; +extern DWORD bOldTaskbar; +extern DWORD bSkinMenus; +extern DWORD bClockFlyoutOnWinC; +extern DWORD bPropertiesInWinX; +extern DWORD bNoMenuAccelerator; +extern DWORD dwAltTabSettings; +extern DWORD dwSnapAssistSettings; +extern DWORD dwStartShowClassicMode; +extern HANDLE hWin11AltTabInitialized; + +typedef HRESULT(*ImmersiveContextMenuHelper_ApplyOwnerDrawToMenu_t)(HMENU hmenu, HWND hWnd, POINT* pptOrigin, unsigned int icmoFlags, void* srgRenderingData); +extern ImmersiveContextMenuHelper_ApplyOwnerDrawToMenu_t ImmersiveContextMenuHelper_ApplyOwnerDrawToMenuFunc; +typedef void(*ImmersiveContextMenuHelper_RemoveOwnerDrawFromMenu_t)(HMENU hmenu, HWND hwnd); +extern ImmersiveContextMenuHelper_RemoveOwnerDrawFromMenu_t ImmersiveContextMenuHelper_RemoveOwnerDrawFromMenuFunc; +typedef LRESULT(*CImmersiveContextMenuOwnerDrawHelper_s_ContextMenuWndProcFunc_t)(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +extern CImmersiveContextMenuOwnerDrawHelper_s_ContextMenuWndProcFunc_t CImmersiveContextMenuOwnerDrawHelper_s_ContextMenuWndProcFunc; + +BOOL VnPatchIAT_NonInline(HMODULE hMod, const char* libName, const char* funcName, uintptr_t hookAddr); +POINT GetDefaultWinXPosition(BOOL bUseRcWork, BOOL* lpBottom, BOOL* lpRight, BOOL bAdjust, BOOL bToRight); +BOOL InvokeClockFlyout(); +void ReportSuccessfulAnimationPatching(); +BOOL IsCrashCounterEnabled(); + +} // extern "C" + +#pragma endregion + + +#pragma region "twinui.pcshell.dll hooks" + +#define LAUNCHERTIP_CLASS_NAME L"LauncherTipWnd" +#define WINX_ADJUST_X 5 +#define WINX_ADJUST_Y 5 + +class DECLSPEC_UUID("51d1268c-d0a5-47cc-a514-547f346f45e8") +CLauncherTipContextMenu; + +enum LTCMITEMFLAGS +{ + LTCMIF_DEFAULT = 0x0, + LTCMIF_RUNAS = 0x1, + LTCMIF_SWITCHTODESKTOP = 0x2, + LTCMIF_INVOKEARGS = 0x4, + LTCMIF_SHOWDESKTOPCOMMAND = 0x8, + LTCMIF_MOBILITYCENTER = 0x10, + LTCMIF_SEARCHCOMMAND = 0x20, + LTCMIF_PRIMARY_CMD = 0x40, + LTCMIF_SECONDARY_CMD = 0x80, + LTCMIF_POWERSHELLCOMMAND = 0x100, + LTCMIF_SUPPRESSONCLOUD = 0x200, + LTCMIF_ACTIVITIESCOMMAND = 0x400, + LTCMIF_TERMINALCOMMAND = 0x800, // Cobalt +}; + +struct LauncherTipMenuCommand +{ + LauncherTipMenuCommand(); + + bool fSeparator; + CoTaskMemNativeString spszCommandName; + CoTaskMemNativeString spszCommandPath; + CoTaskMemNativeString spszCommandTargetArguments; + CoTaskMemNativeString spszVerb; + DWORD ltcmif; +}; + +struct LauncherTipShutdownMenuCommand +{ + DWORD choice; + CoTaskMemNativeString spszCommandName; +}; + +static HRESULT(*winrt_Windows_Internal_Shell_implementation_MeetAndChatManager_OnMessageFunc)(void* _this, UINT uMsg, WPARAM wParam, LPARAM lParam) = nullptr; +static HRESULT(*CLauncherTipContextMenu_ShowLauncherTipContextMenuFunc)(ILauncherTipContextMenu* _this, POINT* pptLocation) = nullptr; +static void(*CLauncherTipContextMenu_ExecuteCommandFunc)(void* _this, ComPtr> spCommand) = nullptr; +static void(*CLauncherTipContextMenu_ExecuteShutdownCommandFunc)(void* _this, ComPtr> spCommand, const RECT* prcDockTo) = nullptr; + +HWND hWinXWnd; +HANDLE hIsWinXShown; +HANDLE hWinXThread; + +HRESULT CLauncherTipContextMenu_ShowLauncherTipContextMenuHook(ILauncherTipContextMenu* _this, POINT* pt); + +HRESULT (STDMETHODCALLTYPE *CLauncherTipContextMenu_CreateInstance_IClassFactory_Func)( + IClassFactory* This, IUnknown* pUnkOuter, REFIID riid, void** ppvObject); +HRESULT STDMETHODCALLTYPE CLauncherTipContextMenu_CreateInstance_IClassFactory_Hook( + IClassFactory* This, IUnknown* pUnkOuter, REFIID riid, void** ppvObject) +{ +#if defined(USE_REIMPLEMENTED_CLauncherTipContextMenu) + *ppvObject = nullptr; + ComPtr spLTCM; + HRESULT hr = MakeAndInitialize(&spLTCM); + if (SUCCEEDED(hr)) + { + hr = spLTCM.CopyTo(riid, ppvObject); + } + return hr; +#else + HRESULT hr = CLauncherTipContextMenu_CreateInstance_IClassFactory_Func(This, pUnkOuter, riid, ppvObject); + if (SUCCEEDED(hr)) + { + ILauncherTipContextMenu* pLTCM = nullptr; + if (SUCCEEDED(((IUnknown*)*ppvObject)->QueryInterface(IID_PPV_ARGS(&pLTCM)))) // Don't influence hr: if this fails, black screen + { + void** vtable = *(void***)pLTCM; + REPLACE_VTABLE_ENTRY(vtable, 3, CLauncherTipContextMenu_ShowLauncherTipContextMenu); + pLTCM->Release(); + } + } + return hr; +#endif +} + +extern "C" LRESULT CALLBACK CLauncherTipContextMenu_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + LRESULT result; + + if (hWnd == archivehWnd && !ArchiveMenuWndProc( + hWnd, uMsg, wParam, lParam, + ImmersiveContextMenuHelper_ApplyOwnerDrawToMenuFunc, + ImmersiveContextMenuHelper_RemoveOwnerDrawFromMenuFunc + )) + { + return 0; + } + + if (uMsg == WM_NCCREATE) + { + CREATESTRUCT* pCs = (CREATESTRUCT*)lParam; + if (pCs->lpCreateParams) + { + *((HWND*)((char*)pCs->lpCreateParams + 0x78)) = hWnd; + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pCs->lpCreateParams); + result = DefWindowProcW(hWnd, uMsg, wParam, lParam); + } + else + { + result = DefWindowProcW(hWnd, uMsg, wParam, lParam); + //result = 0; + } + } + else + { + void* _this = (void*)GetWindowLongPtrW(hWnd, GWLP_USERDATA); + if ((uMsg == WM_DRAWITEM || uMsg == WM_MEASUREITEM) && + CImmersiveContextMenuOwnerDrawHelper_s_ContextMenuWndProcFunc && + CImmersiveContextMenuOwnerDrawHelper_s_ContextMenuWndProcFunc(hWnd, uMsg, wParam, lParam)) + { + result = 0; + } + else + { + result = DefWindowProcW(hWnd, uMsg, wParam, lParam); + } + if (_this) + { + if (uMsg == WM_NCDESTROY) + { + SetWindowLongPtrW(hWnd, GWLP_USERDATA, 0); + *((HWND*)((char*)_this + 0x78)) = nullptr; + } + } + } + return result; +} + +struct ShowLauncherTipContextMenuParameters +{ + ILauncherTipContextMenu* _this; + POINT point; + ComPtr spOperation; + bool bShouldCenterWinXHorizontally; + + ShowLauncherTipContextMenuParameters(ILauncherTipContextMenu* _this, POINT point, IUnknown* pOperation, bool bShouldCenterWinXHorizontally) + : _this(_this) + , point(point) + , spOperation(pOperation) + , bShouldCenterWinXHorizontally(bShouldCenterWinXHorizontally) + { + } +}; + +DWORD ShowLauncherTipContextMenu(LPVOID lpParams) +{ + ShowLauncherTipContextMenuParameters* params = (ShowLauncherTipContextMenuParameters*)lpParams; + + // Adjust this based on info from: CLauncherTipContextMenu::SetSite + // and CLauncherTipContextMenu::CLauncherTipContextMenu + // 22000.739: 0xe8 + // 22000.778: 0xf0 + // What has happened, between .739 and .778 is that the launcher tip + // context menu object now implements a new interface, ILauncherTipContextMenuMigration; + // thus, members have shifted 8 bytes (one 64-bit value which will hold the + // address of the vtable for this intf at runtime) to the right; + // all this intf seems to do, as of now, is to remove some "obsolete" links + // from the menu (check out "CLauncherTipContextMenu::RunMigrationTasks"); it + // seems you can disable this by setting a DWORD "WinXMigrationLevel" = 1 in + // HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced + int offset_in_class = 0; + if (global_rovi.dwBuildNumber >= 22621 || (global_rovi.dwBuildNumber == 22000 && global_ubr >= 778)) + { + offset_in_class = 8; + } + + char* pClassBase = (char*)params->_this - 0x58; + + struct + { + // ComPtr _spScheduler; + // ComPtr _spWindowMessageService; + // ComPtr _spLauncher; + // ComPtr _spSystemMode; + // ComPtr _spMonitorManager; + CCoSimpleArray>> _rgCommands; + CCoSimpleArray>> _rgShutdownCommands; + RTL_CRITICAL_SECTION _csEnumeration; + RTL_CRITICAL_SECTION _csContextMenuDisplay; + bool _fAreCommandsPopulated; + bool _fCommandPopulationInProgress; + bool _fTasksCancelled; + HMENU _hMenu; + HMENU _hMenuShutdown; + bool _fIsRTL; + bool _fReplacePrimaryCommandsWithSecondary; + }& fields = *(std::remove_reference_t*)(pClassBase + offset_in_class + 0xA8); // Begin at _rgCommands + + static ATOM windowRegistrationAtom = 0; + if (windowRegistrationAtom == 0) + { + WNDCLASS wc = { + .style = CS_DBLCLKS, + .lpfnWndProc = CLauncherTipContextMenu_WndProc, + .hInstance = GetModuleHandleW(nullptr), + .hCursor = LoadCursorW(nullptr, IDC_ARROW), + .hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH), + .lpszClassName = LAUNCHERTIP_CLASS_NAME + }; + ATOM atom = RegisterClassW(&wc); + if (atom) + windowRegistrationAtom = atom; + } + + hWinXWnd = CreateWindowInBand( + 0, + MAKEINTATOM(windowRegistrationAtom), + nullptr, + WS_POPUP, + 0, 0, 0, 0, + nullptr, nullptr, + GetModuleHandle(nullptr), + pClassBase, + 7 // ZBID_IMMERSIVE_EDGY + ); + // DO NOT USE ShowWindow here; it breaks the window order + // and renders the desktop toggle unusable; but leave + // SetForegroundWindow as is so that the menu gets dismissed + // when the user clicks outside it + // + // ShowWindow(hWinXWnd, SW_SHOW); + SetForegroundWindow(hWinXWnd); + + while (!fields._fAreCommandsPopulated) + { + Sleep(1); + } + auto finalize = wil::scope_exit([&]() -> void + { + SendMessageW(hWinXWnd, WM_CLOSE, 0, 0); + hIsWinXShown = nullptr; + delete params; + }); + if (!fields._rgCommands.GetSize()) + { + return 0; + } + + // Check if Windows Terminal is installed + bool fHasTerminal = false; + { + ComPtr spLocalAppDataItem; + HRESULT hr = SHGetKnownFolderItem(FOLDERID_LocalAppData, KF_FLAG_DEFAULT, nullptr, IID_PPV_ARGS(&spLocalAppDataItem)); + if (SUCCEEDED(hr)) + { + ComPtr spTerminalFolderItem; + if (SUCCEEDED(SHCreateItemFromRelativeName(spLocalAppDataItem.Get(), L"Microsoft\\WindowsApps\\wt.exe", nullptr, IID_PPV_ARGS(&spTerminalFolderItem)))) + { + fHasTerminal = true; + } + } + } + + // Do not use the _hMenu built by CLauncherTipContextMenu, it contains *both* PowerShell and Terminal entries. + // When Windows Terminal gets installed/uninstalled, the menu entries should be shown/hidden accordingly without + // restarting Explorer. Win32 does not support hiding menu entries. If we DeleteMenuW the Terminal entries in the + // provided menu due to Terminal not being installed, it will not reappear after Terminal is reinstalled. + // + // We build the menu ourselves to avoid those issues. + // + // Implementation based on: + // - CLauncherTipContextMenu::_EnumerateAndBuildMenu() + // - CLauncherTipContextMenu::_EnumerateAndBuildShutdownMenu() + + wil::unique_hmenu hMenu(CreatePopupMenu()); + wil::unique_hmenu hMenuShutdown; + HRESULT hr = ResultFromWin32Bool(hMenu.is_valid()); + if (SUCCEEDED(hr)) + { + size_t iPlusOne = fields._rgCommands.GetSize(); + if (iPlusOne) + { + for (; iPlusOne; --iPlusOne) + { + size_t iContextMenuCommand = iPlusOne - 1; + ComPtr>& spCommand = fields._rgCommands[iContextMenuCommand]; + + if ((spCommand->ltcmif & LTCMIF_POWERSHELLCOMMAND) != 0 && fHasTerminal + || (spCommand->ltcmif & LTCMIF_TERMINALCOMMAND) != 0 && !fHasTerminal) + { + // Skip if this is PowerShell and Windows Terminal is installed + // or if this is Windows Terminal and Windows Terminal is not installed + continue; + } + + AppendMenuW(hMenu.get(), spCommand->fSeparator ? MF_SEPARATOR : 0, iContextMenuCommand + 1, spCommand->spszCommandName.Get()); + if (iContextMenuCommand == 1) + { + hMenuShutdown.reset(CreatePopupMenu()); + hr = ResultFromWin32Bool(hMenuShutdown != nullptr); + if (SUCCEEDED(hr)) + { + CoTaskMemNativeString spShutdownName; + hr = spShutdownName.Initialize(GetModuleHandleW(L"twinui.pcshell.dll"), 10930); // Sh&ut down or sign out + if (SUCCEEDED(hr)) + { + AppendMenuW(hMenu.get(), MF_POPUP, (DWORD)(UINT_PTR)hMenuShutdown.get(), spShutdownName.Get()); + } + + UINT_PTR uIDNewItem = 4000; + for (size_t i = 0; i < fields._rgShutdownCommands.GetSize(); ++i) + { + ComPtr>& spShutdownCommand = fields._rgShutdownCommands[i]; + AppendMenuW(hMenuShutdown.get(), MF_STRING, uIDNewItem++, spShutdownCommand->spszCommandName.Get()); + } + } + } + } + /*if (ShouldPowershellReplaceCmd()) + { + LauncherTipContextMenuTelemetry::LauncherTipContextMenuDefaultConsole(!_fReplacePrimaryCommandsWithSecondary); + }*/ + } + } + + TCHAR buffer[260]; + LoadStringW(GetModuleHandleW(L"ExplorerFrame.dll"), 50222, buffer + (bNoMenuAccelerator ? 0 : 1), 260); + if (!bNoMenuAccelerator) + { + buffer[0] = L'&'; + } + wchar_t* p = wcschr(buffer, L'('); + if (p) + { + p--; + if (*p == L' ') + { + *p = 0; + } + else + { + p++; + *p = 0; + } + } + + BOOL bCreatedMenu = FALSE; + MENUITEMINFOW menuInfo; + ZeroMemory(&menuInfo, sizeof(MENUITEMINFOW)); + menuInfo.cbSize = sizeof(MENUITEMINFOW); + menuInfo.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA; + menuInfo.wID = 3999; + menuInfo.dwItemData = 0; + menuInfo.fType = MFT_STRING; + menuInfo.dwTypeData = buffer; + menuInfo.cch = (UINT)wcslen(buffer); + if (bPropertiesInWinX) + { + InsertMenuItemW( + hMenu.get(), + GetMenuItemCount(hMenu.get()) - 1, + TRUE, + &menuInfo + ); + bCreatedMenu = TRUE; + } + + CSimplePointerArrayNewMem srgRenderingData; + if (bSkinMenus && ImmersiveContextMenuHelper_ApplyOwnerDrawToMenuFunc) + { + ImmersiveContextMenuHelper_ApplyOwnerDrawToMenuFunc( + hMenu.get(), + hWinXWnd, + ¶ms->point, + ICMO_FORCEMOUSESTYLING | ICMO_USESYSTEMTHEME, + &srgRenderingData + ); + } + + BOOL res = TrackPopupMenu( + hMenu.get(), + TPM_RETURNCMD | TPM_RIGHTBUTTON | (params->bShouldCenterWinXHorizontally ? TPM_CENTERALIGN : 0), + params->point.x, + params->point.y, + 0, + hWinXWnd, + nullptr + ); + + if (bSkinMenus && ImmersiveContextMenuHelper_RemoveOwnerDrawFromMenuFunc) + { + ImmersiveContextMenuHelper_RemoveOwnerDrawFromMenuFunc(hMenu.get(), hWinXWnd); + } + + if (bCreatedMenu) + { + RemoveMenu(hMenu.get(), 3999, MF_BYCOMMAND); + } + + if (res > 0) + { + if (bCreatedMenu && res == 3999) + { + LaunchPropertiesGUI(hModule); + } + else if (res >= 4000) + { + if (CLauncherTipContextMenu_ExecuteShutdownCommandFunc) + { + RECT rcAnchor; + rcAnchor.left = params->point.x; + rcAnchor.top = params->point.y - 1; + rcAnchor.right = rcAnchor.left + 1; + rcAnchor.bottom = rcAnchor.top + 1; + CLauncherTipContextMenu_ExecuteShutdownCommandFunc(pClassBase, fields._rgShutdownCommands[res - 4000], &rcAnchor); + } + } + else + { + if (CLauncherTipContextMenu_ExecuteCommandFunc) + { + CLauncherTipContextMenu_ExecuteCommandFunc(pClassBase, fields._rgCommands[res - 1]); + } + } + } + + return 0; +} + +HRESULT CLauncherTipContextMenu_ShowLauncherTipContextMenuHook(ILauncherTipContextMenu* _this, POINT* pt) +{ + HRESULT hr = S_OK; + + if (hWinXThread) + { + WaitForSingleObject(hWinXThread, INFINITE); + CloseHandle(hWinXThread); + hWinXThread = nullptr; + } + + if (!hIsWinXShown) + { + bool bShouldCenterWinXHorizontally = false; + POINT point; + if (pt) + { + point = *pt; + BOOL bBottom, bRight; + POINT dPt = GetDefaultWinXPosition(FALSE, &bBottom, &bRight, FALSE, FALSE); + POINT posCursor; + GetCursorPos(&posCursor); + RECT rcHitZone; + rcHitZone.left = pt->x - 5; + rcHitZone.right = pt->x + 5; + rcHitZone.top = pt->y - 5; + rcHitZone.bottom = pt->y + 5; + //printf("%d %d = %d %d %d %d\n", posCursor.x, posCursor.y, rcHitZone.left, rcHitZone.right, rcHitZone.top, rcHitZone.bottom); + if (bBottom && IsThemeActive() && PtInRect(&rcHitZone, posCursor) && GetClassWord(WindowFromPoint(point), GCW_ATOM) == RegisterWindowMessageW(L"Start")) + { + HMONITOR hMonitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY); + MONITORINFO mi; + mi.cbSize = sizeof(MONITORINFO); + GetMonitorInfoW(hMonitor, &mi); + HWND hWndUnder = WindowFromPoint(*pt); + TCHAR wszClassName[100]; + ZeroMemory(wszClassName, 100); + GetClassNameW(hWndUnder, wszClassName, 100); + if (!wcscmp(wszClassName, L"Shell_TrayWnd") || !wcscmp(wszClassName, L"Shell_SecondaryTrayWnd")) + { + hWndUnder = FindWindowExW(hWndUnder, nullptr, L"Start", nullptr); + } + RECT rcUnder; + GetWindowRect(hWndUnder, &rcUnder); + if (mi.rcMonitor.left != rcUnder.left) + { + bShouldCenterWinXHorizontally = true; + point.x = rcUnder.left + (rcUnder.right - rcUnder.left) / 2; + point.y = rcUnder.top; + } + else + { + UINT dpiX, dpiY; + GetDpiForMonitor(hMonitor, MDT_DEFAULT, &dpiX, &dpiY); + double dx = dpiX / 96.0, dy = dpiY / 96.0; + BOOL xo = FALSE, yo = FALSE; + if ((int)(point.x - WINX_ADJUST_X * dx) < mi.rcMonitor.left) + { + xo = TRUE; + } + if ((int)(point.y + WINX_ADJUST_Y * dy) > mi.rcMonitor.bottom) + { + yo = TRUE; + } + POINT ptCursor; + GetCursorPos(&ptCursor); + if (xo) + { + ptCursor.x += (int)((WINX_ADJUST_X * 2) * dx); + } + else + { + point.x -= (int)(WINX_ADJUST_X * dx); + } + if (yo) + { + ptCursor.y -= (int)((WINX_ADJUST_Y * 2) * dy); + } + else + { + point.y += (int)(WINX_ADJUST_Y * dy); + } + SetCursorPos(ptCursor.x, ptCursor.y); + } + } + } + else + { + point = GetDefaultWinXPosition(FALSE, nullptr, nullptr, TRUE, FALSE); + } + + RECT rc = {}; + ComPtr spOperation; + hr = _this->GetMenuItemsAsync(rc, &spOperation); + if (SUCCEEDED(hr)) + { + ShowLauncherTipContextMenuParameters* params = new(std::nothrow) ShowLauncherTipContextMenuParameters(_this, point, spOperation.Get(), bShouldCenterWinXHorizontally); + hIsWinXShown = CreateThread(nullptr, 0, ShowLauncherTipContextMenu, params, 0, nullptr); + hWinXThread = hIsWinXShown; + } + } + + if (SUCCEEDED(hr) && CLauncherTipContextMenu_ShowLauncherTipContextMenuFunc) + { + hr = CLauncherTipContextMenu_ShowLauncherTipContextMenuFunc(_this, pt); + } + + return hr; +} + +extern "C" void ToggleLauncherTipContextMenu() +{ + if (hIsWinXShown) + { + SendMessageW(hWinXWnd, WM_CLOSE, 0, 0); + return; + } + + HWND hWnd = FindWindowExW(nullptr, nullptr, L"Shell_TrayWnd", nullptr); + if (!hWnd) + return; + + hWnd = FindWindowExW(hWnd, nullptr, L"Start", nullptr); + if (!hWnd) + return; + + POINT pt = GetDefaultWinXPosition(FALSE, nullptr, nullptr, TRUE, FALSE); + // Finally implemented a variation of + // https://github.com/valinet/ExplorerPatcher/issues/3 + // inspired by how the real Start button activates this menu + // (CPearl::_GetLauncherTipContextMenu) + // This also works when auto hide taskbar is on (#63) + ComPtr pImmersiveShell; + if (SUCCEEDED(CoCreateInstance(CLSID_ImmersiveShell, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pImmersiveShell)))) + { + ComPtr pMonitorService; + if (SUCCEEDED(pImmersiveShell->QueryService(SID_IImmersiveMonitorService, IID_PPV_ARGS(&pMonitorService)))) + { + ComPtr pMenu; + if (SUCCEEDED(pMonitorService->QueryServiceFromWindow(hWnd, __uuidof(ILauncherTipContextMenu), IID_PPV_ARGS(&pMenu)))) + { + pMenu->ShowLauncherTipContextMenu(&pt); + } + } + } +} + +LSTATUS twinuipcshell_RegGetValueW( + HKEY hkey, + LPCWSTR lpSubKey, + LPCWSTR lpValue, + DWORD dwFlags, + LPDWORD pdwType, + PVOID pvData, + LPDWORD pcbData +) +{ + LSTATUS lRes = RegGetValueW(hkey, lpSubKey, lpValue, dwFlags, pdwType, pvData, pcbData); + + if (!lstrcmpW(lpValue, L"AltTabSettings")) + { + if (lRes == ERROR_SUCCESS && *(DWORD*)pvData) + { + if (*(DWORD*)pvData == 3) + { + *(DWORD*)pvData = 0; + } + else + { + *(DWORD*)pvData = 1; + } + } + + if (!bOldTaskbar && hWin11AltTabInitialized) + { + SetEvent(hWin11AltTabInitialized); + CloseHandle(hWin11AltTabInitialized); + hWin11AltTabInitialized = nullptr; + } + + lRes = ERROR_SUCCESS; + } + + return lRes; +} + +HRESULT winrt_Windows_Internal_Shell_implementation_MeetAndChatManager_OnMessageHook(void* _this, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (!bClockFlyoutOnWinC) + { + if (winrt_Windows_Internal_Shell_implementation_MeetAndChatManager_OnMessageFunc) + { + return winrt_Windows_Internal_Shell_implementation_MeetAndChatManager_OnMessageFunc(_this, uMsg, wParam, lParam); + } + return S_OK; + } + if (uMsg == 0x2C2 && wParam == 107) + { + InvokeClockFlyout(); + } + return S_OK; +} + +#pragma endregion + + +#pragma region "Enable old Alt+Tab" + +INT64(*twinui_pcshell_IsUndockedAssetAvailableFunc)(INT a1, INT64 a2, INT64 a3, const char* a4); +INT64 twinui_pcshell_IsUndockedAssetAvailableHook(INT a1, INT64 a2, INT64 a3, const char* a4) +{ + // if IsAltTab and AltTabSettings == Windows 10 or sws (Precision Touchpad gesture) + if (a1 == 1 && (dwAltTabSettings == 3 || dwAltTabSettings == 2)) + { + return 0; + } + // if IsSnapAssist and SnapAssistSettings == Windows 10 + else if (a1 == 4 && dwSnapAssistSettings == 3 && !IsWindows11Version22H2OrHigher()) + { + return 0; + } + // else, show Windows 11 style basically + else + { + if (twinui_pcshell_IsUndockedAssetAvailableFunc) + return twinui_pcshell_IsUndockedAssetAvailableFunc(a1, a2, a3, a4); + return 1; + } +} + +INT64(*twinui_pcshell_CMultitaskingViewManager__CreateDCompMTVHostFunc)(INT64 _this, unsigned int a2, INT64 a3, INT64 a4, INT64* a5); +INT64(*twinui_pcshell_CMultitaskingViewManager__CreateXamlMTVHostFunc)(INT64 _this, unsigned int a2, INT64 a3, INT64 a4, INT64* a5); +INT64 twinui_pcshell_CMultitaskingViewManager__CreateXamlMTVHostHook(INT64 _this, unsigned int a2, INT64 a3, INT64 a4, INT64* a5) +{ + if (!twinui_pcshell_IsUndockedAssetAvailableHook(a2, 0, 0, nullptr)) + return twinui_pcshell_CMultitaskingViewManager__CreateDCompMTVHostFunc(_this, a2, a3, a4, a5); + return twinui_pcshell_CMultitaskingViewManager__CreateXamlMTVHostFunc(_this, a2, a3, a4, a5); +} + +#pragma endregion + + +#pragma region "Fixes related to the removal of STTest feature flag (22621.2134+)" + +HRESULT(*twinui_pcshell_PenMenuSystemTrayManager__GetDynamicSystemTrayHeightForMonitorFunc)(IInspectable* _this, HMONITOR hMonitor, float* outHeight); +HRESULT twinui_pcshell_PenMenuSystemTrayManager__GetDynamicSystemTrayHeightForMonitorHook(IInspectable* _this, HMONITOR hMonitor, float* outHeight) +{ + if (bOldTaskbar) + { + MONITORINFO mi; + mi.cbSize = sizeof(MONITORINFO); + GetMonitorInfoW(hMonitor, &mi); + *outHeight = (float)(mi.rcMonitor.bottom - mi.rcWork.bottom); + return S_OK; + } + return twinui_pcshell_PenMenuSystemTrayManager__GetDynamicSystemTrayHeightForMonitorFunc(_this, hMonitor, outHeight); +} + +static struct +{ + int coroInstance_rcOut; // 22621.1992: 0x10 + int coroInstance_pHardwareConfirmatorHost; // 22621.1992: 0xFD + int hardwareConfirmatorHost_bIsInLockScreen; // 22621.1992: 0xEC +} g_Moment2PatchOffsets; + +#if defined(_M_X64) +inline PBYTE GetTargetOfJzBeforeMe(PBYTE anchor) +{ + // Check big jz + if (*(anchor - 6) == 0x0F && *(anchor - 5) == 0x84) + return anchor + *(int*)(anchor - 4); + // Check small jz + if (*(anchor - 2) == 0x74) + return anchor + *(char*)(anchor - 1); + return nullptr; +} +#endif + +// CActionCenterExperienceManager::GetViewPosition() patcher +BOOL Moment2PatchActionCenter(LPMODULEINFO mi) +{ +#if defined(_M_X64) + // Step 1: + // Scan within the DLL for `*a2 = mi.rcMonitor`. + // ```0F 10 45 ?? F3 0F 7F ?? 80 ?? ?? ?? 00 00 00 // movups - movdqu - cmp``` + // 22621.1992: 7E2F0 + // 22621.2283: 140D5 + PBYTE rcMonitorAssignment = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x0F\x10\x45\x00\xF3\x0F\x7F\x00\x80\x00\x00\x00\x00\x00\x00", "xxx?xxx?x???xxx"); + if (!rcMonitorAssignment) return FALSE; + printf("[AC] rcMonitorAssignment = %llX\n", rcMonitorAssignment - (PBYTE)mi->lpBaseOfDll); + + // 22621.1992 has a different compiled code structure than 22621.2283 therefore we have to use a different approach: + // Short circuiting the `if (26008830 is enabled)`. + // 22621.1992: 7E313 + if (!IsWindows11Version22H2Build2134OrHigher()) // We're on 1413-1992 + { +#if USE_MOMENT_3_FIXES_ON_MOMENT_2 + PBYTE featureCheckJz = rcMonitorAssignment + 35; + if (*featureCheckJz != 0x0F && *(featureCheckJz + 1) != 0x84) return FALSE; + + DWORD dwOldProtect = 0; + PBYTE jzAddr = featureCheckJz + 6 + *(DWORD*)(featureCheckJz + 2); + if (!VirtualProtect(featureCheckJz, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect)) return FALSE; + featureCheckJz[0] = 0xE9; + *(DWORD*)(featureCheckJz + 1) = (DWORD)(jzAddr - featureCheckJz - 5); + VirtualProtect(featureCheckJz, 5, dwOldProtect, &dwOldProtect); + goto done; +#else + return FALSE; +#endif + } + + // Step 2: + // Copy `*a2 = mi.rcMonitor` into right after the first jz starting from step 1. + // Find within couple bytes from step 1: + // ```48 8D // lea``` + // Then offset the first ?? so that it points to mi.rcWork which is 16 bytes after mi.rcMonitor. + // 22621.2283: 140E6 + PBYTE blockBegin = (PBYTE)FindPattern(rcMonitorAssignment + 1, 32, "\x48\x8D", "xx"); + if (!blockBegin) return FALSE; + printf("[AC] blockBegin = %llX\n", blockBegin - (PBYTE)mi->lpBaseOfDll); + + // Step 3: + // Exit the block by writing a long jmp into the address referenced by the jz right before step 3, into right after + // the 8 bytes `rcMonitor = mi.rcWork` we've written. + PBYTE blockEnd = GetTargetOfJzBeforeMe(blockBegin); + if (!blockEnd) return FALSE; + printf("[AC] blockEnd = %llX\n", blockEnd - (PBYTE)mi->lpBaseOfDll); + + // Execution + DWORD dwOldProtect = 0; + if (!VirtualProtect(blockBegin, 8 /**a2 = mi.rcWork*/ + 5 /*jmp*/, PAGE_EXECUTE_READWRITE, &dwOldProtect)) return FALSE; + + // Step 2 + memcpy(blockBegin, rcMonitorAssignment, 8); + blockBegin[3] += offsetof(MONITORINFO, rcWork) - offsetof(MONITORINFO, rcMonitor); + + // Step 3 + PBYTE jmpToEnd = blockBegin + 8; + jmpToEnd[0] = 0xE9; + *(DWORD*)(jmpToEnd + 1) = (DWORD)(blockEnd - jmpToEnd - 5); + + VirtualProtect(blockBegin, 8 + 5, dwOldProtect, &dwOldProtect); + goto done; + +done: + printf("[AC] Patched!\n"); + return TRUE; +#else + return FALSE; +#endif +} + +// CControlCenterExperienceManager::PositionView() patcher +BOOL Moment2PatchControlCenter(LPMODULEINFO mi) +{ +#if defined(_M_X64) + // Step 1: + // Scan within the DLL for `rcMonitor = mi.rcMonitor`. + // ```0F 10 44 24 ?? F3 0F 7F 44 24 ?? 80 // movups - movdqu - cmp``` + // 22621.1992: 4B35B + // 22621.2283: 65C5C + PBYTE rcMonitorAssignment = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x0F\x10\x44\x24\x00\xF3\x0F\x7F\x44\x24\x00\x80", "xxxx?xxxxx?x"); + if (!rcMonitorAssignment) return FALSE; + printf("[CC] rcMonitorAssignment = %llX\n", rcMonitorAssignment - (PBYTE)mi->lpBaseOfDll); + + // Step 2: + // Scan within the function for the 10 bytes long `rcMonitor = mi.rcWork`. + // This pattern applies to both ControlCenter and ToastCenter. + // ```0F 10 45 ?? F3 0F 7F 44 24 ?? 48 // movups - movdqu - test``` + // 22621.1992: 4B3FD and 4B418 (The second one is compiled out in later builds) + // 22621.2283: 65CE6 + PBYTE rcWorkAssignment = (PBYTE)FindPattern(rcMonitorAssignment + 1, 256, "\x0F\x10\x45\x00\xF3\x0F\x7F\x44\x24\x00\x48", "xxx?xxxxx?x"); + if (!rcWorkAssignment) return FALSE; + printf("[CC] rcWorkAssignment = %llX\n", rcWorkAssignment - (PBYTE)mi->lpBaseOfDll); + + // Step 3: + // Copy the `rcMonitor = mi.rcWork` into right after the first jz starting from step 1. + // Find within couple bytes from step 1: + // ```48 8D // lea``` + // 22621.1992: 4B373 + // 22621.2283: 65C74 + PBYTE blockBegin = (PBYTE)FindPattern(rcMonitorAssignment + 1, 32, "\x48\x8D", "xx"); + if (!blockBegin) return FALSE; + printf("[CC] blockBegin = %llX\n", blockBegin - (PBYTE)mi->lpBaseOfDll); + + // Step 4: + // Exit the block by writing a long jmp into the address referenced by the jz right before step 3, into right after + // the 10 bytes `rcMonitor = mi.rcWork` we've written. + PBYTE blockEnd = GetTargetOfJzBeforeMe(blockBegin); + if (!blockEnd) return FALSE; + printf("[CC] blockEnd = %llX\n", blockEnd - (PBYTE)mi->lpBaseOfDll); + + // Execution + DWORD dwOldProtect = 0; + if (!VirtualProtect(blockBegin, 10 /*rcMonitor = mi.rcWork*/ + 5 /*jmp*/, PAGE_EXECUTE_READWRITE, &dwOldProtect)) return FALSE; + + // Step 2 + memcpy(blockBegin, rcWorkAssignment, 10); + + // Step 3 + PBYTE jmpToEnd = blockBegin + 10; + jmpToEnd[0] = 0xE9; + *(DWORD*)(jmpToEnd + 1) = (DWORD)(blockEnd - jmpToEnd - 5); + + VirtualProtect(blockBegin, 10 + 5, dwOldProtect, &dwOldProtect); + + printf("[CC] Patched!\n"); + return TRUE; +#else + return FALSE; +#endif +} + +// CToastCenterExperienceManager::PositionView() patcher +BOOL Moment2PatchToastCenter(LPMODULEINFO mi) +{ +#if defined(_M_X64) + // Step 1: + // Scan within the DLL for `rcMonitor = mi.rcMonitor`. + // + // Pattern 1: + // Will have a match if CToastCenterExperienceManager::ShouldShowWithinWorkArea() is present. + // ```0F 10 45 ?? ?? 0F 7F 44 24 ?? 48 8B CF // movups - movdqu - mov``` + // 22621.1992: 40CE8 + // 22621.2283: 501DB + // + // Pattern 2: + // Will have a match if CToastCenterExperienceManager::ShouldShowWithinWorkArea() is inlined. + // ```0F 10 45 ?? ?? 0F 7F 44 24 ?? 44 38 // movups - movdqu - cmp``` + // 25951.1000: 36B2C4 + // + // Pattern 3: + // Same as pattern 1, but different length of the movdqu instruction. + // ```0F 10 45 ?? ?? 0F 7F 45 ?? 48 8B CF // movups - movdqu - mov``` + // 22621.3066: 3DC340 + // + // Pattern 4: + // Same as pattern 2, but different length of the movdqu instruction. + // ```0F 10 45 ?? ?? 0F 7F 45 ?? 44 38 // movups - movdqu - cmp``` + // No matches yet, just in case. + int assignmentSize = 10; + PBYTE rcMonitorAssignment = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x0F\x10\x45\x00\x00\x0F\x7F\x44\x24\x00\x48\x8B\xCF", "xxx??xxxx?xxx"); + if (!rcMonitorAssignment) + { + rcMonitorAssignment = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x0F\x10\x45\x00\x00\x0F\x7F\x44\x24\x00\x44\x38", "xxx??xxxx?xx"); + if (!rcMonitorAssignment) + { + assignmentSize = 9; + rcMonitorAssignment = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x0F\x10\x45\x00\x00\x0F\x7F\x45\x00\x48\x8B\xCF", "xxx??xxx?xxx"); + if (!rcMonitorAssignment) + { + rcMonitorAssignment = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x0F\x10\x45\x00\x00\x0F\x7F\x45\x00\x44\x38", "xxx??xxx?xx"); + if (!rcMonitorAssignment) return FALSE; + } + } + } + printf("[TC] rcMonitorAssignment = %llX\n", rcMonitorAssignment - (PBYTE)mi->lpBaseOfDll); + + // Step 2: + // Copy the `rcMonitor = mi.rcMonitor` into right after the first jz starting from step 1. + // Find within couple bytes from step 1: + // ```48 8D // lea``` + // Then offset the first ?? so that it points to mi.rcWork which is 16 bytes after mi.rcMonitor. + // 22621.1992: 40D02 + // 22621.2283: 501F5 + PBYTE blockBegin = (PBYTE)FindPattern(rcMonitorAssignment + 1, 32, "\x48\x8D", "xx"); + if (!blockBegin) return FALSE; + printf("[TC] blockBegin = %llX\n", blockBegin - (PBYTE)mi->lpBaseOfDll); + + // Step 3: + // Exit the block by writing a long jmp into the address referenced by the jz right before step 3, into right after + // the bytes `rcMonitor = mi.rcWork` we've written. + // + // Note: We are skipping EdgeUI calls here. + PBYTE blockEnd = GetTargetOfJzBeforeMe(blockBegin); + if (!blockEnd) return FALSE; + printf("[TC] blockEnd = %llX\n", blockEnd - (PBYTE)mi->lpBaseOfDll); + + // Execution + DWORD dwOldProtect = 0; + if (!VirtualProtect(blockBegin, assignmentSize /*rcMonitor = mi.rcWork*/ + 5 /*jmp*/, PAGE_EXECUTE_READWRITE, &dwOldProtect)) return FALSE; + + // Step 2 + memcpy(blockBegin, rcMonitorAssignment, assignmentSize); + blockBegin[3] += offsetof(MONITORINFO, rcWork) - offsetof(MONITORINFO, rcMonitor); + + // Step 3 + PBYTE jmpToEnd = blockBegin + assignmentSize; + jmpToEnd[0] = 0xE9; + *(DWORD*)(jmpToEnd + 1) = (DWORD)(blockEnd - jmpToEnd - 5); + + VirtualProtect(blockBegin, assignmentSize + 5, dwOldProtect, &dwOldProtect); + + printf("[TC] Patched!\n"); + return TRUE; +#else + return FALSE; +#endif +} + +// TaskViewFrame::RuntimeClassInitialize() patcher +BOOL Moment2PatchTaskView(LPMODULEINFO mi) +{ +#if defined(_M_X64) + /*** + If we're using the old taskbar, it'll be stuck in an infinite loading since it's waiting for the new one to respond. + Let's safely skip those by NOPing the `TaskViewFrame::UpdateWorkAreaAsync()` and `WaitForCompletion()` calls, and + turning off the COM object cleanup. + + Step 1: + Scan within the DLL to find the beginning, which is the preparation of the 1st call. + It should be 4C 8B or 4D 8B (mov r8, ...). + For the patterns, they're +1 from the result since it can be either of those. + + Pattern 1: + ```8B ?? 48 8D 55 ?? 48 8B ?? E8 ?? ?? ?? ?? 48 8B 08 E8``` + 22621.1992: 7463C + 22621.2134: 3B29C + + Pattern 2: + ```8B ?? 48 8D 54 24 ?? 48 8B ?? E8 ?? ?? ?? ?? 48 8B 08 E8``` + 22621.2283: 24A1D2 + + Step 2: + In place of the 1st call's call op (E8), overwrite it with a code to set the value of the com_ptr passed into the + 2nd argument (rdx) to 0. This is to skip the cleanup that happens right after the 2nd call. + ```48 C7 02 00 00 00 00 mov qword ptr [rdx], 0``` + Start from -13 of the byte after 2nd call's end. + 22621.1992: 74646 + 22621.2134: 3B2A6 + 22621.2283: 24A1DD + + Step 3: + NOP the rest of the 2nd call. + + Summary: + ``` + 48 8B ?? 48 8D 55 ?? 48 8B ?? E8 ?? ?? ?? ?? 48 8B 08 E8 ?? ?? ?? ?? // Pattern 1 + 48 8B ?? 48 8D 54 24 ?? 48 8B ?? E8 ?? ?? ?? ?? 48 8B 08 E8 ?? ?? ?? ?? // Pattern 2 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ + 1st: TaskViewFrame::UpdateWorkAreaAsync() 2nd: WaitForCompletion() + 48 8B ?? 48 8D 54 24 ?? 48 8B ?? 48 C7 02 00 00 00 00 90 90 90 90 90 90 // Result according to Pattern 2 + -------------------------------- xxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx + We need rdx Step 2 Step 3 + ``` + + Notes: + - In 22621.1992 and 22621.2134, `~AsyncOperationCompletedHandler()` is inlined, while it is not in 22621.2283. We + can see `unconditional_release_ref()` calls right in `RuntimeClassInitialize()` of 1992 and 2134. + - In 22621.2134, there is `33 FF xor edi, edi` before the jz for the inlined cleanup. The value of edi is used in + two more cleanup calls after our area of interest (those covered by twoCallsLength), therefore we can't just NOP + everything. And I think detecting such things is too much work. + ***/ + + int twoCallsLength = 1 + 18 + 4; // 4C/4D + pattern length + 4 bytes for the 2nd call's call address + PBYTE firstCallPrep = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x8B\x00\x48\x8D\x55\x00\x48\x8B\x00\xE8\x00\x00\x00\x00\x48\x8B\x08\xE8", "x?xxx?xx?x????xxxx"); + if (!firstCallPrep) + { + twoCallsLength += 1; // Add 1 to the pattern length + firstCallPrep = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x8B\x00\x48\x8D\x54\x24\x00\x48\x8B\x00\xE8\x00\x00\x00\x00\x48\x8B\x08\xE8", "x?xxxx?xx?x????xxxx"); + if (!firstCallPrep) return FALSE; + } + firstCallPrep -= 1; // Point to the 4C/4D + printf("[TV] firstCallPrep = %llX\n", firstCallPrep - (PBYTE)mi->lpBaseOfDll); + + PBYTE firstCallCall = firstCallPrep + twoCallsLength - 13; + printf("[TV] firstCallCall = %llX\n", firstCallCall - (PBYTE)mi->lpBaseOfDll); + + PBYTE nopBegin = firstCallCall + 7; + + // Execution + DWORD dwOldProtect = 0; + if (!VirtualProtect(firstCallPrep, twoCallsLength, PAGE_EXECUTE_READWRITE, &dwOldProtect)) return FALSE; + const BYTE step2Payload[] = { 0x48, 0xC7, 0x02, 0x00, 0x00, 0x00, 0x00 }; + memcpy(firstCallCall, step2Payload, sizeof(step2Payload)); + memset(nopBegin, 0x90, twoCallsLength - (nopBegin - firstCallPrep)); + VirtualProtect(firstCallPrep, twoCallsLength, dwOldProtect, &dwOldProtect); + + printf("[TV] Patched!\n"); + return TRUE; +#else + return FALSE; +#endif +} + +// Reimplementation of HardwareConfirmatorHost::GetDisplayRect() +void WINAPI HardwareConfirmatorShellcode(PBYTE pCoroInstance) +{ + PBYTE pHardwareConfirmatorHost = *(PBYTE*)(pCoroInstance + g_Moment2PatchOffsets.coroInstance_pHardwareConfirmatorHost); + + RECT rc; + HMONITOR hMonitor = MonitorFromRect(&rc, MONITOR_DEFAULTTOPRIMARY); + + ComPtr pImmersiveShell; + if (SUCCEEDED(CoCreateInstance(CLSID_ImmersiveShell, nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&pImmersiveShell)))) + { + ComPtr pMonitorService; + if (SUCCEEDED(pImmersiveShell->QueryService(SID_IImmersiveMonitorService, IID_PPV_ARGS(&pMonitorService)))) + { + ComPtr pEdgeUiManager; + if (SUCCEEDED(pMonitorService->QueryService(hMonitor, SID_EdgeUi, IID_PPV_ARGS(&pEdgeUiManager)))) + { + if (*(pHardwareConfirmatorHost + g_Moment2PatchOffsets.hardwareConfirmatorHost_bIsInLockScreen)) + { + // Lock screen + MONITORINFO mi; + mi.cbSize = sizeof(MONITORINFO); + if (GetMonitorInfoW(hMonitor, &mi)) + rc = mi.rcMonitor; + } + else + { + // Desktop + LOG_IF_FAILED(pEdgeUiManager->GetAutohideImmuneWorkArea(&rc)); + } + + ABI::Windows::Foundation::Rect* out = (ABI::Windows::Foundation::Rect*)(pCoroInstance + g_Moment2PatchOffsets.coroInstance_rcOut); + out->X = (float)rc.left; + out->Y = (float)rc.top; + out->Width = (float)(rc.right - rc.left); + out->Height = (float)(rc.bottom - rc.top); + } + } + } +} + +// [HardwareConfirmatorHost::GetDisplayRectAsync$_ResumeCoro$1() patcher +BOOL Moment2PatchHardwareConfirmator(LPMODULEINFO mi) +{ +#if defined(_M_X64) + // Find required offsets + + // pHardwareConfirmatorHost and bIsInLockScreen: + // Find in GetDisplayRectAsync$_ResumeCoro$1, inside `case 4:` + // + // 48 8B 83 ED 00 00 00 mov rax, [rbx+0EDh] + // ^^^^^^^^^^^ pHardwareConfirmatorHost + // 8A 80 EC 00 00 00 mov al, [rax+0ECh] + // ^^^^^^^^^^^ bIsInLockScreen + // + // if ( ADJ(this)->pHardwareConfirmatorHost->bIsInLockScreen ) + // if ( *(_BYTE *)(*(_QWORD *)(this + 237) + 236i64) ) // 22621.2283 + // ^ HCH ^ bIsInLockScreen + // + // 22621.2134: 1D55D + PBYTE match1 = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x48\x8B\x83\x00\x00\x00\x00\x8A\x80", "xxx????xx"); + printf("[HC] match1 = %llX\n", match1 - (PBYTE)mi->lpBaseOfDll); + if (!match1) return FALSE; + g_Moment2PatchOffsets.coroInstance_pHardwareConfirmatorHost = *(int*)(match1 + 3); + g_Moment2PatchOffsets.hardwareConfirmatorHost_bIsInLockScreen = *(int*)(match1 + 9); + + // coroInstance_rcOut: + // Also in GetDisplayRectAsync$_ResumeCoro$1, through `case 4:` + // We also use this as the point to jump to, which is the code to set the rect and finish the coroutine. + // + // v27 = *(_OWORD *)(this + 16); + // *(_OWORD *)(this - 16) = v27; + // if ( winrt_suspend_handler ) ... + // + // 0F 10 43 10 movups xmm0, xmmword ptr [rbx+10h] + // ^^ coroInstance_rcOut + // 0F 11 84 24 D0 00 00 00 movups [rsp+158h+var_88], xmm0 + // + // 22621.2134: 1D624 + PBYTE match2 = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x0F\x10\x43\x00\x0F\x11\x84\x24", "xxx?xxxx"); + printf("[HC] match2 = %llX\n", match2 - (PBYTE)mi->lpBaseOfDll); + if (!match2) return FALSE; + g_Moment2PatchOffsets.coroInstance_rcOut = *(match2 + 3); + + // Find where to put the shellcode + // We'll overwrite from this position: + // + // *(_OWORD *)(this + 32) = 0i64; + // *(_QWORD *)(this + 48) = MonitorFromRect((LPCRECT)(this + 32), 1u); + // + // 22621.2134: 1D21E + PBYTE writeAt = (PBYTE)FindPattern(mi->lpBaseOfDll, mi->SizeOfImage, "\x48\x8D\x4B\x00\x0F", "xxx?x"); + if (!writeAt) return FALSE; + printf("[HC] writeAt = %llX\n", writeAt - (PBYTE)mi->lpBaseOfDll); + + // In 22621.2134+, after our jump location there is a cleanup for something we skipped. NOP them. + // From match2, bytes +17 until +37, which is 21 bytes to be NOP'd. + // 22621.2134: 1D635-1D64A + PBYTE cleanupBegin = nullptr, cleanupEnd = nullptr; + if (IsWindows11Version22H2Build2134OrHigher()) + { + cleanupBegin = match2 + 17; + cleanupEnd = match2 + 38; // Exclusive + printf("[HC] cleanup = %llX-%llX\n", cleanupBegin - (PBYTE)mi->lpBaseOfDll, cleanupEnd - (PBYTE)mi->lpBaseOfDll); + if (*cleanupBegin != 0x49 || *cleanupEnd != 0x90 /*Already NOP here*/) return FALSE; + } + + // Craft the shellcode + BYTE shellcode[] = { + // lea rcx, [rbx+0] ; rbx is the `this` which is the instance of the coro, we pass it to our function + 0x48, 0x8D, 0x0B, + // mov rax, 1111111111111111h ; placeholder for the address of HardwareConfirmatorShellcode + 0x48, 0xB8, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + // call rax + 0xFF, 0xD0 + }; + + uintptr_t pattern = 0x1111111111111111; + *(uintptr_t*)(memmem(shellcode, sizeof(shellcode), &pattern, sizeof(uintptr_t))) = (uintptr_t)HardwareConfirmatorShellcode; + + // Execution + DWORD dwOldProtect = 0; + SIZE_T totalSize = sizeof(shellcode) + 5; + if (!VirtualProtect(writeAt, totalSize, PAGE_EXECUTE_READWRITE, &dwOldProtect)) return FALSE; + memcpy(writeAt, shellcode, sizeof(shellcode)); + PBYTE jmpLoc = writeAt + sizeof(shellcode); + jmpLoc[0] = 0xE9; + *(DWORD*)(jmpLoc + 1) = (DWORD)(match2 - jmpLoc - 5); + VirtualProtect(writeAt, totalSize, dwOldProtect, &dwOldProtect); + + if (cleanupBegin) + { + dwOldProtect = 0; + if (!VirtualProtect(cleanupBegin, cleanupEnd - cleanupBegin, PAGE_EXECUTE_READWRITE, &dwOldProtect)) return FALSE; + memset(cleanupBegin, 0x90, cleanupEnd - cleanupBegin); + VirtualProtect(cleanupBegin, cleanupEnd - cleanupBegin, dwOldProtect, &dwOldProtect); + } + + printf("[HC] Patched!\n"); + return TRUE; +#else + return FALSE; +#endif +} + +#pragma endregion + + +#pragma region "Fix broken Windows 10 start menu positioning issues caused by 44656322" + +// Reverts 44656322's effects on the start menu +extern "C" HRESULT CStartExperienceManager_GetMonitorInformationHook(void* _this, CSingleViewShellExperience* experience, RECT* rcOutWorkArea, EDGEUI_TRAYSTUCKPLACE* outTrayStuckPlace, bool* bOutRtl, HMONITOR* hOutMonitor) +{ + *rcOutWorkArea = {}; + *outTrayStuckPlace = EUITSP_BOTTOM; + *bOutRtl = false; + if (hOutMonitor) + *hOutMonitor = nullptr; + + ComPtr spImmersiveShellServiceProvider; + RETURN_IF_FAILED(CoCreateInstance(CLSID_ImmersiveShell, nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&spImmersiveShellServiceProvider))); + + ComPtr spImmersiveLauncher; + RETURN_IF_FAILED(spImmersiveShellServiceProvider->QueryService(SID_ImmersiveLauncher, IID_PPV_ARGS(&spImmersiveLauncher))); + + ComPtr spImmersiveMonitor; + HRESULT hr = spImmersiveLauncher->GetMonitor(&spImmersiveMonitor); + if (FAILED(hr)) + return hr; + + HMONITOR hMonitor = nullptr; + if (hOutMonitor) + hr = spImmersiveMonitor->GetHandle(&hMonitor); + + if (FAILED(hr)) + return hr; + + ComPtr spEdgeUiManager; + hr = IUnknown_QueryService(spImmersiveMonitor.Get(), SID_EdgeUi, IID_PPV_ARGS(&spEdgeUiManager)); + if (FAILED(hr)) + return hr; + + EDGEUI_TRAYSTUCKPLACE trayStuckPlace; + RETURN_IF_FAILED(spEdgeUiManager->GetTrayStuckPlace(&trayStuckPlace)); + + HWND hwndTray = FindWindowW(L"Shell_TrayWnd", nullptr); + + RECT rcWork; + if (hwndTray && GetPropW(hwndTray, L"IsAutoHideEnabled")) + { + RETURN_IF_FAILED(spEdgeUiManager->GetAutohideImmuneWorkArea(&rcWork)); + } + else + { + RETURN_IF_FAILED(spImmersiveMonitor->GetWorkArea(&rcWork)); + } + + *rcOutWorkArea = rcWork; + *outTrayStuckPlace = trayStuckPlace; + *bOutRtl = Mirror_IsThreadRTL() != FALSE; + if (hOutMonitor) + *hOutMonitor = hMonitor; + + return S_OK; +} + +#pragma endregion + + +#pragma region "Fix Windows 10 start menu animation on 22000.65+" + +static struct +{ + int startExperienceManager_IStartExperienceManager; + int startExperienceManager_SingleViewShellExperienceEventHandler; + int startExperienceManager_singleViewShellExperience; + int startExperienceManager_openingAnimation; + int startExperienceManager_closingAnimation; + int startExperienceManager_bTransitioningToCortana; +} g_SMAnimationPatchOffsets; + +// Names taken from Windows.UI.Xaml.pdb, only defining the used ones +enum DWMTRANSITION_TARGET +{ + DWMTARGET_LAUNCHERFLYOUTTOLEFT = 0x4D, + DWMTARGET_LAUNCHERFLYOUTTORIGHT = 0x4E, + DWMTARGET_LAUNCHERFLYOUTTOTOP = 0x4F, + DWMTARGET_LAUNCHERFLYOUTTOBOTTOM = 0x50, + DWMTARGET_LAUNCHERFLYOUT = 0x51, + DWMTARGET_LAUNCHERFULLSCREEN = 0x52, +}; + +DEFINE_ENUM_FLAG_OPERATORS(DWMTRANSITION_TARGET); + +extern HRESULT CStartExperienceManager_GetMonitorInformationHook(void* _this, CSingleViewShellExperience* experience, RECT* rcOutWorkArea, EDGEUI_TRAYSTUCKPLACE* outTrayStuckPlace, bool* bOutRtl, HMONITOR* hOutMonitor); +HRESULT(*CStartExperienceManager_GetMonitorInformationFunc)(void* _this, void* experience, RECT* rcOutWorkArea, EDGEUI_TRAYSTUCKPLACE* outTrayStuckPlace, bool* bOutRtl, HMONITOR* hOutMonitor); +HRESULT(*CExperienceManagerAnimationHelper_BeginFunc)(void* _this, void* pViewWrapper, DWMTRANSITION_TARGET target, const RECT* prcBeginSource, const RECT* prcBeginDestination, const RECT* prcEndSource, const RECT* prcEndDestination, const RECT* prcClip); +HRESULT(*CExperienceManagerAnimationHelper_EndFunc)(void* _this); + +HRESULT(*CStartExperienceManager_OnViewUncloakingFunc)(void* eventHandler, CSingleViewShellExperience* pSender); +HRESULT CStartExperienceManager_OnViewUncloakingHook(void* eventHandler, CSingleViewShellExperience* pSender) +{ + PBYTE _this = (PBYTE)eventHandler - g_SMAnimationPatchOffsets.startExperienceManager_SingleViewShellExperienceEventHandler; + + RECT rcWorkArea; + EDGEUI_TRAYSTUCKPLACE tsp; + bool bRtl; + if (SUCCEEDED(CStartExperienceManager_GetMonitorInformationHook(_this, pSender, &rcWorkArea, &tsp, &bRtl, NULL)) && dwStartShowClassicMode) + { + DWMTRANSITION_TARGET target = DWMTARGET_LAUNCHERFLYOUT; + if (pSender->_fullScreen) + target = DWMTARGET_LAUNCHERFULLSCREEN; + else if (tsp == EUITSP_LEFT) + target = DWMTARGET_LAUNCHERFLYOUTTORIGHT; + else if (tsp == EUITSP_TOP) + target = DWMTARGET_LAUNCHERFLYOUTTOBOTTOM; + else if (tsp == EUITSP_RIGHT) + target = DWMTARGET_LAUNCHERFLYOUTTOLEFT; + else if (tsp == EUITSP_BOTTOM) + target = DWMTARGET_LAUNCHERFLYOUTTOTOP; + + CExperienceManagerAnimationHelper_BeginFunc( + _this + g_SMAnimationPatchOffsets.startExperienceManager_openingAnimation, + pSender->_viewWrapper, + (DWMTRANSITION_TARGET)(target | 0x200000), nullptr, nullptr, nullptr, nullptr, &rcWorkArea); + } + + if (global_rovi.dwBuildNumber >= 25169) + { + // Patch hardcoded EUITSP_BOTTOM present in the original function with the correct value +#if defined(_M_X64) + static int* rgpConstants[2]; + if (!rgpConstants[0] && rgpConstants[0] != (int*)-1) + { + // 03 00 00 00 + PBYTE match = (PBYTE)FindPattern(CStartExperienceManager_OnViewUncloakingFunc, 80, "\x03\x00\x00\x00", "xxxx"); + rgpConstants[0] = match ? (int*)match : (int*)-1; + if (match) + { + match = (PBYTE)FindPattern(match + 4, 40, "\x03\x00\x00\x00", "xxxx"); + rgpConstants[1] = match ? (int*)match : (int*)-1; + } + } + for (int i = 0; i < ARRAYSIZE(rgpConstants); i++) + { + if (rgpConstants[i] && rgpConstants[i] != (int*)-1) + { + DWORD dwOldProtect; + if (VirtualProtect(rgpConstants[i], 4, PAGE_EXECUTE_READWRITE, &dwOldProtect)) + { + *rgpConstants[i] = tsp; + VirtualProtect(rgpConstants[i], 4, dwOldProtect, &dwOldProtect); + } + } + } +#elif defined(_M_ARM64) + static DWORD* rgpInsnMovs[2]; + if (!rgpInsnMovs[0] && rgpInsnMovs[0] != (DWORD*)-1) + { + // 68 00 80 52 + PBYTE match = (PBYTE)FindPattern(CStartExperienceManager_OnViewUncloakingFunc, 160, "\x68\x00\x80\x52", "xxxx"); + rgpInsnMovs[0] = match ? (DWORD*)match : (DWORD*)-1; + if (match) + { + match = (PBYTE)FindPattern(match + 4, 40, "\x68\x00\x80\x52", "xxxx"); + rgpInsnMovs[1] = match ? (DWORD*)match : (DWORD*)-1; + } + } + for (int i = 0; i < ARRAYSIZE(rgpInsnMovs); i++) + { + if (rgpInsnMovs[i] && rgpInsnMovs[i] != (DWORD*)-1) + { + DWORD dwOldProtect; + if (VirtualProtect(rgpInsnMovs[i], 4, PAGE_EXECUTE_READWRITE, &dwOldProtect)) + { + if (ARM64_IsInRange(tsp, 16)) + { + DWORD insn = *rgpInsnMovs[i]; + int imm16Mask = ((1 << 16) - 1) << 5; + insn &= ~imm16Mask; // clear imm16 + insn |= (tsp << 5) & imm16Mask; // set imm16 + *rgpInsnMovs[i] = insn; + } + VirtualProtect(rgpInsnMovs[i], 4, dwOldProtect, &dwOldProtect); + } + } + } +#endif + } + + return CStartExperienceManager_OnViewUncloakingFunc(eventHandler, pSender); +} + +HRESULT(*CStartExperienceManager_OnViewUncloakedFunc)(void* eventHandler, CSingleViewShellExperience* pSender); +HRESULT CStartExperienceManager_OnViewUncloakedHook(void* eventHandler, CSingleViewShellExperience* pSender) +{ + PBYTE _this = (PBYTE)eventHandler - g_SMAnimationPatchOffsets.startExperienceManager_SingleViewShellExperienceEventHandler; + + if (dwStartShowClassicMode) + { + CExperienceManagerAnimationHelper_EndFunc(_this + g_SMAnimationPatchOffsets.startExperienceManager_openingAnimation); + } + + return CStartExperienceManager_OnViewUncloakedFunc(eventHandler, pSender); +} + +HRESULT(*CStartExperienceManager_OnViewCloakingFunc)(void* eventHandler, CSingleViewShellExperience* pSender); +HRESULT CStartExperienceManager_OnViewCloakingHook(void* eventHandler, CSingleViewShellExperience* pSender) +{ + PBYTE _this = (PBYTE)eventHandler - g_SMAnimationPatchOffsets.startExperienceManager_SingleViewShellExperienceEventHandler; + + bool bTransitioningToCortana = *(_this + g_SMAnimationPatchOffsets.startExperienceManager_bTransitioningToCortana); + if (!bTransitioningToCortana && dwStartShowClassicMode) + { + RECT rcWorkArea; + EDGEUI_TRAYSTUCKPLACE tsp; + bool bRtl; + HMONITOR hMonitor; + if (SUCCEEDED(CStartExperienceManager_GetMonitorInformationHook(_this, pSender, &rcWorkArea, &tsp, &bRtl, &hMonitor))) + { + DWMTRANSITION_TARGET target = DWMTARGET_LAUNCHERFLYOUT; + if (pSender->_fullScreen) + target = DWMTARGET_LAUNCHERFULLSCREEN; + else if (tsp == EUITSP_LEFT) + target = DWMTARGET_LAUNCHERFLYOUTTOLEFT; + else if (tsp == EUITSP_TOP) + target = DWMTARGET_LAUNCHERFLYOUTTOTOP; + else if (tsp == EUITSP_RIGHT) + target = DWMTARGET_LAUNCHERFLYOUTTORIGHT; + else if (tsp == EUITSP_BOTTOM) + target = DWMTARGET_LAUNCHERFLYOUTTOBOTTOM; + + CExperienceManagerAnimationHelper_BeginFunc( + _this + g_SMAnimationPatchOffsets.startExperienceManager_closingAnimation, + pSender->_viewWrapper, + (DWMTRANSITION_TARGET)(target | 0x200000), nullptr, nullptr, nullptr, nullptr, &rcWorkArea); + } + } + + return CStartExperienceManager_OnViewCloakingFunc(eventHandler, pSender); +} + +HRESULT(*CStartExperienceManager_OnViewHiddenFunc)(void* eventHandler, CSingleViewShellExperience* pSender); +HRESULT CStartExperienceManager_OnViewHiddenHook(void* eventHandler, CSingleViewShellExperience* pSender) +{ + PBYTE _this = (PBYTE)eventHandler - g_SMAnimationPatchOffsets.startExperienceManager_SingleViewShellExperienceEventHandler; + + bool bTransitioningToCortana = *(_this + g_SMAnimationPatchOffsets.startExperienceManager_bTransitioningToCortana); + if (!bTransitioningToCortana && dwStartShowClassicMode) + { + CExperienceManagerAnimationHelper_EndFunc(_this + g_SMAnimationPatchOffsets.startExperienceManager_closingAnimation); + } + + return CStartExperienceManager_OnViewHiddenFunc(eventHandler, pSender); +} + +BOOL FixStartMenuAnimation(LPMODULEINFO mi) +{ + // The idea here is to re-add the code that got removed in 22000.65+. We can see that "STest03" is the feature flag + // that experiments with the new start menu. So, because in 22000.51 one can enable the old start menu with proper + // behavior by setting the Start_ShowClassicMode registry value to 1, and there is a convenient function called + // `StartDocked::ShouldUseStartDocked()`, we crosscheck the removed code and piece together a patch for proper + // animations on 22000.65+. + + g_SMAnimationPatchOffsets.startExperienceManager_IStartExperienceManager = 0x28; + g_SMAnimationPatchOffsets.startExperienceManager_SingleViewShellExperienceEventHandler = 0x60; + + // ### CStartExperienceManager::`vftable'{for `SingleViewShellExperienceEventHandler'} +#if defined(_M_X64) + // ``` + // 48 89 46 48 48 8D 05 ?? ?? ?? ?? 48 89 46 60 48 8D 4E 68 E8 + // ^^^^^^^^^^^ + // ``` + // Ref: CStartExperienceManager::CStartExperienceManager() + PBYTE matchVtable = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x48\x89\x46\x48\x48\x8D\x05\x00\x00\x00\x00\x48\x89\x46\x60\x48\x8D\x4E\x68\xE8", + "xxxxxxx????xxxxxxxxx" + ); + if (matchVtable) + { + matchVtable += 4; + matchVtable += 7 + *(int*)(matchVtable + 3); + } +#elif defined(_M_ARM64) + // * Pattern for Nickel + // ``` + // 69 A2 03 A9 ?? ?? 00 ?? 08 ?? ?? 91 ?? ?? 00 ?? 29 ?? ?? 91 68 32 00 F9 + // ^^^^^^^^^^^+^^^^^^^^^^^ + // ``` + // Ref: CStartExperienceManager::CStartExperienceManager() + PBYTE matchVtable = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x69\xA2\x03\xA9\x00\x00\x00\x00\x08\x00\x00\x91\x00\x00\x00\x00\x29\x00\x00\x91\x68\x32\x00\xF9", + "xxxx??x?x??x??x?x??xxxxx" + ); + if (matchVtable) + { + matchVtable += 4; + matchVtable = (PBYTE)ARM64_DecodeADRL((UINT_PTR)matchVtable, *(DWORD*)matchVtable, *(DWORD*)(matchVtable + 4)); + } + else + { + // * Pattern for Germanium + // ``` + // ?? 22 04 A9 ?? ?? 00 ?? 08 ?? ?? 91 ?? A2 01 91 ?? 32 00 F9 + // ^^^^^^^^^^^+^^^^^^^^^^^ + // ``` + // Ref: CStartExperienceManager::CStartExperienceManager() + matchVtable = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x22\x04\xA9\x00\x00\x00\x00\x08\x00\x00\x91\x00\xA2\x01\x91\x00\x32\x00\xF9", + "xxx??x?x??x?xxx?xxx" + ); + if (matchVtable) + { + matchVtable += 3; + matchVtable = (PBYTE)ARM64_DecodeADRL((UINT_PTR)matchVtable, *(DWORD*)matchVtable, *(DWORD*)(matchVtable + 4)); + } + } +#endif + if (matchVtable) + { + printf("[SMA] matchVtable = %llX\n", matchVtable - (PBYTE)mi->lpBaseOfDll); + } + + // ### Offset of SingleViewShellExperience instance and its event handler +#if defined(_M_X64) + // ``` + // 48 8D 8E ?? ?? ?? ?? 44 8D 45 41 48 8D 56 60 E8 + // ^^^^^^^^^^^ SVSE ^^ SVSEEH (hardcoded to 0x60, included in pattern for sanity check) + // ``` + // Ref: CStartExperienceManager::CStartExperienceManager() + PBYTE matchSingleViewShellExperienceFields = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x48\x8D\x8E\x00\x00\x00\x00\x44\x8D\x45\x41\x48\x8D\x56\x60\xE8", + "xxx????xxxxxxxxx" + ); + if (matchSingleViewShellExperienceFields) + { + g_SMAnimationPatchOffsets.startExperienceManager_singleViewShellExperience = *(int*)(matchSingleViewShellExperienceFields + 3); + } +#elif defined(_M_ARM64) + // ``` + // 22 08 80 52 ?? 82 01 91 ?? ?? ?? 91 ?? ?? ?? ?? 1F 20 03 D5 + // ^^^SVSEEH^^ ^^^^^^^^^^^ SVSE + // ``` + // Ref: CStartExperienceManager::CStartExperienceManager() + PBYTE matchSingleViewShellExperienceFields = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x22\x08\x80\x52\x00\x82\x01\x91\x00\x00\x00\x91\x00\x00\x00\x00\x1F\x20\x03\xD5", + "xxxx?xxx???x????xxxx" + ); + if (matchSingleViewShellExperienceFields) + { + g_SMAnimationPatchOffsets.startExperienceManager_singleViewShellExperience = (int)ARM64_DecodeADD(*(DWORD*)(matchSingleViewShellExperienceFields + 8)); + } +#endif + if (matchSingleViewShellExperienceFields) + { + printf("[SMA] matchSingleViewShellExperienceFields = %llX\n", matchSingleViewShellExperienceFields - (PBYTE)mi->lpBaseOfDll); + } + + // ### Offsets of Animation Helpers + PBYTE matchAnimationHelperFields = nullptr; +#if defined(_M_X64) + // ``` + // 40 88 AE ?? ?? ?? ?? C7 86 ?? ?? ?? ?? 38 00 00 00 + // ^^^^^^^^^^^ AH1 + // ``` + // Ref: CStartExperienceManager::CStartExperienceManager() + // AH2 is located right after AH1. AH is 32 bytes + if (matchSingleViewShellExperienceFields) + { + matchAnimationHelperFields = (PBYTE)FindPattern( + matchSingleViewShellExperienceFields + 16, + 128, + "\x40\x88\xAE\x00\x00\x00\x00\xC7\x86\x00\x00\x00\x00\x38\x00\x00\x00", + "xxx????xx????xxxx" + ); + } + if (matchAnimationHelperFields) + { + g_SMAnimationPatchOffsets.startExperienceManager_openingAnimation = *(int*)(matchAnimationHelperFields + 3); + g_SMAnimationPatchOffsets.startExperienceManager_closingAnimation = g_SMAnimationPatchOffsets.startExperienceManager_openingAnimation + 32; + } +#elif defined(_M_ARM64) + // ``` + // 08 07 80 52 ?? ?? ?? 39 ?? ?? ?? B9 + // ^^^^^^^^^^^ AH1 + // ``` + // Ref: CStartExperienceManager::CStartExperienceManager() + // AH2 is located right after AH1. AH is 32 bytes + if (matchSingleViewShellExperienceFields) + { + matchAnimationHelperFields = (PBYTE)FindPattern( + matchSingleViewShellExperienceFields + 20, + 128, + "\x08\x07\x80\x52\x00\x00\x00\x39\x00\x00\x00\xB9", + "xxxx???x???x" + ); + } + if (matchAnimationHelperFields) + { + int openingAnimation = (int)ARM64_DecodeSTRBIMM(*(DWORD*)(matchAnimationHelperFields + 4)); + if (openingAnimation != -1) + { + g_SMAnimationPatchOffsets.startExperienceManager_openingAnimation = openingAnimation; + g_SMAnimationPatchOffsets.startExperienceManager_closingAnimation = g_SMAnimationPatchOffsets.startExperienceManager_openingAnimation + 32; + } + else + { + matchAnimationHelperFields = nullptr; + } + } +#endif + if (matchAnimationHelperFields) + { + printf( + "[SMA] matchAnimationHelperFields = %llX, +0x%X, +0x%X\n", + matchAnimationHelperFields - (PBYTE)mi->lpBaseOfDll, + g_SMAnimationPatchOffsets.startExperienceManager_openingAnimation, + g_SMAnimationPatchOffsets.startExperienceManager_closingAnimation + ); + } + + // ### Offset of bTransitioningToCortana +#if defined(_M_X64) + // ``` + // 80 B9 ?? ?? ?? ?? 00 75 ?? 48 83 C1 D8 + // ^^^^^^^^^^^ bTransitioningToCortana + // ``` + // Ref: CStartExperienceManager::DimStart() + PBYTE matchTransitioningToCortanaField = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x80\xB9\x00\x00\x00\x00\x00\x75\x00\x48\x83\xC1\xD8", + "xx????xx?xxxx" + ); + if (matchTransitioningToCortanaField) + { + g_SMAnimationPatchOffsets.startExperienceManager_bTransitioningToCortana = g_SMAnimationPatchOffsets.startExperienceManager_IStartExperienceManager + *(int*)(matchTransitioningToCortanaField + 2); + } +#elif defined(_M_ARM64) + // ``` + // ?? ?? ?? 39 E8 00 00 35 ?? ?? ?? ?? 01 ?? ?? 91 22 00 80 52 + // ^^^^^^^^^^^ bTransitioningToCortana + // ``` + // Ref: CStartExperienceManager::DimStart() + PBYTE matchTransitioningToCortanaField = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x39\xE8\x00\x00\x35\x00\x00\x00\x00\x01\x00\x00\x91\x22\x00\x80\x52", + "xxxxx????x??xxxxx" + ); + if (matchTransitioningToCortanaField) + { + int off = (int)ARM64_DecodeLDRBIMM(*(DWORD*)(matchTransitioningToCortanaField - 3)); + if (off != -1) + { + g_SMAnimationPatchOffsets.startExperienceManager_bTransitioningToCortana = g_SMAnimationPatchOffsets.startExperienceManager_IStartExperienceManager + off; + } + else + { + matchTransitioningToCortanaField = nullptr; + } + } +#endif + if (matchTransitioningToCortanaField) + { + printf("[SMA] matchTransitioningToCortanaField = %llX, +0x%X\n", matchTransitioningToCortanaField - (PBYTE)mi->lpBaseOfDll, g_SMAnimationPatchOffsets.startExperienceManager_bTransitioningToCortana); + } + + // ### Offset of CStartExperienceManager::GetMonitorInformation() +#if defined(_M_X64) + // ``` + // 48 8B ?? E8 ?? ?? ?? ?? 8B ?? 85 C0 0F 88 ?? ?? ?? ?? C6 44 24 ?? 01 + // ^^^^^^^^^^^ + // ``` + // Ref: CStartExperienceManager::PositionMenu() + PBYTE matchGetMonitorInformation = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x48\x8B\x00\xE8\x00\x00\x00\x00\x8B\x00\x85\xC0\x0F\x88\x00\x00\x00\x00\xC6\x44\x24\x00\x01", + "xx?x????x?xxxx????xxx?x" + ); + if (matchGetMonitorInformation) + { + matchGetMonitorInformation += 3; + matchGetMonitorInformation += 5 + *(int*)(matchGetMonitorInformation + 1); + } +#elif defined(_M_ARM64) + // * Pattern for 226xx + // ``` + // E3 ?? 00 91 E2 ?? 00 91 E0 03 13 AA ?? ?? ?? ?? F4 03 00 2A + // ^^^^^^^^^^^ + // ``` + // Ref: CStartExperienceManager::PositionMenu() + PBYTE matchGetMonitorInformation = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\xE3\x00\x00\x91\xE2\x00\x00\x91\xE0\x03\x13\xAA\x00\x00\x00\x00\xF4\x03\x00\x2A", + "x?xxx?xxxxxx????xxxx" + ); + if (matchGetMonitorInformation) + { + matchGetMonitorInformation += 12; + matchGetMonitorInformation = (PBYTE)ARM64_FollowBL((DWORD*)matchGetMonitorInformation); + } + if (!matchGetMonitorInformation) + { + // * Pattern for 26100.1, 265, 470, 560, 670, 712, 751, 863, 1000, 1150 + // ``` + // E2 82 00 91 E1 03 13 AA E0 03 14 AA ?? ?? ?? ?? + // ^^^^^^^^^^^ + // ``` + // Ref: CStartExperienceManager::PositionMenu() + matchGetMonitorInformation = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\xE2\x82\x00\x91\xE1\x03\x13\xAA\xE0\x03\x14\xAA", + "xxxxxxxxxxxx" + ); + if (matchGetMonitorInformation) + { + matchGetMonitorInformation += 12; + matchGetMonitorInformation = (PBYTE)ARM64_FollowBL((DWORD*)matchGetMonitorInformation); + } + } + if (!matchGetMonitorInformation) + { + // * Pattern for 26100.961, 1252, 1301, 1330, 1340, 1350, 1591, ... + // ``` + // FF 02 00 39 E2 82 00 91 E0 03 13 AA ?? ?? ?? ?? + // ^^^^^^^^^^^ + // ``` + // Ref: CStartExperienceManager::PositionMenu() + matchGetMonitorInformation = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\xFF\x02\x00\x39\xE2\x82\x00\x91\xE0\x03\x13\xAA", + "xxxxxxxxxxx" + ); + if (matchGetMonitorInformation) + { + matchGetMonitorInformation += 12; + matchGetMonitorInformation = (PBYTE)ARM64_FollowBL((DWORD*)matchGetMonitorInformation); + } + } +#endif + if (matchGetMonitorInformation) + { + CStartExperienceManager_GetMonitorInformationFunc = (decltype(CStartExperienceManager_GetMonitorInformationFunc))matchGetMonitorInformation; + printf("[SMA] CStartExperienceManager::GetMonitorInformation() = %llX\n", matchGetMonitorInformation - (PBYTE)mi->lpBaseOfDll); + } + + // ### Offset of CExperienceManagerAnimationHelper::Begin() +#if defined(_M_X64) + // * Pattern 1, used when all arguments are available: + // ``` + // 44 8B C7 E8 ?? ?? ?? ?? 85 C0 79 19 + // ^^^^^^^^^^^ + // ``` + // * Pattern 2, used when a4, a5, and a6 are optimized out (e.g. 26020, 26058): + // ``` + // 44 8B C7 48 8D 8B ?? ?? ?? ?? E8 ?? ?? ?? ?? 85 C0 79 19 + // ^^^^^^^^^^^ + // ``` + // Ref: CJumpViewExperienceManager::OnViewUncloaking() + PBYTE matchAnimationBegin = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x44\x8B\xC7\xE8\x00\x00\x00\x00\x85\xC0\x79\x19", + "xxxx????xxxx" + ); + if (matchAnimationBegin) + { + matchAnimationBegin += 3; + matchAnimationBegin += 5 + *(int*)(matchAnimationBegin + 1); + } + else + { + matchAnimationBegin = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x44\x8B\xC7\x48\x8D\x8B\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x85\xC0\x79\x19", + "xxxxxx????x????xxxx" + ); + if (matchAnimationBegin) + { + matchAnimationBegin += 10; + matchAnimationBegin += 5 + *(int*)(matchAnimationBegin + 1); + } + } +#elif defined(_M_ARM64) + // * Pattern 1, used when all arguments are available: + // ``` + // 04 00 80 D2 03 00 80 D2 60 C2 05 91 ?? ?? ?? ?? E3 03 00 2A + // ^^^^^^^^^^^ + // ``` + // Ref: CJumpViewExperienceManager::OnViewUncloaking() + PBYTE matchAnimationBegin = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x04\x00\x80\xD2\x03\x00\x80\xD2\x60\xC2\x05\x91\x00\x00\x00\x00\xE3\x03\x00\x2A", + "xxxxxxxxxxxx????xxxx" + ); + if (matchAnimationBegin) + { + matchAnimationBegin += 12; + matchAnimationBegin = (PBYTE)ARM64_FollowBL((DWORD*)matchAnimationBegin); + } + else + { + // * Pattern 2, used when a4, a5, and a6 are optimized out (e.g. 26020, 26058): + // ``` + // ?? 02 0B 32 ?? ?? ?? 91 ?? ?? ?? 91 ?? ?? ?? ?? E3 03 00 2A + // ^^^^^^^^^^^ + // ``` + // Ref: CJumpViewExperienceManager::OnViewUncloaking() + matchAnimationBegin = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x02\x0B\x32\00\x00\x00\x91\x00\x00\x00\x91\x00\x00\x00\x00\xE3\x03\x00\x2A", + "xxx???x???x????xxxx" + ); + if (matchAnimationBegin) + { + matchAnimationBegin += 11; + matchAnimationBegin = (PBYTE)ARM64_FollowBL((DWORD*)matchAnimationBegin); + } + } +#endif + if (matchAnimationBegin) + { + CExperienceManagerAnimationHelper_BeginFunc = (decltype(CExperienceManagerAnimationHelper_BeginFunc))matchAnimationBegin; + printf("[SMA] CExperienceManagerAnimationHelper::Begin() = %llX\n", matchAnimationBegin - (PBYTE)mi->lpBaseOfDll); + } + + // ### Offset of CExperienceManagerAnimationHelper::End() +#if defined(_M_X64) + // ``` + // 40 53 48 83 EC 20 80 39 00 74 + // ``` + PBYTE matchAnimationEnd = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x40\x53\x48\x83\xEC\x20\x80\x39\x00\x74", + "xxxxxxxxxx" + ); +#elif defined(_M_ARM64) + // ``` + // 7F 23 03 D5 F3 0F 1F F8 FD 7B BF A9 FD 03 00 91 08 00 40 39 + // ----------- PACIBSP, don't scan for this because it's everywhere + // ``` + PBYTE matchAnimationEnd = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\xF3\x0F\x1F\xF8\xFD\x7B\xBF\xA9\xFD\x03\x00\x91\x08\x00\x40\x39", + "xxxxxxxxxxxxxxxx" + ); + if (matchAnimationEnd) + { + matchAnimationEnd -= 4; + } +#endif + if (matchAnimationEnd) + { + CExperienceManagerAnimationHelper_EndFunc = (decltype(CExperienceManagerAnimationHelper_EndFunc))matchAnimationEnd; + printf("[SMA] CExperienceManagerAnimationHelper::End() = %llX\n", matchAnimationEnd - (PBYTE)mi->lpBaseOfDll); + } + + // ### CStartExperienceManager::Hide() +#if defined(_M_X64) + // * Pattern 1, mov [rbx+2A3h], r12b: + // ``` + // 74 ?? ?? 03 00 00 00 44 88 + // ^^ Turn jz into jmp + // ``` + // * Pattern 2, mov byte ptr [rbx+2A3h], 1: + // ``` + // 74 ?? ?? 03 00 00 00 C6 83 + // ^^ Turn jz into jmp + // ``` + // Perform on exactly two matches + PBYTE matchHideA = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x74\x00\x00\x03\x00\x00\x00\x44\x88", + "x??xxxxxx" + ); + PBYTE matchHideB = nullptr; + if (matchHideA) + { + printf("[SMA] matchHideA in CStartExperienceManager::Hide() = %llX\n", matchHideA - (PBYTE)mi->lpBaseOfDll); + matchHideB = (PBYTE)FindPattern( + matchHideA + 14, + mi->SizeOfImage - (matchHideA + 14 - (PBYTE)mi->lpBaseOfDll), + "\x74\x00\x00\x03\x00\x00\x00\x44\x88", + "x??xxxxxx" + ); + if (matchHideB) + { + printf("[SMA] matchHideB in CStartExperienceManager::Hide() = %llX\n", matchHideB - (PBYTE)mi->lpBaseOfDll); + } + } + + if (!matchHideA || !matchHideB) + { + matchHideA = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x74\x00\x00\x03\x00\x00\x00\xC6\x83", + "x??xxxxxx" + ); + matchHideB = nullptr; + if (matchHideA) + { + printf("[SMA] matchHideA in CStartExperienceManager::Hide() = %llX\n", matchHideA - (PBYTE)mi->lpBaseOfDll); + matchHideB = (PBYTE)FindPattern( + matchHideA + 14, + mi->SizeOfImage - (matchHideA + 14 - (PBYTE)mi->lpBaseOfDll), + "\x74\x00\x00\x03\x00\x00\x00\xC6\x83", + "x??xxxxxx" + ); + if (matchHideB) + { + printf("[SMA] matchHideB in CStartExperienceManager::Hide() = %llX\n", matchHideB - (PBYTE)mi->lpBaseOfDll); + } + } + } +#elif defined(_M_ARM64) + // ``` + // E1 03 ?? 2A ?? ?? 04 91 ?? ?? ?? ?? ?? 03 00 2A + // ``` + // Check two instructions before, and NOP these: + // ``` + // MOV W??, #3 + // STRB W??, [X??,#0x???] + // ``` + // Perform on exactly two matches + PBYTE matchHideA = nullptr; + PBYTE matchHideB = nullptr; + auto findTheIfBody = [](PBYTE pAnchor) -> PBYTE + { + // 27881.1000+ has CBNZ before us, follow it if it is. + // Otherwise, just check the two instructions before. + PBYTE pMaybeFollowed = (PBYTE)ARM64_FollowCBNZW((DWORD*)(pAnchor - 4)); + PBYTE pIfBlockBegin = pMaybeFollowed ? pMaybeFollowed : pAnchor - 8; + + DWORD insnMovzw = *(DWORD*)pIfBlockBegin; + if (!ARM64_IsMOVZW(insnMovzw)) + return nullptr; + + DWORD movzwImm16 = ARM64_ReadBitsSignExtend(insnMovzw, 20, 5); + if (movzwImm16 != 3) + return nullptr; + + DWORD insnStrbimm = *(DWORD*)(pIfBlockBegin + 4); + if (!ARM64_IsSTRBIMM(insnStrbimm)) + return nullptr; + + return pIfBlockBegin; + }; + PBYTE matchHideAAfter = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\xE1\x03\x00\x2A\x00\x00\x04\x91\x00\x00\x00\x00\x00\x03\x00\x2A", + "xx?x??xx?????xxx" + ); + if (matchHideAAfter) + { + matchHideA = findTheIfBody(matchHideAAfter); + } + if (matchHideA) + { + printf("[SMA] matchHideA in CStartExperienceManager::Hide() = %llX\n", matchHideA - (PBYTE)mi->lpBaseOfDll); + PBYTE matchHideBAfter = (PBYTE)FindPattern( + matchHideAAfter + 16, + 1024, + "\xE1\x03\x00\x2A\x00\x00\x04\x91\x00\x00\x00\x00\x00\x03\x00\x2A", + "xx?x??xx?????xxx" + ); + if (matchHideBAfter) + { + matchHideB = findTheIfBody(matchHideBAfter); + } + if (matchHideB) + { + printf("[SMA] matchHideB in CStartExperienceManager::Hide() = %llX\n", matchHideB - (PBYTE)mi->lpBaseOfDll); + } + } +#endif + + if (!matchVtable + || !matchSingleViewShellExperienceFields + || !matchAnimationHelperFields + || !matchTransitioningToCortanaField + || !matchGetMonitorInformation + || !matchAnimationBegin + || !matchAnimationEnd + || !matchHideA + || !matchHideB) + { + printf("[SMA] Not all offsets were found, cannot perform patch\n"); + return FALSE; + } + + void** vtable = (void**)matchVtable; + REPLACE_VTABLE_ENTRY(vtable, 4, CStartExperienceManager_OnViewUncloaking); + REPLACE_VTABLE_ENTRY(vtable, 5, CStartExperienceManager_OnViewUncloaked); + REPLACE_VTABLE_ENTRY(vtable, 6, CStartExperienceManager_OnViewCloaking); + REPLACE_VTABLE_ENTRY(vtable, 10, CStartExperienceManager_OnViewHidden); + + if (dwStartShowClassicMode) + { + DWORD dwOldProtect = 0; +#if defined(_M_X64) + if (VirtualProtect(matchHideA, 1, PAGE_EXECUTE_READWRITE, &dwOldProtect)) + { + matchHideA[0] = 0xEB; + VirtualProtect(matchHideA, 1, dwOldProtect, &dwOldProtect); + + dwOldProtect = 0; + if (VirtualProtect(matchHideB, 1, PAGE_EXECUTE_READWRITE, &dwOldProtect)) + { + matchHideB[0] = 0xEB; + VirtualProtect(matchHideB, 1, dwOldProtect, &dwOldProtect); + } + } +#elif defined(_M_ARM64) + if (VirtualProtect(matchHideA, 8, PAGE_EXECUTE_READWRITE, &dwOldProtect)) + { + *(DWORD*)(matchHideA + 0) = 0xD503201F; // NOP + *(DWORD*)(matchHideA + 4) = 0xD503201F; // NOP + VirtualProtect(matchHideA, 8, dwOldProtect, &dwOldProtect); + + dwOldProtect = 0; + if (VirtualProtect(matchHideB, 8, PAGE_EXECUTE_READWRITE, &dwOldProtect)) + { + *(DWORD*)(matchHideB + 0) = 0xD503201F; // NOP + *(DWORD*)(matchHideB + 4) = 0xD503201F; // NOP + VirtualProtect(matchHideB, 8, dwOldProtect, &dwOldProtect); + } + } +#endif + } + + int rv = -1; + if (CStartExperienceManager_GetMonitorInformationFunc) + { + rv = funchook_prepare( + funchook, + (void**)&CStartExperienceManager_GetMonitorInformationFunc, + CStartExperienceManager_GetMonitorInformationHook + ); + } + if (rv != 0) + { + printf("Failed to hook CStartExperienceManager::GetMonitorInformation(). rv = %d\n", rv); + } + + return TRUE; +} + +#pragma endregion + + +#pragma region "Fix broken taskbar jump list positioning caused by 40874676" + +class RoVariant +{ + enum States + { + StateIsNull = 0, + StateIsObjNoRef = 1, + StateIsObj = 3, + StateIsPV = 7 + }; + + static bool StateHasRefcount(HRESULT hrState) + { + return hrState == StateIsPV || hrState == StateIsObj; + } + + class Accessor + { + IInspectable* _pI; + HRESULT _hrState; + + ABI::Windows::Foundation::IPropertyValue* _PV() const + { + return (ABI::Windows::Foundation::IPropertyValue*)_pI; + } + + HRESULT VerifyPV() const + { + if (_hrState == StateIsPV) + return S_OK; + if (SUCCEEDED(_hrState)) + return TYPE_E_TYPEMISMATCH; + return _hrState; + } + + public: + Accessor(IInspectable* pI, HRESULT hr) : _pI(pI), _hrState(hr) {} + Accessor* operator->() { return this; } + HRESULT get_Type(ABI::Windows::Foundation::PropertyType* type) const; + + #define GETTER(name, type) HRESULT Get##name(type* value) const \ + { \ + if (!value) \ + return E_POINTER; \ + *value = {}; \ + HRESULT hr = VerifyPV(); \ + if (SUCCEEDED(hr)) \ + hr = _PV()->Get##name(value); \ + return hr; \ + } + + GETTER(UInt8, UINT8); + GETTER(Int16, INT16); + GETTER(UInt16, UINT16); + GETTER(Int32, INT32); + GETTER(UInt32, UINT32); + GETTER(Int64, INT64); + GETTER(UInt64, UINT64); + GETTER(Single, float); + GETTER(Double, double); + GETTER(Char16, WCHAR); + GETTER(Boolean, BOOLEAN); + GETTER(String, HSTRING); + GETTER(Guid, GUID); + GETTER(DateTime, ABI::Windows::Foundation::DateTime); + GETTER(TimeSpan, ABI::Windows::Foundation::TimeSpan); + GETTER(Point, ABI::Windows::Foundation::Point); + GETTER(Size, ABI::Windows::Foundation::Size); + GETTER(Rect, ABI::Windows::Foundation::Rect); + + #undef GETTER + + HRESULT GetInspectable(IInspectable** value) const + { + if (!value) + return E_POINTER; + *value = nullptr; + HRESULT hr = _hrState; + if (SUCCEEDED(hr)) + { + if (hr != StateIsNull && (hr == StateIsObj || hr == StateIsObjNoRef)) + { + *value = _pI; + _pI->AddRef(); + hr = S_OK; + } + else + { + hr = TYPE_E_TYPEMISMATCH; + } + } + return hr; + } + + #define GETTER_ARRAY(name, type) HRESULT Get##name##Array(UINT* length, type** value) const \ + { \ + if (!length || !value) \ + return E_POINTER; \ + *length = 0; \ + *value = nullptr; \ + HRESULT hr = VerifyPV(); \ + if (SUCCEEDED(hr)) \ + hr = _PV()->Get##name##Array(length, value); \ + return hr; \ + } + + GETTER_ARRAY(UInt8, UINT8); + GETTER_ARRAY(Int16, INT16); + GETTER_ARRAY(UInt16, UINT16); + GETTER_ARRAY(Int32, INT32); + GETTER_ARRAY(UInt32, UINT32); + GETTER_ARRAY(Int64, INT64); + GETTER_ARRAY(UInt64, UINT64); + GETTER_ARRAY(Single, float); + GETTER_ARRAY(Double, double); + GETTER_ARRAY(Char16, WCHAR); + GETTER_ARRAY(Boolean, BOOLEAN); + GETTER_ARRAY(String, HSTRING); + GETTER_ARRAY(Inspectable, IInspectable*); + GETTER_ARRAY(Guid, GUID); + GETTER_ARRAY(DateTime, ABI::Windows::Foundation::DateTime); + GETTER_ARRAY(TimeSpan, ABI::Windows::Foundation::TimeSpan); + GETTER_ARRAY(Point, ABI::Windows::Foundation::Point); + GETTER_ARRAY(Size, ABI::Windows::Foundation::Size); + GETTER_ARRAY(Rect, ABI::Windows::Foundation::Rect); + + #undef GETTER_ARRAY + }; + + class OutRef + { + RoVariant* _pOwner; + IInspectable* _pI; + + public: + OutRef(RoVariant* pOwner) : _pOwner(pOwner), _pI(nullptr) {} + operator ABI::Windows::Foundation::IPropertyValue**() { return (ABI::Windows::Foundation::IPropertyValue**)&_pI; } + operator IInspectable**() { return &_pI; } + ~OutRef() { _pOwner->Attach(_pI); } + }; + + IInspectable* _pI = nullptr; + HRESULT _hrState = StateIsNull; + +public: + RoVariant() = default; + RoVariant(RoVariant*); + RoVariant(RoVariant&); + RoVariant(ABI::Windows::Foundation::IPropertyValue*, bool); + +private: + RoVariant(IInspectable* pI, bool fAddRefInspectable, bool attach) + { + if (pI) + { + ABI::Windows::Foundation::IPropertyValue* pPV; + HRESULT hr = pI->QueryInterface(IID_PPV_ARGS(&pPV)); + if (SUCCEEDED(hr)) + { + _pI = pPV; + if (attach) + pI->Release(); + _hrState = StateIsPV; + } + else if (hr != E_NOINTERFACE) + { + _pI = nullptr; + _hrState = hr; + if (attach) + pI->Release(); + } + else + { + _pI = pI; + if (fAddRefInspectable && !attach) + _pI->AddRef(); + _hrState = fAddRefInspectable ? StateIsObj : StateIsObjNoRef; + } + } + else + { + _pI = nullptr; + _hrState = StateIsNull; + } + } + +public: + RoVariant(IInspectable* pI, bool attach) + { + RoVariant tmp(pI, true, attach); + Swap(tmp); + } + + RoVariant(void*); + + ~RoVariant() + { + if (_pI && StateHasRefcount(_hrState)) + _pI->Release(); + } + + RoVariant& operator=(RoVariant other) + { + Swap(other); + return *this; + } + + void Swap(RoVariant& other) + { + IInspectable* pI = _pI; + _pI = other._pI; + other._pI = pI; + + HRESULT hrState = _hrState; + _hrState = other._hrState; + other._hrState = hrState; + } + + operator IInspectable*() const { return Get(); } + IInspectable* Get() const { return _pI; } + IInspectable* Detach(); + void Attach(ABI::Windows::Foundation::IPropertyValue*); + + void Attach(IInspectable* pI) + { + RoVariant tmp = RoVariant(pI, true, true); + Swap(tmp); + } + + Accessor operator*() const { return Accessor(_pI, _hrState); } + Accessor operator->() const { return Accessor(_pI, _hrState); } + OutRef operator&() { return ReleaseAndGetAddressOf(); } + + struct USE_INSTEAD_ReleaseAndGetAddressOf + { + }; + + USE_INSTEAD_ReleaseAndGetAddressOf GetAddressOf() { return USE_INSTEAD_ReleaseAndGetAddressOf(); } + OutRef ReleaseAndGetAddressOf() { return OutRef(this); } + bool operator!(); + static RoVariant Wrap(ABI::Windows::Foundation::IPropertyValue*); + static RoVariant Wrap(IInspectable* pI) { return RoVariant(pI, false, false); } + HRESULT CopyTo(ABI::Windows::Foundation::IPropertyValue**); + HRESULT CopyTo(IInspectable**); +}; + +namespace ABI::Windows::UI::Xaml +{ + enum HorizontalAlignment + { + HorizontalAlignment_Left = 0, + HorizontalAlignment_Center = 1, + HorizontalAlignment_Right = 2, + HorizontalAlignment_Stretch = 3, + }; + + enum VerticalAlignment + { + VerticalAlignment_Top = 0, + VerticalAlignment_Center = 1, + VerticalAlignment_Bottom = 2, + VerticalAlignment_Stretch = 3, + }; +} + +static struct +{ + int jumpViewExperienceManager_rcWorkArea; +} g_JVPositioningPatchOffsets; + +HRESULT CJumpViewExperienceManager_CalcWindowPosition( + RECT rcWork, + POINT ptAnchor, + int width, + int height, + ABI::Windows::UI::Xaml::HorizontalAlignment hAlign, + ABI::Windows::UI::Xaml::VerticalAlignment vAlign, + RECT& result) +{ + using namespace ABI::Windows::UI::Xaml; + + if (false) // Feature_40874676 + { + result.bottom = max(min(ptAnchor.y, rcWork.bottom), rcWork.top); + int desiredTop = result.bottom - height; + result.top = max(desiredTop, rcWork.top); + int desiredLeft = ptAnchor.x - (width / 2); + result.left = min(max(desiredLeft, rcWork.left), rcWork.right); + result.right = min(result.left + width, rcWork.right); + return S_OK; + } + + switch (vAlign) + { + case VerticalAlignment_Center: + { + int desiredTopPre = (height / -2) + ptAnchor.y; + result.bottom = min(height + max(desiredTopPre, rcWork.top), rcWork.bottom); + int desiredTop = result.bottom - height; + result.top = max(desiredTop, rcWork.top); + break; + } + case VerticalAlignment_Top: + { + int desiredTopPre = ptAnchor.y; + result.bottom = min(height + max(desiredTopPre, rcWork.top), rcWork.bottom); + int desiredTop = result.bottom - height; + result.top = max(desiredTop, rcWork.top); + break; + } + case VerticalAlignment_Bottom: + { + int top = max(min(ptAnchor.y, rcWork.bottom) - height, rcWork.top); + result.bottom = min(top + height, rcWork.bottom); + result.top = top; + break; + } + default: + { + RETURN_HR(E_NOTIMPL); + } + } + + switch (hAlign) + { + case HorizontalAlignment_Center: + { + int desiredLeftPre = (width / -2) + ptAnchor.x; + result.right = min(width + max(desiredLeftPre, rcWork.left), rcWork.right); + int desiredLeft = result.right - width; + result.left = max(desiredLeft, rcWork.left); + break; + } + case HorizontalAlignment_Left: + { + int desiredLeftPre = ptAnchor.x; + result.right = min(width + max(desiredLeftPre, rcWork.left), rcWork.right); + int desiredLeft = result.right - width; + result.left = max(desiredLeft, rcWork.left); + break; + } + case HorizontalAlignment_Right: + { + result.left = max(min(ptAnchor.x, rcWork.right) - width, rcWork.left); + result.right = min(result.left + width, rcWork.right); + break; + } + default: + { + RETURN_HR(E_NOTIMPL); + } + } + + return S_OK; +} + +HRESULT CJumpViewExperienceManager_GetMonitorInformation(void* _this, POINT ptAnchor, RECT* prcOutWorkArea, UINT* outDpi, EDGEUI_TRAYSTUCKPLACE* outStuckPlace) +{ + HMONITOR hMonitor = MonitorFromPoint(ptAnchor, MONITOR_DEFAULTTONEAREST); + RETURN_LAST_ERROR_IF(hMonitor == INVALID_HANDLE_VALUE); + + MONITORINFO mi = { sizeof(mi) }; + RETURN_IF_WIN32_BOOL_FALSE(GetMonitorInfoW(hMonitor, &mi)); + *prcOutWorkArea = mi.rcWork; + + UINT dpiY; + RETURN_IF_FAILED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, outDpi, &dpiY)); // 884 + + ComPtr spImmersiveShellServiceProvider; + RETURN_IF_FAILED(CoCreateInstance(CLSID_ImmersiveShell, nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&spImmersiveShellServiceProvider))); + + ComPtr spImmersiveMonitorManager; + RETURN_IF_FAILED(spImmersiveShellServiceProvider->QueryService(SID_IImmersiveMonitorService, IID_PPV_ARGS(&spImmersiveMonitorManager))); // 886 + + ComPtr spEdgeUiManager; + RETURN_IF_FAILED(spImmersiveMonitorManager->QueryService(hMonitor, SID_EdgeUi, IID_PPV_ARGS(&spEdgeUiManager))); // 887 + RETURN_IF_FAILED(spEdgeUiManager->GetTrayStuckPlace(outStuckPlace)); // 888 + + return S_OK; +} + +HRESULT(*CJumpViewExperienceManager_EnsureWindowPositionFunc)(void* _this, CSingleViewShellExperience* experience); +HRESULT CJumpViewExperienceManager_EnsureWindowPositionHook(void* _this, CSingleViewShellExperience* experience) +{ + if (!experience->_viewWrapper) + return S_OK; + + ComPtr> properties; + RETURN_IF_FAILED(experience->_propertySet.As(&properties)); // 813 + + POINT ptAnchor; + { + RoVariant variant; + RETURN_IF_FAILED(properties->Lookup(Wrappers::HStringReference(L"Position").Get(), &variant)); // 816 + + ABI::Windows::Foundation::Point value; + RETURN_IF_FAILED(variant->GetPoint(&value)); // 819 + + ptAnchor.x = (int)value.X; + ptAnchor.y = (int)value.Y; + } + + ABI::Windows::UI::Xaml::HorizontalAlignment hAlign; + { + RoVariant variant; + RETURN_IF_FAILED(properties->Lookup(Wrappers::HStringReference(L"HorizontalAlign").Get(), &variant)); // 828 + + int value; + RETURN_IF_FAILED(variant->GetInt32(&value)); // 831 + hAlign = (ABI::Windows::UI::Xaml::HorizontalAlignment)value; + } + + ABI::Windows::UI::Xaml::VerticalAlignment vAlign; + { + RoVariant variant; + RETURN_IF_FAILED(properties->Lookup(Wrappers::HStringReference(L"VerticalAlign").Get(), &variant)); // 838 + + int value; + RETURN_IF_FAILED(variant->GetInt32(&value)); // 841 + vAlign = (ABI::Windows::UI::Xaml::VerticalAlignment)value; + } + + RECT rcWorkArea; + UINT dpi; + RETURN_IF_FAILED(CJumpViewExperienceManager_GetMonitorInformation( + _this, ptAnchor, &rcWorkArea, &dpi, + (EDGEUI_TRAYSTUCKPLACE*)((PBYTE)_this + 0x1F0))); // 850 + *((RECT*)((PBYTE)_this + g_JVPositioningPatchOffsets.jumpViewExperienceManager_rcWorkArea)) = rcWorkArea; + + int width, height; + ExperienceManagerUtils::ScaleByDPI(&experience->_desiredSize, dpi, &width, &height); + RETURN_HR_IF(E_INVALIDARG, width <= 0 || height <= 0); // 860 + + RECT rcPosition; + RETURN_IF_FAILED(CJumpViewExperienceManager_CalcWindowPosition(rcWorkArea, ptAnchor, width, height, hAlign, vAlign, rcPosition)); + RETURN_IF_FAILED(experience->SetPosition(&rcPosition)); + + return S_OK; +} + +BOOL FixJumpViewPositioning(MODULEINFO* mi) +{ + // Offset sanity checks + + // EDGEUI_TRAYSTUCKPLACE CJumpViewExperienceManager::m_trayStuckPlace +#if defined(_M_X64) + // 8B 8B B0 01 00 00 BF 5C 00 00 00 85 C9 + // ^^^^^^^^^^^ + // Ref: CJumpViewExperienceManager::OnViewUncloaking() + PBYTE matchOffsetTrayStuckPlace = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x8B\x8B\xB0\x01\x00\x00\xBF\x5C\x00\x00\x00\x85\xC9", + "xxxxxxxxxxxxx" + ); +#elif defined(_M_ARM64) + // ?? ?? 41 B9 89 0B 80 52 A8 01 00 34 1F 05 00 71 20 01 00 54 1F 09 00 71 A0 00 00 54 1F 0D 00 71 01 01 00 54 69 0B 80 52 + // ^^^^^^^^^^^ Important instr. to distinguish from MeetNowExperienceManager::OnViewUncloaking() in GE > !!!!!!!!!!! + // Ref: CJumpViewExperienceManager::OnViewCloaking() + PBYTE matchOffsetTrayStuckPlace = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x41\xB9\x89\x0B\x80\x52\xA8\x01\x00\x34\x1F\x05\x00\x71\x20\x01\x00\x54\x1F\x09\x00\x71\xA0\x00\x00\x54\x1F\x0D\x00\x71\x01\x01\x00\x54\x69\x0B\x80\x52", + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + ); +#endif + if (matchOffsetTrayStuckPlace) + { + printf("[JVP] matchOffsetTrayStuckPlace = %llX\n", matchOffsetTrayStuckPlace - (PBYTE)mi->lpBaseOfDll); + } + + // RECT CJumpViewExperienceManager::m_rcWorkArea + PBYTE matchOffsetRcWorkArea = nullptr; +#if defined(_M_X64) + // 48 8B 53 70 48 8D 83 ?? ?? ?? ?? + // -- ^^^^^^^^^^^ + // Ref: CJumpViewExperienceManager::OnViewUncloaking() + // Note: The ref function belongs to SingleViewShellExperienceEventHandler so `this` is +0x40. + // As long as the above sanity check passes, hardcoding it should be fine. + if (matchOffsetTrayStuckPlace) + { + matchOffsetRcWorkArea = (PBYTE)FindPattern( + matchOffsetTrayStuckPlace + 13, + 256, + "\x48\x8B\x53\x70\x48\x8D\x83", + "xxxxxxx" + ); + if (matchOffsetRcWorkArea) + { + g_JVPositioningPatchOffsets.jumpViewExperienceManager_rcWorkArea = 0x40 + *(int*)(matchOffsetRcWorkArea + 7); + } + } +#elif defined(_M_ARM64) + if (matchOffsetTrayStuckPlace) + { + // Without Feature_TaskbarJumplistOnHover (48980211) + // 01 38 40 F9 07 00 07 91 + // ----------- ^^^^^^^^^^^ + // If this matches then the offset of m_rcWorkArea is +0x200 + // Ref: CJumpViewExperienceManager::OnViewCloaking() + matchOffsetRcWorkArea = (PBYTE)FindPattern( + matchOffsetTrayStuckPlace + 38, + 128, + "\x01\x38\x40\xF9\x07\x00\x07\x91", + "xxxxxxxx" + ); + if (matchOffsetRcWorkArea) + { + g_JVPositioningPatchOffsets.jumpViewExperienceManager_rcWorkArea = 0x200; + } + if (!matchOffsetRcWorkArea) + { + // With Feature_TaskbarJumplistOnHover (48980211) + // 22 01 03 32 67 32 07 91 + // ^^^^^^^^^^^ + // If this matches then the offset of m_rcWorkArea is +0x20C + // Ref: CJumpViewExperienceManager::OnViewCloaking() + matchOffsetRcWorkArea = (PBYTE)FindPattern( + matchOffsetTrayStuckPlace + 38, + 128, + "\x22\x01\x03\x32\x67\x32\x07\x91", + "xxxxxxxx" + ); + if (matchOffsetRcWorkArea) + { + g_JVPositioningPatchOffsets.jumpViewExperienceManager_rcWorkArea = 0x20C; + } + } + } +#endif + if (matchOffsetRcWorkArea) + { + printf("[JVP] matchOffsetRcWorkArea = %llX\n", matchOffsetRcWorkArea - (PBYTE)mi->lpBaseOfDll); + } + + // CJumpViewExperienceManager::EnsureWindowPosition() +#if defined(_M_X64) + // Base Nickel and Germanium + // 8D 4E C0 48 8B ?? E8 ?? ?? ?? ?? 8B + // ^^^^^^^^^^^ + // Ref: CJumpViewExperienceManager::OnViewPropertiesChanging() + PBYTE matchEnsureWindowPosition = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x8D\x4E\xC0\x48\x8B\x00\xE8\x00\x00\x00\x00\x8B", + "xxxxx?x????x" + ); + if (matchEnsureWindowPosition) + { + matchEnsureWindowPosition += 6; + matchEnsureWindowPosition += 5 + *(int*)(matchEnsureWindowPosition + 1); + } + if (!matchEnsureWindowPosition) + { + // Nickel with Feature_TaskbarJumplistOnHover (48980211) + // - 22621.3930, 3936, 4000, 4010, 4076, 4082, 4110, 4145, ... + // 4C 8D 76 C0 48 8B D3 49 8B CE E8 ?? ?? ?? ?? 8B + // ^^^^^^^^^^^ + // Ref: CJumpViewExperienceManager::OnViewPropertiesChanging() + matchEnsureWindowPosition = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x4C\x8D\x76\xC0\x48\x8B\xD3\x49\x8B\xCE\xE8\x00\x00\x00\x00\x8B", + "xxxxxxxxxxx????x" + ); + if (matchEnsureWindowPosition) + { + matchEnsureWindowPosition += 10; + matchEnsureWindowPosition += 5 + *(int*)(matchEnsureWindowPosition + 1); + } + } + if (!matchEnsureWindowPosition) + { + // Germanium with Feature_TaskbarJumplistOnHover (48980211) + // - 26100.1350, 1591, ... + // 48 8B D7 49 8D 4E C0 E8 ?? ?? ?? ?? 8B + // ^^^^^^^^^^^ + // Ref: CJumpViewExperienceManager::OnViewPropertiesChanging() + matchEnsureWindowPosition = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x48\x8B\xD7\x49\x8D\x4E\xC0\xE8\x00\x00\x00\x00\x8B", + "xxxxxxxx????x" + ); + if (matchEnsureWindowPosition) + { + matchEnsureWindowPosition += 7; + matchEnsureWindowPosition += 5 + *(int*)(matchEnsureWindowPosition + 1); + } + } +#elif defined(_M_ARM64) + // E1 03 ?? AA ?? 02 01 D1 ?? ?? ?? ?? ?? 03 00 2A + // !! ^^^^^^^^^^^ + // Do not change this to a wildcard, this byte is important + // Ref: CJumpViewExperienceManager::OnViewPropertiesChanging() + PBYTE matchEnsureWindowPosition = (PBYTE)FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\xE1\x03\x00\xAA\x00\x02\x01\xD1\x00\x00\x00\x00\x00\x03\x00\x2A", + "xx?x?xxx?????xxx" + ); + if (matchEnsureWindowPosition) + { + matchEnsureWindowPosition += 8; + matchEnsureWindowPosition = (PBYTE)ARM64_FollowBL((DWORD*)matchEnsureWindowPosition); + } +#endif + if (matchEnsureWindowPosition) + { + printf("[JVP] matchEnsureWindowPosition = %llX\n", matchEnsureWindowPosition - (PBYTE)mi->lpBaseOfDll); + } + + if (!matchOffsetTrayStuckPlace + || !matchOffsetRcWorkArea + || !matchEnsureWindowPosition) + { + printf("[JVP] Not all offsets were found, cannot perform patch\n"); + return FALSE; + } + + CJumpViewExperienceManager_EnsureWindowPositionFunc = (decltype(CJumpViewExperienceManager_EnsureWindowPositionFunc))matchEnsureWindowPosition; + funchook_prepare( + funchook, + (void**)&CJumpViewExperienceManager_EnsureWindowPositionFunc, + CJumpViewExperienceManager_EnsureWindowPositionHook + ); + + return TRUE; +} + +#pragma endregion + + +void TryToFindTwinuiPCShellOffsets(DWORD* pOffsets) +{ + // We read from the file instead of from memory because other tweak software might've modified the functions we're looking for + WCHAR wszPath[MAX_PATH]; + GetSystemDirectoryW(wszPath, MAX_PATH); + wcscat_s(wszPath, MAX_PATH, L"\\twinui.pcshell.dll"); + HANDLE hFile = CreateFileW(wszPath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + if (hFile == INVALID_HANDLE_VALUE) + { + printf("Failed to open twinui.pcshell.dll\n"); + return; + } + + DWORD dwSize = GetFileSize(hFile, nullptr); + PBYTE pFile = (PBYTE)malloc(dwSize); + DWORD dwRead = 0; + if (!ReadFile(hFile, pFile, dwSize, &dwRead, nullptr) || dwRead != dwSize) + { + printf("Failed to read twinui.pcshell.dll\n"); + goto cleanup; + } + + if (IsWindows11()) + { + // All patterns here have been tested to work on: + // - 22621.1, 22621.1992, 22621.2134, 22621.2283, 22621.2359 (RP) + // - 23545.1000 + // - 25951.1000 + + if (!pOffsets[0] || pOffsets[0] == 0xFFFFFFFF) + { +#if defined(_M_X64) + // 48 8B 49 08 E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 48 8B 89 + // ^^^^^^^^^^^ + // Ref: CMultitaskingViewFrame::v_WndProc() + PBYTE match = (PBYTE)FindPattern( + pFile, dwSize, + "\x48\x8B\x49\x08\xE8\x00\x00\x00\x00\xE9\x00\x00\x00\x00\x48\x8B\x89", + "xxxxx????x????xxx" + ); + if (match) + { + match += 4; + pOffsets[0] = (DWORD)(match + 5 + *(int*)(match + 1) - pFile); + } +#elif defined(_M_ARM64) + // ?? AE 00 71 ?? ?? 00 54 ?? 06 40 F9 E3 03 ?? AA E2 03 ?? AA E1 03 ?? 2A ?? ?? ?? ?? + // ^^^^^^^^^^^ + // Ref: CMultitaskingViewFrame::v_WndProc() + PBYTE match = (PBYTE)FindPattern( + pFile, dwSize, + "\xAE\x00\x71\x00\x00\x00\x54\x00\x06\x40\xF9\xE3\x03\x00\xAA\xE2\x03\x00\xAA\xE1\x03\x00\x2A", + "xxx??xx?xxxxx?xxx?xxx?x" + ); + if (match) + { + match += 23; + pOffsets[0] = (DWORD)FileOffsetToRVA(pFile, (PBYTE)ARM64_FollowBL((DWORD*)match) - pFile); + } +#endif + if (pOffsets[0] && pOffsets[0] != 0xFFFFFFFF) + { + printf("CImmersiveContextMenuOwnerDrawHelper::s_ContextMenuWndProc() = %lX\n", pOffsets[0]); + } + } + if (!pOffsets[1] || pOffsets[1] == 0xFFFFFFFF) + { +#if defined(_M_X64) + // Don't worry if this is too long, this works on 17763 and 25951 + // 40 55 53 56 57 41 54 41 55 41 56 41 57 48 8D AC 24 ? ? ? ? 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 85 ? ? ? ? 4C 8B B5 ? ? ? ? 41 8B C1 + PBYTE match = (PBYTE)FindPattern( + pFile, dwSize, + "\x40\x55\x53\x56\x57\x41\x54\x41\x55\x41\x56\x41\x57\x48\x8D\xAC\x24\x00\x00\x00\x00\x48\x81\xEC\x00\x00\x00\x00\x48\x8B\x05\x00\x00\x00\x00\x48\x33\xC4\x48\x89\x85\x00\x00\x00\x00\x4C\x8B\xB5\x00\x00\x00\x00\x41\x8B\xC1", + "xxxxxxxxxxxxxxxxx????xxx????xxx????xxxxxx????xxx????xxx" + ); + if (match) + { + pOffsets[1] = (DWORD)(match - pFile); + } +#elif defined(_M_ARM64) + // 40 F9 43 03 1C 32 E4 03 15 AA ?? ?? FF 97 + // ^^^^^^^^^^^ + // Ref: ImmersiveContextMenuHelper::ApplyOwnerDrawToMenu() + PBYTE match = (PBYTE)FindPattern( + pFile, dwSize, + "\x40\xF9\x43\x03\x1C\x32\xE4\x03\x15\xAA\x00\x00\xFF\x97", + "xxxxxxxxxx??xx" + ); + if (match) + { + match += 10; + pOffsets[1] = (DWORD)FileOffsetToRVA(pFile, (PBYTE)ARM64_FollowBL((DWORD*)match) - pFile); + } +#endif + if (pOffsets[1] && pOffsets[1] != 0xFFFFFFFF) + { + printf("ImmersiveContextMenuHelper::ApplyOwnerDrawToMenu() = %lX\n", pOffsets[1]); + } + } + if (!pOffsets[2] || pOffsets[2] == 0xFFFFFFFF) + { +#if defined(_M_X64) + // 48 89 5C 24 ? 48 89 7C 24 ? 55 48 8B EC 48 83 EC 60 48 8B FA 48 8B D9 E8 + PBYTE match = (PBYTE)FindPattern( + pFile, dwSize, + "\x48\x89\x5C\x24\x00\x48\x89\x7C\x24\x00\x55\x48\x8B\xEC\x48\x83\xEC\x60\x48\x8B\xFA\x48\x8B\xD9\xE8", + "xxxx?xxxx?xxxxxxxxxxxxxxx" + ); + if (match) + { + pOffsets[2] = (DWORD)(match - pFile); + } +#elif defined(_M_ARM64) + // 7F 23 03 D5 F3 53 BF A9 FD 7B BB A9 FD 03 00 91 F3 03 00 AA F4 03 01 AA ?? ?? ?? ?? FF ?? 03 A9 + // ----------- PACIBSP, don't scan for this because it's everywhere + PBYTE match = (PBYTE)FindPattern( + pFile, dwSize, + "\xF3\x53\xBF\xA9\xFD\x7B\xBB\xA9\xFD\x03\x00\x91\xF3\x03\x00\xAA\xF4\x03\x01\xAA\x00\x00\x00\x00\xFF\x00\x03\xA9", + "xxxxxxxxxxxxxxxxxxxx????x?xx" + ); + if (match) + { + match -= 4; + pOffsets[2] = (DWORD)FileOffsetToRVA(pFile, match - pFile); + } +#endif + if (pOffsets[2] && pOffsets[2] != 0xFFFFFFFF) + { + printf("ImmersiveContextMenuHelper::RemoveOwnerDrawFromMenu() = %lX\n", pOffsets[2]); + } + } + if (!pOffsets[3] || pOffsets[3] == 0xFFFFFFFF) + { +#if defined(_M_X64) + // 48 8B ? E8 ? ? ? ? 4C 8B ? 48 8B ? 48 8B CE E8 ? ? ? ? 90 + // ^^^^^^^ + PBYTE match = (PBYTE)FindPattern( + pFile, dwSize, + "\x48\x8B\x00\xE8\x00\x00\x00\x00\x4C\x8B\x00\x48\x8B\x00\x48\x8B\xCE\xE8\x00\x00\x00\x00\x90", + "xx?x????xx?xx?xxxx????x" + ); + if (match) + { + match += 17; + pOffsets[3] = (DWORD)(match + 5 + *(int*)(match + 1) - pFile); + } +#elif defined(_M_ARM64) + // 82 62 00 91 ?? ?? 00 91 E0 03 ?? AA ?? ?? ?? ?? 1F 20 03 D5 + // ^^^^^^^^^^^ + PBYTE match = (PBYTE)FindPattern( + pFile, dwSize, + "\x82\x62\x00\x91\x00\x00\x00\x91\xE0\x03\x00\xAA\x00\x00\x00\x00\x1F\x20\x03\xD5", + "xxxx??xxxx?x????xxxx" + ); + if (match) + { + match += 12; + pOffsets[3] = (DWORD)FileOffsetToRVA(pFile, (PBYTE)ARM64_FollowBL((DWORD*)match) - pFile); + } +#endif + if (pOffsets[3] && pOffsets[3] != 0xFFFFFFFF) + { + printf("CLauncherTipContextMenu::_ExecuteShutdownCommand() = %lX\n", pOffsets[3]); + } + } + if (!pOffsets[4] || pOffsets[4] == 0xFFFFFFFF) + { +#if defined(_M_X64) + // Cobalt: + // 48 89 46 ? 48 8B CB E8 ? ? ? ? 48 8B D3 48 8B CF E8 ? ? ? ? 90 + // ^^^^^^^ + PBYTE match = (PBYTE)FindPattern( + pFile, dwSize, + "\x48\x89\x46\x00\x48\x8B\xCB\xE8\x00\x00\x00\x00\x48\x8B\xD3\x48\x8B\xCF\xE8\x00\x00\x00\x00\x90", + "xxx?xxxx????xxxxxxx????x" + ); + if (match) + { + match += 18; + pOffsets[4] = (DWORD)(match + 5 + *(int*)(match + 1) - pFile); + } + else + { + // Nickel+: + // 48 89 03 48 8B CB E8 ? ? ? ? 48 8B D3 48 8B CF E8 ? ? ? ? 90 + // ^^^^^^^ + match = (PBYTE)FindPattern( + pFile, dwSize, + "\x48\x89\x03\x48\x8B\xCB\xE8\x00\x00\x00\x00\x48\x8B\xD3\x48\x8B\xCF\xE8\x00\x00\x00\x00\x90", + "xxxxxxx????xxxxxxx????x" + ); + if (match) + { + match += 17; + pOffsets[4] = (DWORD)(match + 5 + *(int*)(match + 1) - pFile); + } + } +#elif defined(_M_ARM64) + // 08 09 40 F9 ?? ?? 00 F9 ?? ?? ?? ?? ?? ?? 00 91 E0 03 ?? AA ?? ?? ?? ?? 1F 20 03 D5 + // ^^^^^^^^^^^ + PBYTE match = (PBYTE)FindPattern( + pFile, dwSize, + "\x08\x09\x40\xF9\x00\x00\x00\xF9\x00\x00\x00\x00\x00\x00\x00\x91\xE0\x03\x00\xAA\x00\x00\x00\x00\x1F\x20\x03\xD5", + "xxxx??xx??????xxxx?x????xxxx" + ); + if (match) + { + match += 20; + pOffsets[4] = (DWORD)FileOffsetToRVA(pFile, (PBYTE)ARM64_FollowBL((DWORD*)match) - pFile); + } +#endif + if (pOffsets[4] && pOffsets[4] != 0xFFFFFFFF) + { + printf("CLauncherTipContextMenu::_ExecuteCommand() = %lX\n", pOffsets[4]); + } + } + if (!pOffsets[5] || pOffsets[5] == 0xFFFFFFFF) + { +#if defined(_M_X64) + // Ref: CMultitaskingViewManager::_CreateMTVHost() + // Inlined GetMTVHostKind() + // 4C 89 74 24 ?? ?? 8B ?? ?? 8B ?? 8B D7 48 8B CE E8 ?? ?? ?? ?? 8B + // ^^^^^^^^^^^ + PBYTE match = (PBYTE)FindPattern( + pFile, dwSize, + "\x4C\x89\x74\x24\x00\x00\x8B\x00\x00\x8B\x00\x8B\xD7\x48\x8B\xCE\xE8\x00\x00\x00\x00\x8B", + "xxxx??x??x?xxxxxx????x" + ); + if (match) + { + match += 16; + pOffsets[5] = (DWORD)(match + 5 + *(int*)(match + 1) - pFile); + } + else + { + // Non-inlined GetMTVHostKind() + // 8B CF E8 ?? ?? ?? ?? ?? 89 ?? 24 ?? ?? 8B ?? ?? 8B ?? 8B D7 48 8B CE 83 F8 01 + match = (PBYTE)FindPattern( + pFile, dwSize, + "\x8B\xCF\xE8\x00\x00\x00\x00\x00\x89\x00\x24\x00\x00\x8B\x00\x00\x8B\x00\x8B\xD7\x48\x8B\xCE\x83\xF8\x01", + "xxx?????x?x??x??x?xxxxxxxx" + ); + if (match) + { + PBYTE target = nullptr; + DWORD jnzSize = 0; + if (FollowJnz(match + 26, &target, &jnzSize)) + { + match += 26 + jnzSize; + if (match[0] == 0xE8) + { + pOffsets[5] = (DWORD)(match + 5 + *(int*)(match + 1) - pFile); + } + } + } + } +#elif defined(_M_ARM64) + // F3 53 BE A9 F5 5B 01 A9 FD 7B ?? A9 FD 03 00 91 30 00 80 92 F5 03 04 AA B0 ?? 00 F9 F3 03 00 AA BF 02 00 F9 68 2E 40 F9 F6 03 03 AA B3 23 02 A9 ?? ?? 00 B5 + PBYTE match = (PBYTE)FindPattern( + pFile, dwSize, + "\xF3\x53\xBE\xA9\xF5\x5B\x01\xA9\xFD\x7B\x00\xA9\xFD\x03\x00\x91\x30\x00\x80\x92\xF5\x03\x04\xAA\xB0\x00\x00\xF9\xF3\x03\x00\xAA\xBF\x02\x00\xF9\x68\x2E\x40\xF9\xF6\x03\x03\xAA\xB3\x23\x02\xA9\x00\x00\x00\xB5", + "xxxxxxxxxx?xxxxxxxxxxxxxx?xxxxxxxxxxxxxxxxxxxxxx??xx" + ); + if (match) + { + pOffsets[5] = (DWORD)FileOffsetToRVA(pFile, match - 4 - pFile); + } +#endif + if (pOffsets[5] && pOffsets[5] != 0xFFFFFFFF) + { + printf("CMultitaskingViewManager::_CreateXamlMTVHost() = %lX\n", pOffsets[5]); + } + } + if (!pOffsets[6] || pOffsets[6] == 0xFFFFFFFF) + { +#if defined(_M_X64) + // Ref: CMultitaskingViewManager::_CreateMTVHost() + // Inlined GetMTVHostKind() + // 4C 89 74 24 ?? ?? 8B ?? ?? 8B ?? 8B D7 48 8B CE E8 ?? ?? ?? ?? 90 + // ^^^^^^^^^^^ + PBYTE match = (PBYTE)FindPattern( + pFile, dwSize, + "\x4C\x89\x74\x24\x00\x00\x8B\x00\x00\x8B\x00\x8B\xD7\x48\x8B\xCE\xE8\x00\x00\x00\x00\x90", + "xxxx??x??x?xxxxxx????x" + ); + if (match) + { + match += 16; + pOffsets[6] = (DWORD)(match + 5 + *(int*)(match + 1) - pFile); + } + else + { + // Non-inlined GetMTVHostKind() + // 8B CF E8 ?? ?? ?? ?? ?? 89 ?? 24 ?? ?? 8B ?? ?? 8B ?? 8B D7 48 8B CE 83 F8 01 + match = (PBYTE)FindPattern( + pFile, dwSize, + "\x8B\xCF\xE8\x00\x00\x00\x00\x00\x89\x00\x24\x00\x00\x8B\x00\x00\x8B\x00\x8B\xD7\x48\x8B\xCE\x83\xF8\x01", + "xxx?????x?x??x??x?xxxxxxxx" + ); + if (match) + { + PBYTE target = nullptr; + DWORD jnzSize = 0; + if (FollowJnz(match + 26, &target, &jnzSize) && target[0] == 0xE8) + { + pOffsets[6] = (DWORD)(target + 5 + *(int*)(target + 1) - pFile); + } + } + } +#elif defined(_M_ARM64) + // F3 53 BC A9 F5 5B 01 A9 F7 13 00 F9 F9 17 00 F9 FB 1B 00 F9 FD 7B BC A9 FD 03 00 91 FF ?? 00 D1 30 00 80 92 FB 03 04 AA + PBYTE match = (PBYTE)FindPattern( + pFile, dwSize, + "\xF3\x53\xBC\xA9\xF5\x5B\x01\xA9\xF7\x13\x00\xF9\xF9\x17\x00\xF9\xFB\x1B\x00\xF9\xFD\x7B\xBC\xA9\xFD\x03\x00\x91\xFF\x00\x00\xD1\x30\x00\x80\x92\xFB\x03\x04\xAA", + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx?xxxxxxxxxx" + ); + if (match) + { + pOffsets[6] = (DWORD)FileOffsetToRVA(pFile, match - 4 - pFile); + } +#endif + if (pOffsets[6] && pOffsets[6] != 0xFFFFFFFF) + { + printf("CMultitaskingViewManager::_CreateDCompMTVHost() = %lX\n", pOffsets[6]); + } + } + } + +cleanup: + free(pFile); + CloseHandle(hFile); +} + +extern "C" void RunTwinUIPCShellPatches(symbols_addr* symbols_PTRS) +{ + HMODULE hTwinuiPcshell = LoadLibraryW(L"twinui.pcshell.dll"); + MODULEINFO miTwinuiPcshell; + GetModuleInformation(GetCurrentProcess(), hTwinuiPcshell, &miTwinuiPcshell, sizeof(MODULEINFO)); + + // ZeroMemory(symbols_PTRS->twinui_pcshell_PTRS, sizeof(symbols_PTRS->twinui_pcshell_PTRS)); // Uncomment for testing + TryToFindTwinuiPCShellOffsets(symbols_PTRS->twinui_pcshell_PTRS); + + if (symbols_PTRS->twinui_pcshell_PTRS[0] && symbols_PTRS->twinui_pcshell_PTRS[0] != 0xFFFFFFFF) + { + CImmersiveContextMenuOwnerDrawHelper_s_ContextMenuWndProcFunc = (decltype(CImmersiveContextMenuOwnerDrawHelper_s_ContextMenuWndProcFunc)) + ((uintptr_t)hTwinuiPcshell + symbols_PTRS->twinui_pcshell_PTRS[0]); + } + + if (symbols_PTRS->twinui_pcshell_PTRS[1] && symbols_PTRS->twinui_pcshell_PTRS[1] != 0xFFFFFFFF) + { + ImmersiveContextMenuHelper_ApplyOwnerDrawToMenuFunc = (decltype(ImmersiveContextMenuHelper_ApplyOwnerDrawToMenuFunc)) + ((uintptr_t)hTwinuiPcshell + symbols_PTRS->twinui_pcshell_PTRS[1]); + } + + if (symbols_PTRS->twinui_pcshell_PTRS[2] && symbols_PTRS->twinui_pcshell_PTRS[2] != 0xFFFFFFFF) + { + ImmersiveContextMenuHelper_RemoveOwnerDrawFromMenuFunc = (decltype(ImmersiveContextMenuHelper_RemoveOwnerDrawFromMenuFunc)) + ((uintptr_t)hTwinuiPcshell + symbols_PTRS->twinui_pcshell_PTRS[2]); + } + + if (symbols_PTRS->twinui_pcshell_PTRS[3] && symbols_PTRS->twinui_pcshell_PTRS[3] != 0xFFFFFFFF) + { + CLauncherTipContextMenu_ExecuteShutdownCommandFunc = (decltype(CLauncherTipContextMenu_ExecuteShutdownCommandFunc)) + ((uintptr_t)hTwinuiPcshell + symbols_PTRS->twinui_pcshell_PTRS[3]); + } + + if (symbols_PTRS->twinui_pcshell_PTRS[4] && symbols_PTRS->twinui_pcshell_PTRS[4] != 0xFFFFFFFF) + { + CLauncherTipContextMenu_ExecuteCommandFunc = (decltype(CLauncherTipContextMenu_ExecuteCommandFunc)) + ((uintptr_t)hTwinuiPcshell + symbols_PTRS->twinui_pcshell_PTRS[4]); + } + + int rv; + + if (IsWindows11()) + { + if (bOldTaskbar) + { + typedef HRESULT (WINAPI *DllGetClassObject_t)(REFCLSID rclsid, REFIID riid, LPVOID* ppv); + DllGetClassObject_t pfnDllGetClassObject = (DllGetClassObject_t)GetProcAddress(hTwinuiPcshell, "DllGetClassObject"); + if (pfnDllGetClassObject) + { + IClassFactory* pFactory; + HRESULT hr = pfnDllGetClassObject(__uuidof(CLauncherTipContextMenu), IID_PPV_ARGS(&pFactory)); + if (SUCCEEDED(hr)) + { + void** vtable = *(void***)pFactory; + REPLACE_VTABLE_ENTRY(vtable, 3, CLauncherTipContextMenu_CreateInstance_IClassFactory_); + pFactory->Release(); + } + } + } + + rv = -1; + if (symbols_PTRS->twinui_pcshell_PTRS[5] && symbols_PTRS->twinui_pcshell_PTRS[5] != 0xFFFFFFFF) + { + twinui_pcshell_CMultitaskingViewManager__CreateDCompMTVHostFunc = (decltype(twinui_pcshell_CMultitaskingViewManager__CreateDCompMTVHostFunc)) + ((uintptr_t)hTwinuiPcshell + symbols_PTRS->twinui_pcshell_PTRS[6]); + twinui_pcshell_CMultitaskingViewManager__CreateXamlMTVHostFunc = (decltype(twinui_pcshell_CMultitaskingViewManager__CreateXamlMTVHostFunc)) + ((uintptr_t)hTwinuiPcshell + symbols_PTRS->twinui_pcshell_PTRS[5]); + rv = funchook_prepare( + funchook, + (void**)&twinui_pcshell_CMultitaskingViewManager__CreateXamlMTVHostFunc, + twinui_pcshell_CMultitaskingViewManager__CreateXamlMTVHostHook + ); + } + if (rv != 0) + { + printf("Failed to hook CMultitaskingViewManager::_CreateXamlMTVHost(). rv = %d\n", rv); + } + } + + /*rv = -1; + if (symbols_PTRS->twinui_pcshell_PTRS[TWINUI_PCSHELL_SB_CNT - 1] && symbols_PTRS->twinui_pcshell_PTRS[TWINUI_PCSHELL_SB_CNT - 1] != 0xFFFFFFFF) + { + winrt_Windows_Internal_Shell_implementation_MeetAndChatManager_OnMessageFunc = (INT64(*)(void*, POINT*)) + ((uintptr_t)hTwinuiPcshell + symbols_PTRS->twinui_pcshell_PTRS[TWINUI_PCSHELL_SB_CNT - 1]); + rv = funchook_prepare( + funchook, + (void**)&winrt_Windows_Internal_Shell_implementation_MeetAndChatManager_OnMessageFunc, + winrt_Windows_Internal_Shell_implementation_MeetAndChatManager_OnMessageHook + ); + } + if (rv != 0) + { + printf("Failed to hook winrt_Windows_Internal_Shell_implementation_MeetAndChatManager_OnMessage(). rv = %d\n", rv); + }*/ + +#if USE_MOMENT_3_FIXES_ON_MOMENT_2 + // Use this only for testing, since the RtlQueryFeatureConfiguration() hook is perfect. + // Only tested on 22621.1992. + BOOL bPerformMoment2Patches = IsWindows11Version22H2Build1413OrHigher(); +#else + // This is the only way to fix stuff since the flag "26008830" and the code when it's not enabled are gone. + // Tested on: + // - 22621.2134, 22621.2283, 22621.2359 (RP) + // - 23545.1000 + BOOL bPerformMoment2Patches = IsWindows11Version22H2Build2134OrHigher(); +#endif + if (bOldTaskbar != 1) + { + bPerformMoment2Patches = FALSE; + } + if (bPerformMoment2Patches) + { + // Fix flyout placement: Our goal with these patches is to get `mi.rcWork` assigned + Moment2PatchActionCenter(&miTwinuiPcshell); + Moment2PatchControlCenter(&miTwinuiPcshell); + Moment2PatchToastCenter(&miTwinuiPcshell); + + // Fix task view + Moment2PatchTaskView(&miTwinuiPcshell); + + // Fix volume and brightness popups + HMODULE hHardwareConfirmator = LoadLibraryW(L"Windows.Internal.HardwareConfirmator.dll"); + MODULEINFO miHardwareConfirmator; + GetModuleInformation(GetCurrentProcess(), hHardwareConfirmator, &miHardwareConfirmator, sizeof(MODULEINFO)); + Moment2PatchHardwareConfirmator(&miHardwareConfirmator); + + // Fix pen menu +#if defined(_M_X64) + // 48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 50 49 8B ? 48 81 C1 + PBYTE match = (PBYTE)FindPattern( + hTwinuiPcshell, + miTwinuiPcshell.SizeOfImage, + "\x48\x89\x5C\x24\x00\x48\x89\x74\x24\x00\x57\x48\x83\xEC\x50\x49\x8B\x00\x48\x81\xC1", + "xxxx?xxxx?xxxxxxx?xxx" + ); +#elif defined(_M_ARM64) + PBYTE match = nullptr; +#endif + rv = -1; + if (match) + { + twinui_pcshell_PenMenuSystemTrayManager__GetDynamicSystemTrayHeightForMonitorFunc = (decltype(twinui_pcshell_PenMenuSystemTrayManager__GetDynamicSystemTrayHeightForMonitorFunc))match; + printf("PenMenuSystemTrayManager::GetDynamicSystemTrayHeightForMonitor() = %llX\n", match - (PBYTE)hTwinuiPcshell); + rv = funchook_prepare( + funchook, + (void**)&twinui_pcshell_PenMenuSystemTrayManager__GetDynamicSystemTrayHeightForMonitorFunc, + twinui_pcshell_PenMenuSystemTrayManager__GetDynamicSystemTrayHeightForMonitorHook + ); + } + if (rv != 0) + { + printf("Failed to hook PenMenuSystemTrayManager::GetDynamicSystemTrayHeightForMonitor(). rv = %d\n", rv); + } + } + + if ((global_rovi.dwBuildNumber > 22000 || global_rovi.dwBuildNumber == 22000 && global_ubr >= 65) // Allow on 22000.65+ + && (bOldTaskbar || dwStartShowClassicMode)) + { + // Make sure crash counter is enabled. If one of the patches make Explorer crash while the start menu is open, + // we don't want to softlock the user. The system reopens the start menu if Explorer terminates while it's open. + if (IsCrashCounterEnabled()) + { + if (FixStartMenuAnimation(&miTwinuiPcshell)) + { + ReportSuccessfulAnimationPatching(); + } + } + } + + if (IsWindows11Version22H2OrHigher() && bOldTaskbar) + { + // Fix broken taskbar jump list positioning caused by 40874676 + FixJumpViewPositioning(&miTwinuiPcshell); + } + + VnPatchIAT_NonInline(hTwinuiPcshell, "API-MS-WIN-CORE-REGISTRY-L1-1-0.DLL", "RegGetValueW", (uintptr_t)twinuipcshell_RegGetValueW); + printf("Setup twinui.pcshell functions done\n"); +} diff --git a/ExplorerPatcher/utility.h b/ExplorerPatcher/utility.h index 2887ff3..11969fe 100644 --- a/ExplorerPatcher/utility.h +++ b/ExplorerPatcher/utility.h @@ -1,1031 +1,1042 @@ -#ifndef _H_UTILITY_H_ -#define _H_UTILITY_H_ -#if __has_include("ep_private.h") -//#define USE_PRIVATE_INTERFACES -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#pragma comment(lib, "Rstrtmgr.lib") -#define _LIBVALINET_INCLUDE_UNIVERSAL -#ifndef __cplusplus -#include -#endif -#include "osutility.h" -#include "queryversion.h" -#pragma comment(lib, "Psapi.lib") -#include -#include -#include -#include -#include "Localization.h" - -#include "def.h" - -#define WM_MSG_GUI_SECTION WM_USER + 1 -#define WM_MSG_GUI_SECTION_GET 1 - -#ifdef __cplusplus -#define EP_INLINE inline -#else -#define EP_INLINE -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -DEFINE_GUID(CLSID_ImmersiveShell, - 0xc2f03a33, - 0x21f5, 0x47fa, 0xb4, 0xbb, - 0x15, 0x63, 0x62, 0xa2, 0xf2, 0x39 -); - -DEFINE_GUID(IID_OpenControlPanel, - 0xD11AD862, - 0x66De, 0x4DF4, 0xBf, 0x6C, - 0x1F, 0x56, 0x21, 0x99, 0x6A, 0xF1 -); - -DEFINE_GUID(CLSID_VBScript, - 0xB54F3741, - 0x5B07, 0x11CF, 0xA4, 0xB0, - 0x00, 0xAA, 0x00, 0x4A, 0x55, 0xE8 -); - -DEFINE_GUID(CLSID_NetworkListManager, - 0xDCB00C01, 0x570F, 0x4A9B, 0x8D, 0x69, 0x19, 0x9F, 0xDB, 0xA5, 0x72, 0x3B); - -DEFINE_GUID(IID_NetworkListManager, - 0xDCB00000, 0x570F, 0x4A9B, 0x8D, 0x69, 0x19, 0x9F, 0xDB, 0xA5, 0x72, 0x3B); - -typedef struct _StuckRectsData -{ - int pvData[6]; - RECT rc; - POINT pt; -} StuckRectsData; - -HRESULT FindDesktopFolderView(REFIID riid, void** ppv); - -HRESULT GetDesktopAutomationObject(REFIID riid, void** ppv); - -HRESULT ShellExecuteFromExplorer( - PCWSTR pszFile, - PCWSTR pszParameters, - PCWSTR pszDirectory, - PCWSTR pszOperation, - int nShowCmd -); - -void ToggleTaskbarAutohide(); - -#pragma region "Enable old taskbar" -typedef interface ITrayUIHost ITrayUIHost; - -typedef interface ITrayUI ITrayUI; - -DEFINE_GUID(IID_ITrayUI, - 0x12b454e1, - 0x6e50, 0x42b8, 0xbc, 0x3e, - 0xae, 0x7f, 0x54, 0x91, 0x99, 0xd6 -); - -DEFINE_GUID(IID_ITrayUIComponent, - 0x27775f88, - 0x01d3, 0x46ec, 0xa1, 0xc1, - 0x64, 0xb4, 0xc0, 0x9b, 0x21, 0x1b -); - -typedef HRESULT(*TrayUI_CreateInstance_t)(ITrayUIHost* host, REFIID riid, void** ppv); -EP_INLINE TrayUI_CreateInstance_t explorer_TrayUI_CreateInstanceFunc; -#pragma endregion - -inline int FileExistsW(wchar_t* file) -{ - WIN32_FIND_DATAW FindFileData; - HANDLE handle = FindFirstFileW(file, &FindFileData); - int found = handle != INVALID_HANDLE_VALUE; - if (found) - { - FindClose(handle); - } - return found; -} - -// https://stackoverflow.com/questions/1672677/print-a-guid-variable -void printf_guid(GUID guid); - -#ifdef _DEBUG -LRESULT CALLBACK BalloonWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - -__declspec(dllexport) int CALLBACK ZZTestBalloon(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow); - -__declspec(dllexport) int CALLBACK ZZTestToast(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow); -#endif - -#ifndef EP_BUILD_SETUP -__declspec(dllexport) int CALLBACK ZZLaunchExplorer(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow); - -__declspec(dllexport) int CALLBACK ZZLaunchExplorerDelayed(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow); - -__declspec(dllexport) int CALLBACK ZZRestartExplorer(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow); -#endif - -#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) -#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) - -typedef LSTATUS(*t_SHRegGetValueFromHKCUHKLM)( - PCWSTR pwszKey, - PCWSTR pwszValue, - int/*SRRF*/ srrfFlags, - DWORD* pdwType, - void* pvData, - DWORD* pcbData -); -EP_INLINE t_SHRegGetValueFromHKCUHKLM SHRegGetValueFromHKCUHKLMFunc; - -inline LSTATUS SHRegGetValueFromHKCUHKLMWithOpt( - PCWSTR pwszKey, - PCWSTR pwszValue, - REGSAM samDesired, - void* pvData, - DWORD* pcbData -) -{ - LSTATUS lRes = ERROR_FILE_NOT_FOUND; - HKEY hKey = NULL; - - RegOpenKeyExW( - HKEY_CURRENT_USER, - pwszKey, - 0, - samDesired, - &hKey - ); - if (hKey == NULL || hKey == INVALID_HANDLE_VALUE) - { - hKey = NULL; - } - if (hKey) - { - lRes = RegQueryValueExW( - hKey, - pwszValue, - 0, - NULL, - (LPBYTE)pvData, - pcbData - ); - RegCloseKey(hKey); - if (lRes == ERROR_SUCCESS || lRes == ERROR_MORE_DATA) - { - return lRes; - } - } - RegOpenKeyExW( - HKEY_LOCAL_MACHINE, - pwszKey, - 0, - samDesired, - &hKey - ); - if (hKey == NULL || hKey == INVALID_HANDLE_VALUE) - { - hKey = NULL; - } - if (hKey) - { - lRes = RegQueryValueExW( - hKey, - pwszValue, - 0, - NULL, - (LPBYTE)pvData, - pcbData - ); - RegCloseKey(hKey); - if (lRes == ERROR_SUCCESS || lRes == ERROR_MORE_DATA) - { - return lRes; - } - } - return lRes; -} - -EP_INLINE HWND(WINAPI* CreateWindowInBand)( - _In_ DWORD dwExStyle, - _In_opt_ LPCWSTR lpClassName, - _In_opt_ LPCWSTR lpWindowName, - _In_ DWORD dwStyle, - _In_ int X, - _In_ int Y, - _In_ int nWidth, - _In_ int nHeight, - _In_opt_ HWND hWndParent, - _In_opt_ HMENU hMenu, - _In_opt_ HINSTANCE hInstance, - _In_opt_ LPVOID lpParam, - DWORD band -); - -EP_INLINE BOOL(WINAPI* GetWindowBand)(HWND hWnd, PDWORD pdwBand); - -EP_INLINE BOOL(WINAPI* SetWindowBand)(HWND hWnd, HWND hwndInsertAfter, DWORD dwBand); - -EP_INLINE INT64(*SetWindowCompositionAttribute)(HWND, void*); - -// uxtheme.dll private functions - -typedef enum IMMERSIVE_COLOR_TYPE -{ - // Defining only used ones - IMCLR_SystemAccentLight2 = 2, - IMCLR_SystemAccentDark2 = 6 -} IMMERSIVE_COLOR_TYPE; - -typedef struct IMMERSIVE_COLOR_PREFERENCE -{ - DWORD crStartColor; - DWORD crAccentColor; -} IMMERSIVE_COLOR_PREFERENCE; - -typedef enum IMMERSIVE_HC_CACHE_MODE -{ - IHCM_USE_CACHED_VALUE = 0, - IHCM_REFRESH = 1 -} IMMERSIVE_HC_CACHE_MODE; - -typedef void(*GetThemeName_t)(void*, void*, void*); // 74 -EP_INLINE GetThemeName_t GetThemeName; - -typedef bool(*RefreshImmersiveColorPolicyState_t)(); // 104 -EP_INLINE RefreshImmersiveColorPolicyState_t RefreshImmersiveColorPolicyState; - -typedef bool(*GetIsImmersiveColorUsingHighContrast_t)(IMMERSIVE_HC_CACHE_MODE); // 106 -EP_INLINE GetIsImmersiveColorUsingHighContrast_t GetIsImmersiveColorUsingHighContrast; - -typedef HRESULT(*GetUserColorPreference_t)(IMMERSIVE_COLOR_PREFERENCE*, bool); // 120 -EP_INLINE GetUserColorPreference_t GetUserColorPreference; - -typedef DWORD(*GetColorFromPreference_t)(const IMMERSIVE_COLOR_PREFERENCE*, IMMERSIVE_COLOR_TYPE, bool, IMMERSIVE_HC_CACHE_MODE); // 121 -EP_INLINE GetColorFromPreference_t GetColorFromPreference; - -typedef bool(*ShouldAppsUseDarkMode_t)(); // 132 -EP_INLINE ShouldAppsUseDarkMode_t ShouldAppsUseDarkMode; - -typedef void(*AllowDarkModeForWindow_t)(HWND hWnd, BOOL bAllowDark); // 133 -EP_INLINE AllowDarkModeForWindow_t AllowDarkModeForWindow; - -typedef void(*SetPreferredAppMode_t)(BOOL bAllowDark); // 135 -EP_INLINE SetPreferredAppMode_t SetPreferredAppMode; - -typedef bool(*ShouldSystemUseDarkMode_t)(); // 138 -EP_INLINE ShouldSystemUseDarkMode_t ShouldSystemUseDarkMode; - -void* ReadFromFile(wchar_t* wszFileName, DWORD* dwSize); - -int ComputeFileHash(LPCWSTR filename, LPSTR hash, DWORD dwHash); - -int ComputeFileHash2(HMODULE hModule, LPCWSTR filename, LPSTR hash, DWORD dwHash); - -void GetHardcodedHash(LPCWSTR wszPath, LPSTR hash, DWORD dwHash); - -void LaunchPropertiesGUI(HMODULE hModule); - -BOOL SystemShutdown(BOOL reboot); - -LSTATUS RegisterDWMService(DWORD dwDesiredState, DWORD dwOverride); - -char* StrReplaceAllA(const char* s, const char* oldW, const char* newW, int* dwNewSize); - -WCHAR* StrReplaceAllW(const WCHAR* s, const WCHAR* oldW, const WCHAR* newW, int* dwNewSize); - -HRESULT InputBox(BOOL bPassword, HWND hWnd, LPCWSTR wszPrompt, LPCWSTR wszTitle, LPCWSTR wszDefault, LPWSTR wszAnswer, DWORD cbAnswer, BOOL* bCancelled); - -BOOL GetLogonSid(PSID* ppsid); - -BOOL PrepareSecurityDescriptor(PSID pMainSid, DWORD dwMainPermissions, PSID pSecondarySid, DWORD dwSecondayPermissions, PSECURITY_DESCRIPTOR* ppSD); - -inline BOOL IsHighContrast() -{ - HIGHCONTRASTW highContrast; - ZeroMemory(&highContrast, sizeof(HIGHCONTRASTW)); - highContrast.cbSize = sizeof(highContrast); - if (SystemParametersInfoW(SPI_GETHIGHCONTRAST, sizeof(highContrast), &highContrast, FALSE)) - return highContrast.dwFlags & HCF_HIGHCONTRASTON; - return FALSE; -} - -// https://codereview.stackexchange.com/questions/29198/random-string-generator-in-c -static inline WCHAR* rand_string(WCHAR* str, size_t size) -{ - const WCHAR charset[] = L"abcdefghijklmnopqrstuvwxyz"; - if (size) { - --size; - for (size_t n = 0; n < size; n++) { - int key = rand() % (int)((sizeof(charset) / sizeof(WCHAR)) - 1); - str[n] = charset[key]; - } - str[size] = L'\0'; - } - return str; -} - -inline long long milliseconds_now() { - LARGE_INTEGER s_frequency; - BOOL s_use_qpc = QueryPerformanceFrequency(&s_frequency); - if (s_use_qpc) { - LARGE_INTEGER now; - QueryPerformanceCounter(&now); - return (1000LL * now.QuadPart) / s_frequency.QuadPart; - } - else { - return GetTickCount(); - } -} - -inline BOOL IsAppRunningAsAdminMode() -{ - BOOL fIsRunAsAdmin = FALSE; - DWORD dwError = ERROR_SUCCESS; - PSID pAdministratorsGroup = NULL; - - // Allocate and initialize a SID of the administrators group. - SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; - if (!AllocateAndInitializeSid( - &NtAuthority, - 2, - SECURITY_BUILTIN_DOMAIN_RID, - DOMAIN_ALIAS_RID_ADMINS, - 0, 0, 0, 0, 0, 0, - &pAdministratorsGroup)) - { - dwError = GetLastError(); - goto Cleanup; - } - - // Determine whether the SID of administrators group is enabled in - // the primary access token of the process. - if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin)) - { - dwError = GetLastError(); - goto Cleanup; - } - -Cleanup: - // Centralized cleanup for all allocated resources. - if (pAdministratorsGroup) - { - FreeSid(pAdministratorsGroup); - pAdministratorsGroup = NULL; - } - - // Throw the error if something failed in the function. - if (ERROR_SUCCESS != dwError) - { - return FALSE; - } - - return fIsRunAsAdmin; -} - -inline BOOL IsDesktopWindowAlreadyPresent() -{ - return (FindWindowExW(NULL, NULL, L"Progman", NULL) || FindWindowExW(NULL, NULL, L"Proxy Desktop", NULL)); -} - -// https://jiangsheng.net/2013/01/22/how-to-restart-windows-explorer-programmatically-using-restart-manager/ -inline RM_UNIQUE_PROCESS GetExplorerApplication() -{ - HWND hwnd = FindWindow(L"Shell_TrayWnd", NULL); - DWORD pid = 0; - GetWindowThreadProcessId(hwnd, &pid); - - RM_UNIQUE_PROCESS out = { 0, { (DWORD)-1, (DWORD)-1 } }; - DWORD bytesReturned; - WCHAR imageName[MAX_PATH]; // process image name buffer - DWORD processIds[2048]; // max 2048 processes (more than enough) - - // enumerate all running processes (usually around 60-70) - EnumProcesses(processIds, sizeof(processIds), &bytesReturned); - int count = bytesReturned / sizeof(DWORD); // number of processIds returned - - for (int i = 0; i < count; ++i) - { - DWORD processId = processIds[i]; - HANDLE hProc; - if (processId == pid && (hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId))) - { - GetProcessImageFileNameW(hProc, imageName, MAX_PATH); - FILETIME ftStart, ftExit, ftKernel, ftUser; - GetProcessTimes(hProc, &ftStart, &ftExit, &ftKernel, &ftUser); - - if (ftStart.dwLowDateTime < out.ProcessStartTime.dwLowDateTime) - { - out.dwProcessId = processId; - out.ProcessStartTime = ftStart; - } - CloseHandle(hProc); - } - } - return out; // return count in pResults -} - -static DWORD RmSession = -1; -static wchar_t RmSessionKey[CCH_RM_SESSION_KEY + 1]; - -// shuts down the explorer and is ready for explorer restart -inline DWORD WINAPI BeginExplorerRestart(LPVOID lpUnused) -{ - if (RmStartSession(&RmSession, 0, RmSessionKey) == ERROR_SUCCESS) - { - RM_UNIQUE_PROCESS rgApplications[] = { GetExplorerApplication() }; - RmRegisterResources(RmSession, 0, 0, 1, rgApplications, 0, 0); - - DWORD rebootReason; - UINT nProcInfoNeeded, nProcInfo = 16; - RM_PROCESS_INFO affectedApps[16]; - RmGetList(RmSession, &nProcInfoNeeded, &nProcInfo, affectedApps, &rebootReason); - - if (rebootReason == RmRebootReasonNone) // no need for reboot? - { - // shutdown explorer - RmShutdown(RmSession, RmForceShutdown, 0); - } - } - return 0; -} -// restarts the explorer -inline void FinishExplorerRestart() -{ - DWORD dwError; - if (dwError = RmRestart(RmSession, 0, NULL)) - printf("\n RmRestart error: %d\n\n", dwError); - - RmEndSession(RmSession); - RmSession = -1; - RmSessionKey[0] = 0; -} - -// https://stackoverflow.com/questions/5689904/gracefully-exit-explorer-programmatically -inline BOOL ExitExplorer() -{ - HWND hWndTray = FindWindowW(L"Shell_TrayWnd", NULL); - return PostMessageW(hWndTray, 0x5B4, 0, 0); -} - -inline void StartExplorerWithDelay(int delay, HANDLE userToken) -{ - WCHAR wszPath[MAX_PATH]; - ZeroMemory(wszPath, MAX_PATH * sizeof(WCHAR)); - GetWindowsDirectoryW(wszPath, MAX_PATH); - wcscat_s(wszPath, MAX_PATH, L"\\explorer.exe"); - Sleep(delay); - if (userToken != INVALID_HANDLE_VALUE) - { - HANDLE primaryUserToken = INVALID_HANDLE_VALUE; - if (ImpersonateLoggedOnUser(userToken)) - { - DuplicateTokenEx(userToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &primaryUserToken); - RevertToSelf(); - } - if (primaryUserToken != INVALID_HANDLE_VALUE) - { - PROCESS_INFORMATION processInfo; - ZeroMemory(&processInfo, sizeof(processInfo)); - STARTUPINFOW startupInfo; - ZeroMemory(&startupInfo, sizeof(startupInfo)); - startupInfo.cb = sizeof(startupInfo); - BOOL processCreated = CreateProcessWithTokenW( - primaryUserToken, LOGON_WITH_PROFILE, wszPath, NULL, 0, NULL, NULL, &startupInfo, &processInfo) != 0; - CloseHandle(primaryUserToken); - if (processInfo.hProcess != INVALID_HANDLE_VALUE) - { - CloseHandle(processInfo.hProcess); - } - if (processInfo.hThread != INVALID_HANDLE_VALUE) - { - CloseHandle(processInfo.hThread); - } - if (processCreated) - { - return; - } - } - } - ShellExecuteW( - NULL, - L"open", - wszPath, - NULL, - NULL, - SW_SHOWNORMAL - ); -} - -inline void StartExplorer() -{ - - /*PROCESSENTRY32 pe32 = {0}; - pe32.dwSize = sizeof(PROCESSENTRY32); - HANDLE hSnapshot = CreateToolhelp32Snapshot( - TH32CS_SNAPPROCESS, - 0 - ); - if (Process32First(hSnapshot, &pe32) == TRUE) - { - do - { - if (!wcscmp(pe32.szExeFile, TEXT("explorer.exe"))) - { - HANDLE hSihost = OpenProcess( - PROCESS_TERMINATE, - FALSE, - pe32.th32ProcessID - ); - TerminateProcess(hSihost, 1); - CloseHandle(hSihost); - } - } while (Process32Next(hSnapshot, &pe32) == TRUE); - } - CloseHandle(hSnapshot); - */ - wchar_t wszPath[MAX_PATH]; - ZeroMemory( - wszPath, - (MAX_PATH) * sizeof(wchar_t) - ); - GetWindowsDirectoryW( - wszPath, - MAX_PATH - ); - wcscat_s( - wszPath, - MAX_PATH, - L"\\explorer.exe" - ); - STARTUPINFO si; - ZeroMemory(&si, sizeof(STARTUPINFO)); - si.cb = sizeof(si); - PROCESS_INFORMATION pi; - ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); - if (CreateProcessW( - NULL, - wszPath, - NULL, - NULL, - TRUE, - CREATE_UNICODE_ENVIRONMENT, - NULL, - NULL, - &si, - &pi - )) - { - CloseHandle(pi.hThread); - CloseHandle(pi.hProcess); - } -} - -inline BOOL IncrementDLLReferenceCount(HINSTANCE hinst) -{ - HMODULE hMod; - GetModuleHandleExW( - GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, - (LPCWSTR)hinst, - &hMod); - return TRUE; -} - -PVOID FindPattern(PVOID pBase, SIZE_T dwSize, LPCSTR lpPattern, LPCSTR lpMask); - -#if _M_X64 -inline BOOL FollowJnz(PBYTE pJnz, PBYTE* pTarget, DWORD* pJnzSize) -{ - // Check big jnz - if (pJnz[0] == 0x0F && pJnz[1] == 0x85) - { - *pTarget = pJnz + 6 + *(int*)(pJnz + 2); - *pJnzSize = 6; - return TRUE; - } - // Check small jnz - if (pJnz[0] == 0x75) - { - *pTarget = pJnz + 2 + *(char*)(pJnz + 1); - *pJnzSize = 2; - return TRUE; - } - return FALSE; -} -#endif - -#if _M_ARM64 -// https://github.com/CAS-Atlantic/AArch64-Encoding - -__forceinline DWORD ARM64_ReadBits(DWORD value, int h, int l) -{ - return (value >> l) & ((1 << (h - l + 1)) - 1); -} - -__forceinline int ARM64_SignExtend(DWORD value, int numBits) -{ - DWORD mask = 1 << (numBits - 1); - if (value & mask) - value |= ~((1 << numBits) - 1); - return (int)value; -} - -__forceinline int ARM64_ReadBitsSignExtend(DWORD insn, int h, int l) -{ - return ARM64_SignExtend(ARM64_ReadBits(insn, h, l), h - l + 1); -} - -__forceinline BOOL ARM64_IsInRange(int value, int bitCount) -{ - int minVal = -(1 << (bitCount - 1)); - int maxVal = (1 << (bitCount - 1)) - 1; - return value >= minVal && value <= maxVal; -} - -__forceinline UINT_PTR ARM64_Align(UINT_PTR value, UINT_PTR alignment) -{ - return value & ~(alignment - 1); -} - -__forceinline BOOL ARM64_IsCBZW(DWORD insn) { return ARM64_ReadBits(insn, 31, 24) == 0b00110100; } -__forceinline BOOL ARM64_IsCBNZW(DWORD insn) { return ARM64_ReadBits(insn, 31, 24) == 0b00110101; } -__forceinline BOOL ARM64_IsBL(DWORD insn) { return ARM64_ReadBits(insn, 31, 26) == 0b100101; } -__forceinline BOOL ARM64_IsADRP(DWORD insn) { return (ARM64_ReadBits(insn, 31, 24) & ~0b01100000) == 0b10010000; } - -__forceinline DWORD* ARM64_FollowBL(DWORD* pInsnBL) -{ - DWORD insnBL = *pInsnBL; - if (!ARM64_IsBL(insnBL)) - return NULL; - int imm26 = ARM64_ReadBitsSignExtend(insnBL, 25, 0); - return pInsnBL + imm26; // offset = imm26 * 4 -} - -__forceinline DWORD ARM64_MakeB(int imm26) -{ - if (!ARM64_IsInRange(imm26, 26)) - return 0; - return 0b000101 << 26 | imm26 & (1 << 26) - 1; -} - -__forceinline DWORD ARM64_CBZWToB(DWORD insnCBZW) -{ - if (!ARM64_IsCBZW(insnCBZW)) - return 0; - int imm19 = ARM64_ReadBitsSignExtend(insnCBZW, 23, 5); - return ARM64_MakeB(imm19); -} - -__forceinline DWORD ARM64_CBNZWToB(DWORD insnCBNZW) -{ - if (!ARM64_IsCBNZW(insnCBNZW)) - return 0; - int imm19 = ARM64_ReadBitsSignExtend(insnCBNZW, 23, 5); - return ARM64_MakeB(imm19); -} - -__forceinline DWORD ARM64_DecodeADD(DWORD insnADD) -{ - DWORD imm12 = ARM64_ReadBits(insnADD, 21, 10); - DWORD shift = ARM64_ReadBits(insnADD, 22, 22); - return imm12 << (shift * 12); -} - -__forceinline DWORD ARM64_DecodeSTRBIMM(DWORD insnSTRBIMM) -{ - if (ARM64_ReadBits(insnSTRBIMM, 31, 22) != 0b0011100100) - return (DWORD)-1; - DWORD imm12 = ARM64_ReadBits(insnSTRBIMM, 21, 10); - return imm12; -} - -__forceinline DWORD ARM64_DecodeLDRBIMM(DWORD insnLDRBIMM) -{ - if (ARM64_ReadBits(insnLDRBIMM, 31, 22) != 0b0011100101) - return (DWORD)-1; - DWORD imm12 = ARM64_ReadBits(insnLDRBIMM, 21, 10); - return imm12; -} - -inline UINT_PTR ARM64_DecodeADRL(UINT_PTR offset, DWORD insnADRP, DWORD insnADD) -{ - if (!ARM64_IsADRP(insnADRP)) - return 0; - - UINT_PTR page = ARM64_Align(offset, 0x1000); - - DWORD adrp_immlo = ARM64_ReadBits(insnADRP, 30, 29); - DWORD adrp_immhi = ARM64_ReadBits(insnADRP, 23, 5); - DWORD adrp_imm = ((adrp_immhi << 2) | adrp_immlo) << 12; - - DWORD add_imm = ARM64_DecodeADD(insnADD); - - return page + adrp_imm + add_imm; -} -#endif - -#if defined(WITH_MAIN_PATCHER) && WITH_MAIN_PATCHER -inline BOOL WINAPI PatchContextMenuOfNewMicrosoftIME(BOOL* bFound) -{ - // huge thanks to @Simplestas: https://github.com/valinet/ExplorerPatcher/issues/598 - HMODULE hInputSwitch = NULL; - if (!GetModuleHandleExW(0, L"InputSwitch.dll", &hInputSwitch)) - return FALSE; - - MODULEINFO mi; - GetModuleInformation(GetCurrentProcess(), hInputSwitch, &mi, sizeof(mi)); - -#if defined(_M_X64) - // 44 38 ?? ?? 74 ?? ?? 8B CE E8 ?? ?? ?? ?? 85 C0 - // ^^ Change jz into jmp - PBYTE match = (PBYTE)FindPattern( - hInputSwitch, - mi.SizeOfImage, - "\x44\x38\x00\x00\x74\x00\x00\x8B\xCE\xE8\x00\x00\x00\x00\x85\xC0", - "xx??x??xxx????xx" - ); - if (!match) - return FALSE; - - DWORD dwOldProtect; - if (!VirtualProtect(match + 4, 1, PAGE_EXECUTE_READWRITE, &dwOldProtect)) - return FALSE; - - match[4] = 0xEB; - - VirtualProtect(match + 4, 1, dwOldProtect, &dwOldProtect); - - return TRUE; -#elif defined(_M_ARM64) - // A8 43 40 39 C8 04 00 34 E0 03 14 AA - // ^^^^^^^^^^^ Change CBZ to B - PBYTE match = (PBYTE)FindPattern( - hInputSwitch, - mi.SizeOfImage, - "\xA8\x43\x40\x39\xC8\x04\x00\x34\xE0\x03\x14\xAA", - "xxxxxxxxxxxx" - ); - if (!match) - return FALSE; - - match += 4; - - DWORD newInsn = ARM64_CBZWToB(*(DWORD*)match); - if (!newInsn) - return FALSE; - - DWORD dwOldProtect; - if (!VirtualProtect(match, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect)) - return FALSE; - - *(DWORD*)match = newInsn; - - VirtualProtect(match, 4, dwOldProtect, &dwOldProtect); - - return TRUE; -#endif -} -#endif - -extern UINT PleaseWaitTimeout; -extern HHOOK PleaseWaitHook; -extern HWND PleaseWaitHWND; -extern void* PleaseWaitCallbackData; -extern BOOL (*PleaseWaitCallbackFunc)(void* data); -BOOL PleaseWait_UpdateTimeout(int timeout); -VOID CALLBACK PleaseWait_TimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime); -LRESULT CALLBACK PleaseWait_HookProc(int code, WPARAM wParam, LPARAM lParam); - -BOOL DownloadAndInstallWebView2Runtime(); - -BOOL DownloadFile(LPCWSTR wszURL, DWORD dwSize, LPCWSTR wszPath); - -BOOL IsConnectedToInternet(); - -#define SCRATCH_QCM_FIRST 1 -#define SCRATCH_QCM_LAST 0x7FFF - -#define SPOP_OPENMENU 1 -#define SPOP_INSERTMENU_ALL 0b1111110000 -#define SPOP_INSERTMENU_OPEN 0b0000010000 -#define SPOP_INSERTMENU_NEXTPIC 0b0000100000 -#define SPOP_INSERTMENU_LIKE 0b0001000000 -#define SPOP_INSERTMENU_DISLIKE 0b0010000000 -#define SPOP_INSERTMENU_INFOTIP1 0b0100000000 -#define SPOP_INSERTMENU_INFOTIP2 0b1000000000 -#define SPOP_CLICKMENU_FIRST 40000 -#define SPOP_CLICKMENU_OPEN 40000 -#define SPOP_CLICKMENU_NEXTPIC 40001 -#define SPOP_CLICKMENU_LIKE 40002 -#define SPOP_CLICKMENU_DISLIKE 40003 -#define SPOP_CLICKMENU_LAST 40003 - -BOOL DoesOSBuildSupportSpotlight(); - -BOOL IsSpotlightEnabled(); - -void SpotlightHelper(DWORD dwOp, HWND hWnd, HMENU hMenu, LPPOINT pPt); - -typedef struct _MonitorOverrideData -{ - DWORD cbIndex; - DWORD dwIndex; - HMONITOR hMonitor; -} MonitorOverrideData; - -BOOL ExtractMonitorByIndex(HMONITOR hMonitor, HDC hDC, LPRECT lpRect, MonitorOverrideData* mod); -HRESULT SHRegGetBOOLWithREGSAM(HKEY key, LPCWSTR subKey, LPCWSTR value, REGSAM regSam, BOOL* data); -HRESULT SHRegGetDWORD(HKEY hkey, const WCHAR* pwszSubKey, const WCHAR* pwszValue, DWORD* pdwData); - -inline BOOL MaskCompare(PVOID pBuffer, LPCSTR lpPattern, LPCSTR lpMask) -{ - for (PBYTE value = (PBYTE)pBuffer; *lpMask; ++lpPattern, ++lpMask, ++value) - { - if (*lpMask == 'x' && *(LPCBYTE)lpPattern != *value) - return FALSE; - } - - return TRUE; -} - -inline __declspec(noinline) PVOID FindPatternHelper(PVOID pBase, SIZE_T dwSize, LPCSTR lpPattern, LPCSTR lpMask) -{ - for (SIZE_T index = 0; index < dwSize; ++index) - { - PBYTE pAddress = (PBYTE)pBase + index; - - if (MaskCompare(pAddress, lpPattern, lpMask)) - return pAddress; - } - - return NULL; -} - -inline PVOID FindPattern(PVOID pBase, SIZE_T dwSize, LPCSTR lpPattern, LPCSTR lpMask) -{ - dwSize -= strlen(lpMask); - return FindPatternHelper(pBase, dwSize, lpPattern, lpMask); -} - -inline UINT_PTR FileOffsetToRVA(PBYTE pBase, UINT_PTR offset) -{ - PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBase; - PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)(pBase + pDosHeader->e_lfanew); - PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHeaders); - for (int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++, pSection++) - { - if (offset >= pSection->PointerToRawData && offset < pSection->PointerToRawData + pSection->SizeOfRawData) - return offset - pSection->PointerToRawData + pSection->VirtualAddress; - } - return 0; -} - -inline UINT_PTR RVAToFileOffset(PBYTE pBase, UINT_PTR rva) -{ - PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBase; - PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)(pBase + pDosHeader->e_lfanew); - PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHeaders); - for (int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++, pSection++) - { - if (rva >= pSection->VirtualAddress && rva < pSection->VirtualAddress + pSection->Misc.VirtualSize) - return rva - pSection->VirtualAddress + pSection->PointerToRawData; - } - return 0; -} - -inline HMODULE LoadGuiModule() -{ - wchar_t epGuiPath[MAX_PATH]; - ZeroMemory(epGuiPath, sizeof(epGuiPath)); - SHGetFolderPathW(NULL, SPECIAL_FOLDER, NULL, SHGFP_TYPE_CURRENT, epGuiPath); - wcscat_s(epGuiPath, MAX_PATH, _T(APP_RELATIVE_PATH) L"\\ep_gui.dll"); - return LoadLibraryExW(epGuiPath, NULL, LOAD_LIBRARY_AS_DATAFILE); -} - -inline BOOL DoesWindows10StartMenuExist() -{ - if (!IsWindows11()) - return TRUE; - - wchar_t szPath[MAX_PATH]; - GetWindowsDirectoryW(szPath, MAX_PATH); - wcscat_s(szPath, MAX_PATH, L"\\SystemApps\\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\\StartUI.dll"); - if (FileExistsW(szPath)) - return TRUE; - - GetWindowsDirectoryW(szPath, MAX_PATH); - wcscat_s(szPath, MAX_PATH, L"\\SystemApps\\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\\StartUI_.dll"); - if (FileExistsW(szPath)) - return TRUE; - - return FALSE; -} - -inline BOOL IsStockWindows10TaskbarAvailable() -{ -#if _M_X64 - return global_rovi.dwBuildNumber < 26002; -#else - return !IsWindows11(); -#endif -} - -inline const WCHAR* PickTaskbarDll() -{ - DWORD b = global_rovi.dwBuildNumber; - - if (b == 15063 // Windows 10 1703 - || b == 16299 // Windows 10 1709 - || b == 17134 // Windows 10 1803 - || b == 17763 // Windows 10 1809 - || b >= 18362 && b <= 18363 // Windows 10 1903, 1909 - || b >= 19041 && b <= 19045) // Windows 10 20H2, 21H2, 22H2 - { - return L"ep_taskbar.0.dll"; - } - - if (b >= 21343 && b <= 22000) // Windows 11 21H2 - { - return L"ep_taskbar.1.dll"; - } - - if ((b >= 22621 && b <= 22635) // 22H2-23H2 Release, Release Preview, and Beta channels - || (b >= 23403 && b <= 25197)) // Early pre-reboot Dev channel until post-reboot Dev channel - { - return L"ep_taskbar.2.dll"; - } - - if (b >= 25201 && b <= 25915) // Pre-reboot Dev channel until early Canary channel, nuked ITrayComponentHost methods related to classic search box - { - return L"ep_taskbar.3.dll"; - } - - if (b >= 25921 && b <= 26040) // Canary channel with nuked classic system tray - { - return L"ep_taskbar.4.dll"; - } - - if (b >= 26052) // Same as 4 but with 2 new methods in ITrayComponentHost between GetTrayUI and ProgrammableTaskbarReportClick - { - return L"ep_taskbar.5.dll"; - } - - return NULL; -} - -inline BOOL DoesTaskbarDllExist() -{ - const wchar_t* pszTaskbarDll = PickTaskbarDll(); - if (!pszTaskbarDll) - return FALSE; - - wchar_t szPath[MAX_PATH]; - ZeroMemory(szPath, sizeof(szPath)); - SHGetFolderPathW(NULL, SPECIAL_FOLDER, NULL, SHGFP_TYPE_CURRENT, szPath); - wcscat_s(szPath, MAX_PATH, _T(APP_RELATIVE_PATH) L"\\"); - wcscat_s(szPath, MAX_PATH, pszTaskbarDll); - return FileExistsW(szPath); -} - -inline void AdjustTaskbarStyleValue(DWORD* pdwValue) -{ - if (*pdwValue >= 2 && !DoesTaskbarDllExist()) - { - *pdwValue = 1; - } - - if (IsWindows11()) - { - if (*pdwValue == 1 && !IsStockWindows10TaskbarAvailable()) - { - *pdwValue = 0; - } - } - else - { - if (*pdwValue == 0) - { - *pdwValue = 1; // There's no such thing as Windows 11 taskbar on Windows 10 - } - } -} - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef _H_UTILITY_H_ +#define _H_UTILITY_H_ +#if __has_include("ep_private.h") +//#define USE_PRIVATE_INTERFACES +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#pragma comment(lib, "Rstrtmgr.lib") +#define _LIBVALINET_INCLUDE_UNIVERSAL +#ifndef __cplusplus +#include +#endif +#include "osutility.h" +#include "queryversion.h" +#pragma comment(lib, "Psapi.lib") +#include +#include +#include +#include +#include "Localization.h" + +#include "def.h" + +#define WM_MSG_GUI_SECTION WM_USER + 1 +#define WM_MSG_GUI_SECTION_GET 1 + +#ifdef __cplusplus +#define EP_INLINE inline +#else +#define EP_INLINE +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +DEFINE_GUID(CLSID_ImmersiveShell, + 0xc2f03a33, + 0x21f5, 0x47fa, 0xb4, 0xbb, + 0x15, 0x63, 0x62, 0xa2, 0xf2, 0x39 +); + +DEFINE_GUID(IID_OpenControlPanel, + 0xD11AD862, + 0x66De, 0x4DF4, 0xBf, 0x6C, + 0x1F, 0x56, 0x21, 0x99, 0x6A, 0xF1 +); + +DEFINE_GUID(CLSID_VBScript, + 0xB54F3741, + 0x5B07, 0x11CF, 0xA4, 0xB0, + 0x00, 0xAA, 0x00, 0x4A, 0x55, 0xE8 +); + +DEFINE_GUID(CLSID_NetworkListManager, + 0xDCB00C01, 0x570F, 0x4A9B, 0x8D, 0x69, 0x19, 0x9F, 0xDB, 0xA5, 0x72, 0x3B); + +DEFINE_GUID(IID_NetworkListManager, + 0xDCB00000, 0x570F, 0x4A9B, 0x8D, 0x69, 0x19, 0x9F, 0xDB, 0xA5, 0x72, 0x3B); + +typedef struct _StuckRectsData +{ + int pvData[6]; + RECT rc; + POINT pt; +} StuckRectsData; + +HRESULT FindDesktopFolderView(REFIID riid, void** ppv); + +HRESULT GetDesktopAutomationObject(REFIID riid, void** ppv); + +HRESULT ShellExecuteFromExplorer( + PCWSTR pszFile, + PCWSTR pszParameters, + PCWSTR pszDirectory, + PCWSTR pszOperation, + int nShowCmd +); + +void ToggleTaskbarAutohide(); + +#pragma region "Enable old taskbar" +typedef interface ITrayUIHost ITrayUIHost; + +typedef interface ITrayUI ITrayUI; + +DEFINE_GUID(IID_ITrayUI, + 0x12b454e1, + 0x6e50, 0x42b8, 0xbc, 0x3e, + 0xae, 0x7f, 0x54, 0x91, 0x99, 0xd6 +); + +DEFINE_GUID(IID_ITrayUIComponent, + 0x27775f88, + 0x01d3, 0x46ec, 0xa1, 0xc1, + 0x64, 0xb4, 0xc0, 0x9b, 0x21, 0x1b +); + +typedef HRESULT(*TrayUI_CreateInstance_t)(ITrayUIHost* host, REFIID riid, void** ppv); +EP_INLINE TrayUI_CreateInstance_t explorer_TrayUI_CreateInstanceFunc; +#pragma endregion + +inline int FileExistsW(wchar_t* file) +{ + WIN32_FIND_DATAW FindFileData; + HANDLE handle = FindFirstFileW(file, &FindFileData); + int found = handle != INVALID_HANDLE_VALUE; + if (found) + { + FindClose(handle); + } + return found; +} + +// https://stackoverflow.com/questions/1672677/print-a-guid-variable +void printf_guid(GUID guid); + +#ifdef _DEBUG +LRESULT CALLBACK BalloonWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +__declspec(dllexport) int CALLBACK ZZTestBalloon(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow); + +__declspec(dllexport) int CALLBACK ZZTestToast(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow); +#endif + +#ifndef EP_BUILD_SETUP +__declspec(dllexport) int CALLBACK ZZLaunchExplorer(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow); + +__declspec(dllexport) int CALLBACK ZZLaunchExplorerDelayed(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow); + +__declspec(dllexport) int CALLBACK ZZRestartExplorer(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow); +#endif + +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) +#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) + +typedef LSTATUS(*t_SHRegGetValueFromHKCUHKLM)( + PCWSTR pwszKey, + PCWSTR pwszValue, + int/*SRRF*/ srrfFlags, + DWORD* pdwType, + void* pvData, + DWORD* pcbData +); +EP_INLINE t_SHRegGetValueFromHKCUHKLM SHRegGetValueFromHKCUHKLMFunc; + +inline LSTATUS SHRegGetValueFromHKCUHKLMWithOpt( + PCWSTR pwszKey, + PCWSTR pwszValue, + REGSAM samDesired, + void* pvData, + DWORD* pcbData +) +{ + LSTATUS lRes = ERROR_FILE_NOT_FOUND; + HKEY hKey = NULL; + + RegOpenKeyExW( + HKEY_CURRENT_USER, + pwszKey, + 0, + samDesired, + &hKey + ); + if (hKey == NULL || hKey == INVALID_HANDLE_VALUE) + { + hKey = NULL; + } + if (hKey) + { + lRes = RegQueryValueExW( + hKey, + pwszValue, + 0, + NULL, + (LPBYTE)pvData, + pcbData + ); + RegCloseKey(hKey); + if (lRes == ERROR_SUCCESS || lRes == ERROR_MORE_DATA) + { + return lRes; + } + } + RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + pwszKey, + 0, + samDesired, + &hKey + ); + if (hKey == NULL || hKey == INVALID_HANDLE_VALUE) + { + hKey = NULL; + } + if (hKey) + { + lRes = RegQueryValueExW( + hKey, + pwszValue, + 0, + NULL, + (LPBYTE)pvData, + pcbData + ); + RegCloseKey(hKey); + if (lRes == ERROR_SUCCESS || lRes == ERROR_MORE_DATA) + { + return lRes; + } + } + return lRes; +} + +EP_INLINE HWND(WINAPI* CreateWindowInBand)( + _In_ DWORD dwExStyle, + _In_opt_ LPCWSTR lpClassName, + _In_opt_ LPCWSTR lpWindowName, + _In_ DWORD dwStyle, + _In_ int X, + _In_ int Y, + _In_ int nWidth, + _In_ int nHeight, + _In_opt_ HWND hWndParent, + _In_opt_ HMENU hMenu, + _In_opt_ HINSTANCE hInstance, + _In_opt_ LPVOID lpParam, + DWORD band +); + +EP_INLINE BOOL(WINAPI* GetWindowBand)(HWND hWnd, PDWORD pdwBand); + +EP_INLINE BOOL(WINAPI* SetWindowBand)(HWND hWnd, HWND hwndInsertAfter, DWORD dwBand); + +EP_INLINE INT64(*SetWindowCompositionAttribute)(HWND, void*); + +// uxtheme.dll private functions + +typedef enum IMMERSIVE_COLOR_TYPE +{ + // Defining only used ones + IMCLR_SystemAccentLight2 = 2, + IMCLR_SystemAccentDark2 = 6 +} IMMERSIVE_COLOR_TYPE; + +typedef struct IMMERSIVE_COLOR_PREFERENCE +{ + DWORD crStartColor; + DWORD crAccentColor; +} IMMERSIVE_COLOR_PREFERENCE; + +typedef enum IMMERSIVE_HC_CACHE_MODE +{ + IHCM_USE_CACHED_VALUE = 0, + IHCM_REFRESH = 1 +} IMMERSIVE_HC_CACHE_MODE; + +typedef void(*GetThemeName_t)(void*, void*, void*); // 74 +EP_INLINE GetThemeName_t GetThemeName; + +typedef bool(*RefreshImmersiveColorPolicyState_t)(); // 104 +EP_INLINE RefreshImmersiveColorPolicyState_t RefreshImmersiveColorPolicyState; + +typedef bool(*GetIsImmersiveColorUsingHighContrast_t)(IMMERSIVE_HC_CACHE_MODE); // 106 +EP_INLINE GetIsImmersiveColorUsingHighContrast_t GetIsImmersiveColorUsingHighContrast; + +typedef HRESULT(*GetUserColorPreference_t)(IMMERSIVE_COLOR_PREFERENCE*, bool); // 120 +EP_INLINE GetUserColorPreference_t GetUserColorPreference; + +typedef DWORD(*GetColorFromPreference_t)(const IMMERSIVE_COLOR_PREFERENCE*, IMMERSIVE_COLOR_TYPE, bool, IMMERSIVE_HC_CACHE_MODE); // 121 +EP_INLINE GetColorFromPreference_t GetColorFromPreference; + +typedef bool(*ShouldAppsUseDarkMode_t)(); // 132 +EP_INLINE ShouldAppsUseDarkMode_t ShouldAppsUseDarkMode; + +typedef void(*AllowDarkModeForWindow_t)(HWND hWnd, BOOL bAllowDark); // 133 +EP_INLINE AllowDarkModeForWindow_t AllowDarkModeForWindow; + +typedef void(*SetPreferredAppMode_t)(BOOL bAllowDark); // 135 +EP_INLINE SetPreferredAppMode_t SetPreferredAppMode; + +typedef bool(*ShouldSystemUseDarkMode_t)(); // 138 +EP_INLINE ShouldSystemUseDarkMode_t ShouldSystemUseDarkMode; + +void* ReadFromFile(wchar_t* wszFileName, DWORD* dwSize); + +int ComputeFileHash(LPCWSTR filename, LPSTR hash, DWORD dwHash); + +int ComputeFileHash2(HMODULE hModule, LPCWSTR filename, LPSTR hash, DWORD dwHash); + +void GetHardcodedHash(LPCWSTR wszPath, LPSTR hash, DWORD dwHash); + +void LaunchPropertiesGUI(HMODULE hModule); + +BOOL SystemShutdown(BOOL reboot); + +LSTATUS RegisterDWMService(DWORD dwDesiredState, DWORD dwOverride); + +char* StrReplaceAllA(const char* s, const char* oldW, const char* newW, int* dwNewSize); + +WCHAR* StrReplaceAllW(const WCHAR* s, const WCHAR* oldW, const WCHAR* newW, int* dwNewSize); + +HRESULT InputBox(BOOL bPassword, HWND hWnd, LPCWSTR wszPrompt, LPCWSTR wszTitle, LPCWSTR wszDefault, LPWSTR wszAnswer, DWORD cbAnswer, BOOL* bCancelled); + +BOOL GetLogonSid(PSID* ppsid); + +BOOL PrepareSecurityDescriptor(PSID pMainSid, DWORD dwMainPermissions, PSID pSecondarySid, DWORD dwSecondayPermissions, PSECURITY_DESCRIPTOR* ppSD); + +inline BOOL IsHighContrast() +{ + HIGHCONTRASTW highContrast; + ZeroMemory(&highContrast, sizeof(HIGHCONTRASTW)); + highContrast.cbSize = sizeof(highContrast); + if (SystemParametersInfoW(SPI_GETHIGHCONTRAST, sizeof(highContrast), &highContrast, FALSE)) + return highContrast.dwFlags & HCF_HIGHCONTRASTON; + return FALSE; +} + +// https://codereview.stackexchange.com/questions/29198/random-string-generator-in-c +static inline WCHAR* rand_string(WCHAR* str, size_t size) +{ + const WCHAR charset[] = L"abcdefghijklmnopqrstuvwxyz"; + if (size) { + --size; + for (size_t n = 0; n < size; n++) { + int key = rand() % (int)((sizeof(charset) / sizeof(WCHAR)) - 1); + str[n] = charset[key]; + } + str[size] = L'\0'; + } + return str; +} + +inline long long milliseconds_now() { + LARGE_INTEGER s_frequency; + BOOL s_use_qpc = QueryPerformanceFrequency(&s_frequency); + if (s_use_qpc) { + LARGE_INTEGER now; + QueryPerformanceCounter(&now); + return (1000LL * now.QuadPart) / s_frequency.QuadPart; + } + else { + return GetTickCount(); + } +} + +inline BOOL IsAppRunningAsAdminMode() +{ + BOOL fIsRunAsAdmin = FALSE; + DWORD dwError = ERROR_SUCCESS; + PSID pAdministratorsGroup = NULL; + + // Allocate and initialize a SID of the administrators group. + SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; + if (!AllocateAndInitializeSid( + &NtAuthority, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &pAdministratorsGroup)) + { + dwError = GetLastError(); + goto Cleanup; + } + + // Determine whether the SID of administrators group is enabled in + // the primary access token of the process. + if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin)) + { + dwError = GetLastError(); + goto Cleanup; + } + +Cleanup: + // Centralized cleanup for all allocated resources. + if (pAdministratorsGroup) + { + FreeSid(pAdministratorsGroup); + pAdministratorsGroup = NULL; + } + + // Throw the error if something failed in the function. + if (ERROR_SUCCESS != dwError) + { + return FALSE; + } + + return fIsRunAsAdmin; +} + +inline BOOL IsDesktopWindowAlreadyPresent() +{ + return (FindWindowExW(NULL, NULL, L"Progman", NULL) || FindWindowExW(NULL, NULL, L"Proxy Desktop", NULL)); +} + +// https://jiangsheng.net/2013/01/22/how-to-restart-windows-explorer-programmatically-using-restart-manager/ +inline RM_UNIQUE_PROCESS GetExplorerApplication() +{ + HWND hwnd = FindWindow(L"Shell_TrayWnd", NULL); + DWORD pid = 0; + GetWindowThreadProcessId(hwnd, &pid); + + RM_UNIQUE_PROCESS out = { 0, { (DWORD)-1, (DWORD)-1 } }; + DWORD bytesReturned; + WCHAR imageName[MAX_PATH]; // process image name buffer + DWORD processIds[2048]; // max 2048 processes (more than enough) + + // enumerate all running processes (usually around 60-70) + EnumProcesses(processIds, sizeof(processIds), &bytesReturned); + int count = bytesReturned / sizeof(DWORD); // number of processIds returned + + for (int i = 0; i < count; ++i) + { + DWORD processId = processIds[i]; + HANDLE hProc; + if (processId == pid && (hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId))) + { + GetProcessImageFileNameW(hProc, imageName, MAX_PATH); + FILETIME ftStart, ftExit, ftKernel, ftUser; + GetProcessTimes(hProc, &ftStart, &ftExit, &ftKernel, &ftUser); + + if (ftStart.dwLowDateTime < out.ProcessStartTime.dwLowDateTime) + { + out.dwProcessId = processId; + out.ProcessStartTime = ftStart; + } + CloseHandle(hProc); + } + } + return out; // return count in pResults +} + +static DWORD RmSession = -1; +static wchar_t RmSessionKey[CCH_RM_SESSION_KEY + 1]; + +// shuts down the explorer and is ready for explorer restart +inline DWORD WINAPI BeginExplorerRestart(LPVOID lpUnused) +{ + if (RmStartSession(&RmSession, 0, RmSessionKey) == ERROR_SUCCESS) + { + RM_UNIQUE_PROCESS rgApplications[] = { GetExplorerApplication() }; + RmRegisterResources(RmSession, 0, 0, 1, rgApplications, 0, 0); + + DWORD rebootReason; + UINT nProcInfoNeeded, nProcInfo = 16; + RM_PROCESS_INFO affectedApps[16]; + RmGetList(RmSession, &nProcInfoNeeded, &nProcInfo, affectedApps, &rebootReason); + + if (rebootReason == RmRebootReasonNone) // no need for reboot? + { + // shutdown explorer + RmShutdown(RmSession, RmForceShutdown, 0); + } + } + return 0; +} +// restarts the explorer +inline void FinishExplorerRestart() +{ + DWORD dwError; + if (dwError = RmRestart(RmSession, 0, NULL)) + printf("\n RmRestart error: %d\n\n", dwError); + + RmEndSession(RmSession); + RmSession = -1; + RmSessionKey[0] = 0; +} + +// https://stackoverflow.com/questions/5689904/gracefully-exit-explorer-programmatically +inline BOOL ExitExplorer() +{ + HWND hWndTray = FindWindowW(L"Shell_TrayWnd", NULL); + return PostMessageW(hWndTray, 0x5B4, 0, 0); +} + +inline void StartExplorerWithDelay(int delay, HANDLE userToken) +{ + WCHAR wszPath[MAX_PATH]; + ZeroMemory(wszPath, MAX_PATH * sizeof(WCHAR)); + GetWindowsDirectoryW(wszPath, MAX_PATH); + wcscat_s(wszPath, MAX_PATH, L"\\explorer.exe"); + Sleep(delay); + if (userToken != INVALID_HANDLE_VALUE) + { + HANDLE primaryUserToken = INVALID_HANDLE_VALUE; + if (ImpersonateLoggedOnUser(userToken)) + { + DuplicateTokenEx(userToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &primaryUserToken); + RevertToSelf(); + } + if (primaryUserToken != INVALID_HANDLE_VALUE) + { + PROCESS_INFORMATION processInfo; + ZeroMemory(&processInfo, sizeof(processInfo)); + STARTUPINFOW startupInfo; + ZeroMemory(&startupInfo, sizeof(startupInfo)); + startupInfo.cb = sizeof(startupInfo); + BOOL processCreated = CreateProcessWithTokenW( + primaryUserToken, LOGON_WITH_PROFILE, wszPath, NULL, 0, NULL, NULL, &startupInfo, &processInfo) != 0; + CloseHandle(primaryUserToken); + if (processInfo.hProcess != INVALID_HANDLE_VALUE) + { + CloseHandle(processInfo.hProcess); + } + if (processInfo.hThread != INVALID_HANDLE_VALUE) + { + CloseHandle(processInfo.hThread); + } + if (processCreated) + { + return; + } + } + } + ShellExecuteW( + NULL, + L"open", + wszPath, + NULL, + NULL, + SW_SHOWNORMAL + ); +} + +inline void StartExplorer() +{ + + /*PROCESSENTRY32 pe32 = {0}; + pe32.dwSize = sizeof(PROCESSENTRY32); + HANDLE hSnapshot = CreateToolhelp32Snapshot( + TH32CS_SNAPPROCESS, + 0 + ); + if (Process32First(hSnapshot, &pe32) == TRUE) + { + do + { + if (!wcscmp(pe32.szExeFile, TEXT("explorer.exe"))) + { + HANDLE hSihost = OpenProcess( + PROCESS_TERMINATE, + FALSE, + pe32.th32ProcessID + ); + TerminateProcess(hSihost, 1); + CloseHandle(hSihost); + } + } while (Process32Next(hSnapshot, &pe32) == TRUE); + } + CloseHandle(hSnapshot); + */ + wchar_t wszPath[MAX_PATH]; + ZeroMemory( + wszPath, + (MAX_PATH) * sizeof(wchar_t) + ); + GetWindowsDirectoryW( + wszPath, + MAX_PATH + ); + wcscat_s( + wszPath, + MAX_PATH, + L"\\explorer.exe" + ); + STARTUPINFO si; + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(si); + PROCESS_INFORMATION pi; + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + if (CreateProcessW( + NULL, + wszPath, + NULL, + NULL, + TRUE, + CREATE_UNICODE_ENVIRONMENT, + NULL, + NULL, + &si, + &pi + )) + { + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + } +} + +inline BOOL IncrementDLLReferenceCount(HINSTANCE hinst) +{ + HMODULE hMod; + GetModuleHandleExW( + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + (LPCWSTR)hinst, + &hMod); + return TRUE; +} + +PVOID FindPattern(PVOID pBase, SIZE_T dwSize, LPCSTR lpPattern, LPCSTR lpMask); + +#if _M_X64 +inline BOOL FollowJnz(PBYTE pJnz, PBYTE* pTarget, DWORD* pJnzSize) +{ + // Check big jnz + if (pJnz[0] == 0x0F && pJnz[1] == 0x85) + { + *pTarget = pJnz + 6 + *(int*)(pJnz + 2); + *pJnzSize = 6; + return TRUE; + } + // Check small jnz + if (pJnz[0] == 0x75) + { + *pTarget = pJnz + 2 + *(char*)(pJnz + 1); + *pJnzSize = 2; + return TRUE; + } + return FALSE; +} +#endif + +#if _M_ARM64 +// https://github.com/CAS-Atlantic/AArch64-Encoding + +__forceinline DWORD ARM64_ReadBits(DWORD value, int h, int l) +{ + return (value >> l) & ((1 << (h - l + 1)) - 1); +} + +__forceinline int ARM64_SignExtend(DWORD value, int numBits) +{ + DWORD mask = 1 << (numBits - 1); + if (value & mask) + value |= ~((1 << numBits) - 1); + return (int)value; +} + +__forceinline int ARM64_ReadBitsSignExtend(DWORD insn, int h, int l) +{ + return ARM64_SignExtend(ARM64_ReadBits(insn, h, l), h - l + 1); +} + +__forceinline BOOL ARM64_IsInRange(int value, int bitCount) +{ + int minVal = -(1 << (bitCount - 1)); + int maxVal = (1 << (bitCount - 1)) - 1; + return value >= minVal && value <= maxVal; +} + +__forceinline UINT_PTR ARM64_Align(UINT_PTR value, UINT_PTR alignment) +{ + return value & ~(alignment - 1); +} + +__forceinline BOOL ARM64_IsCBZW(DWORD insn) { return ARM64_ReadBits(insn, 31, 24) == 0b00110100; } +__forceinline BOOL ARM64_IsCBNZW(DWORD insn) { return ARM64_ReadBits(insn, 31, 24) == 0b00110101; } +__forceinline BOOL ARM64_IsBL(DWORD insn) { return ARM64_ReadBits(insn, 31, 26) == 0b100101; } +__forceinline BOOL ARM64_IsADRP(DWORD insn) { return (ARM64_ReadBits(insn, 31, 24) & ~0b01100000) == 0b10010000; } +__forceinline BOOL ARM64_IsMOVZW(DWORD insn) { return ARM64_ReadBits(insn, 31, 23) == 0b010100101; } +__forceinline BOOL ARM64_IsSTRBIMM(DWORD insn) { return ARM64_ReadBits(insn, 31, 22) == 0b0011100100; } + +__forceinline DWORD* ARM64_FollowCBNZW(DWORD* pInsnCBNZW) +{ + DWORD insnCBNZW = *pInsnCBNZW; + if (!ARM64_IsCBNZW(insnCBNZW)) + return NULL; + int imm19 = ARM64_ReadBitsSignExtend(insnCBNZW, 23, 5); + return pInsnCBNZW + imm19; // offset = imm19 * 4 +} + +__forceinline DWORD* ARM64_FollowBL(DWORD* pInsnBL) +{ + DWORD insnBL = *pInsnBL; + if (!ARM64_IsBL(insnBL)) + return NULL; + int imm26 = ARM64_ReadBitsSignExtend(insnBL, 25, 0); + return pInsnBL + imm26; // offset = imm26 * 4 +} + +__forceinline DWORD ARM64_MakeB(int imm26) +{ + if (!ARM64_IsInRange(imm26, 26)) + return 0; + return 0b000101 << 26 | imm26 & (1 << 26) - 1; +} + +__forceinline DWORD ARM64_CBZWToB(DWORD insnCBZW) +{ + if (!ARM64_IsCBZW(insnCBZW)) + return 0; + int imm19 = ARM64_ReadBitsSignExtend(insnCBZW, 23, 5); + return ARM64_MakeB(imm19); +} + +__forceinline DWORD ARM64_CBNZWToB(DWORD insnCBNZW) +{ + if (!ARM64_IsCBNZW(insnCBNZW)) + return 0; + int imm19 = ARM64_ReadBitsSignExtend(insnCBNZW, 23, 5); + return ARM64_MakeB(imm19); +} + +__forceinline DWORD ARM64_DecodeADD(DWORD insnADD) +{ + DWORD imm12 = ARM64_ReadBits(insnADD, 21, 10); + DWORD shift = ARM64_ReadBits(insnADD, 22, 22); + return imm12 << (shift * 12); +} + +__forceinline DWORD ARM64_DecodeSTRBIMM(DWORD insnSTRBIMM) +{ + if (ARM64_ReadBits(insnSTRBIMM, 31, 22) != 0b0011100100) + return (DWORD)-1; + DWORD imm12 = ARM64_ReadBits(insnSTRBIMM, 21, 10); + return imm12; +} + +__forceinline DWORD ARM64_DecodeLDRBIMM(DWORD insnLDRBIMM) +{ + if (ARM64_ReadBits(insnLDRBIMM, 31, 22) != 0b0011100101) + return (DWORD)-1; + DWORD imm12 = ARM64_ReadBits(insnLDRBIMM, 21, 10); + return imm12; +} + +inline UINT_PTR ARM64_DecodeADRL(UINT_PTR offset, DWORD insnADRP, DWORD insnADD) +{ + if (!ARM64_IsADRP(insnADRP)) + return 0; + + UINT_PTR page = ARM64_Align(offset, 0x1000); + + DWORD adrp_immlo = ARM64_ReadBits(insnADRP, 30, 29); + DWORD adrp_immhi = ARM64_ReadBits(insnADRP, 23, 5); + DWORD adrp_imm = ((adrp_immhi << 2) | adrp_immlo) << 12; + + DWORD add_imm = ARM64_DecodeADD(insnADD); + + return page + adrp_imm + add_imm; +} +#endif + +#if defined(WITH_MAIN_PATCHER) && WITH_MAIN_PATCHER +inline BOOL WINAPI PatchContextMenuOfNewMicrosoftIME(BOOL* bFound) +{ + // huge thanks to @Simplestas: https://github.com/valinet/ExplorerPatcher/issues/598 + HMODULE hInputSwitch = NULL; + if (!GetModuleHandleExW(0, L"InputSwitch.dll", &hInputSwitch)) + return FALSE; + + MODULEINFO mi; + GetModuleInformation(GetCurrentProcess(), hInputSwitch, &mi, sizeof(mi)); + +#if defined(_M_X64) + // 44 38 ?? ?? 74 ?? ?? 8B CE E8 ?? ?? ?? ?? 85 C0 + // ^^ Change jz into jmp + PBYTE match = (PBYTE)FindPattern( + hInputSwitch, + mi.SizeOfImage, + "\x44\x38\x00\x00\x74\x00\x00\x8B\xCE\xE8\x00\x00\x00\x00\x85\xC0", + "xx??x??xxx????xx" + ); + if (!match) + return FALSE; + + DWORD dwOldProtect; + if (!VirtualProtect(match + 4, 1, PAGE_EXECUTE_READWRITE, &dwOldProtect)) + return FALSE; + + match[4] = 0xEB; + + VirtualProtect(match + 4, 1, dwOldProtect, &dwOldProtect); + + return TRUE; +#elif defined(_M_ARM64) + // A8 43 40 39 C8 04 00 34 E0 03 14 AA + // ^^^^^^^^^^^ Change CBZ to B + PBYTE match = (PBYTE)FindPattern( + hInputSwitch, + mi.SizeOfImage, + "\xA8\x43\x40\x39\xC8\x04\x00\x34\xE0\x03\x14\xAA", + "xxxxxxxxxxxx" + ); + if (!match) + return FALSE; + + match += 4; + + DWORD newInsn = ARM64_CBZWToB(*(DWORD*)match); + if (!newInsn) + return FALSE; + + DWORD dwOldProtect; + if (!VirtualProtect(match, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect)) + return FALSE; + + *(DWORD*)match = newInsn; + + VirtualProtect(match, 4, dwOldProtect, &dwOldProtect); + + return TRUE; +#endif +} +#endif + +extern UINT PleaseWaitTimeout; +extern HHOOK PleaseWaitHook; +extern HWND PleaseWaitHWND; +extern void* PleaseWaitCallbackData; +extern BOOL (*PleaseWaitCallbackFunc)(void* data); +BOOL PleaseWait_UpdateTimeout(int timeout); +VOID CALLBACK PleaseWait_TimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime); +LRESULT CALLBACK PleaseWait_HookProc(int code, WPARAM wParam, LPARAM lParam); + +BOOL DownloadAndInstallWebView2Runtime(); + +BOOL DownloadFile(LPCWSTR wszURL, DWORD dwSize, LPCWSTR wszPath); + +BOOL IsConnectedToInternet(); + +#define SCRATCH_QCM_FIRST 1 +#define SCRATCH_QCM_LAST 0x7FFF + +#define SPOP_OPENMENU 1 +#define SPOP_INSERTMENU_ALL 0b1111110000 +#define SPOP_INSERTMENU_OPEN 0b0000010000 +#define SPOP_INSERTMENU_NEXTPIC 0b0000100000 +#define SPOP_INSERTMENU_LIKE 0b0001000000 +#define SPOP_INSERTMENU_DISLIKE 0b0010000000 +#define SPOP_INSERTMENU_INFOTIP1 0b0100000000 +#define SPOP_INSERTMENU_INFOTIP2 0b1000000000 +#define SPOP_CLICKMENU_FIRST 40000 +#define SPOP_CLICKMENU_OPEN 40000 +#define SPOP_CLICKMENU_NEXTPIC 40001 +#define SPOP_CLICKMENU_LIKE 40002 +#define SPOP_CLICKMENU_DISLIKE 40003 +#define SPOP_CLICKMENU_LAST 40003 + +BOOL DoesOSBuildSupportSpotlight(); + +BOOL IsSpotlightEnabled(); + +void SpotlightHelper(DWORD dwOp, HWND hWnd, HMENU hMenu, LPPOINT pPt); + +typedef struct _MonitorOverrideData +{ + DWORD cbIndex; + DWORD dwIndex; + HMONITOR hMonitor; +} MonitorOverrideData; + +BOOL ExtractMonitorByIndex(HMONITOR hMonitor, HDC hDC, LPRECT lpRect, MonitorOverrideData* mod); +HRESULT SHRegGetBOOLWithREGSAM(HKEY key, LPCWSTR subKey, LPCWSTR value, REGSAM regSam, BOOL* data); +HRESULT SHRegGetDWORD(HKEY hkey, const WCHAR* pwszSubKey, const WCHAR* pwszValue, DWORD* pdwData); + +inline BOOL MaskCompare(PVOID pBuffer, LPCSTR lpPattern, LPCSTR lpMask) +{ + for (PBYTE value = (PBYTE)pBuffer; *lpMask; ++lpPattern, ++lpMask, ++value) + { + if (*lpMask == 'x' && *(LPCBYTE)lpPattern != *value) + return FALSE; + } + + return TRUE; +} + +inline __declspec(noinline) PVOID FindPatternHelper(PVOID pBase, SIZE_T dwSize, LPCSTR lpPattern, LPCSTR lpMask) +{ + for (SIZE_T index = 0; index < dwSize; ++index) + { + PBYTE pAddress = (PBYTE)pBase + index; + + if (MaskCompare(pAddress, lpPattern, lpMask)) + return pAddress; + } + + return NULL; +} + +inline PVOID FindPattern(PVOID pBase, SIZE_T dwSize, LPCSTR lpPattern, LPCSTR lpMask) +{ + dwSize -= strlen(lpMask); + return FindPatternHelper(pBase, dwSize, lpPattern, lpMask); +} + +inline UINT_PTR FileOffsetToRVA(PBYTE pBase, UINT_PTR offset) +{ + PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBase; + PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)(pBase + pDosHeader->e_lfanew); + PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHeaders); + for (int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++, pSection++) + { + if (offset >= pSection->PointerToRawData && offset < pSection->PointerToRawData + pSection->SizeOfRawData) + return offset - pSection->PointerToRawData + pSection->VirtualAddress; + } + return 0; +} + +inline UINT_PTR RVAToFileOffset(PBYTE pBase, UINT_PTR rva) +{ + PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBase; + PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)(pBase + pDosHeader->e_lfanew); + PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHeaders); + for (int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++, pSection++) + { + if (rva >= pSection->VirtualAddress && rva < pSection->VirtualAddress + pSection->Misc.VirtualSize) + return rva - pSection->VirtualAddress + pSection->PointerToRawData; + } + return 0; +} + +inline HMODULE LoadGuiModule() +{ + wchar_t epGuiPath[MAX_PATH]; + ZeroMemory(epGuiPath, sizeof(epGuiPath)); + SHGetFolderPathW(NULL, SPECIAL_FOLDER, NULL, SHGFP_TYPE_CURRENT, epGuiPath); + wcscat_s(epGuiPath, MAX_PATH, _T(APP_RELATIVE_PATH) L"\\ep_gui.dll"); + return LoadLibraryExW(epGuiPath, NULL, LOAD_LIBRARY_AS_DATAFILE); +} + +inline BOOL DoesWindows10StartMenuExist() +{ + if (!IsWindows11()) + return TRUE; + + wchar_t szPath[MAX_PATH]; + GetWindowsDirectoryW(szPath, MAX_PATH); + wcscat_s(szPath, MAX_PATH, L"\\SystemApps\\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\\StartUI.dll"); + if (FileExistsW(szPath)) + return TRUE; + + GetWindowsDirectoryW(szPath, MAX_PATH); + wcscat_s(szPath, MAX_PATH, L"\\SystemApps\\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\\StartUI_.dll"); + if (FileExistsW(szPath)) + return TRUE; + + return FALSE; +} + +inline BOOL IsStockWindows10TaskbarAvailable() +{ +#if _M_X64 + return global_rovi.dwBuildNumber < 26002; +#else + return !IsWindows11(); +#endif +} + +inline const WCHAR* PickTaskbarDll() +{ + DWORD b = global_rovi.dwBuildNumber; + + if (b == 15063 // Windows 10 1703 + || b == 16299 // Windows 10 1709 + || b == 17134 // Windows 10 1803 + || b == 17763 // Windows 10 1809 + || b >= 18362 && b <= 18363 // Windows 10 1903, 1909 + || b >= 19041 && b <= 19045) // Windows 10 20H2, 21H2, 22H2 + { + return L"ep_taskbar.0.dll"; + } + + if (b >= 21343 && b <= 22000) // Windows 11 21H2 + { + return L"ep_taskbar.1.dll"; + } + + if ((b >= 22621 && b <= 22635) // 22H2-23H2 Release, Release Preview, and Beta channels + || (b >= 23403 && b <= 25197)) // Early pre-reboot Dev channel until post-reboot Dev channel + { + return L"ep_taskbar.2.dll"; + } + + if (b >= 25201 && b <= 25915) // Pre-reboot Dev channel until early Canary channel, nuked ITrayComponentHost methods related to classic search box + { + return L"ep_taskbar.3.dll"; + } + + if (b >= 25921 && b <= 26040) // Canary channel with nuked classic system tray + { + return L"ep_taskbar.4.dll"; + } + + if (b >= 26052) // Same as 4 but with 2 new methods in ITrayComponentHost between GetTrayUI and ProgrammableTaskbarReportClick + { + return L"ep_taskbar.5.dll"; + } + + return NULL; +} + +inline BOOL DoesTaskbarDllExist() +{ + const wchar_t* pszTaskbarDll = PickTaskbarDll(); + if (!pszTaskbarDll) + return FALSE; + + wchar_t szPath[MAX_PATH]; + ZeroMemory(szPath, sizeof(szPath)); + SHGetFolderPathW(NULL, SPECIAL_FOLDER, NULL, SHGFP_TYPE_CURRENT, szPath); + wcscat_s(szPath, MAX_PATH, _T(APP_RELATIVE_PATH) L"\\"); + wcscat_s(szPath, MAX_PATH, pszTaskbarDll); + return FileExistsW(szPath); +} + +inline void AdjustTaskbarStyleValue(DWORD* pdwValue) +{ + if (*pdwValue >= 2 && !DoesTaskbarDllExist()) + { + *pdwValue = 1; + } + + if (IsWindows11()) + { + if (*pdwValue == 1 && !IsStockWindows10TaskbarAvailable()) + { + *pdwValue = 0; + } + } + else + { + if (*pdwValue == 0) + { + *pdwValue = 1; // There's no such thing as Windows 11 taskbar on Windows 10 + } + } +} + +#ifdef __cplusplus +} +#endif + +#endif