From 4e90ae904238de79cfbcb5ecd2b235ed9df3d90b Mon Sep 17 00:00:00 2001 From: AllieTheFox Date: Sun, 14 Jun 2026 09:05:01 -0600 Subject: [PATCH 1/2] feat: Add StartExperience wrappers to fix bugs relating to 61558864 velocity id. --- ExplorerPatcher/ExplorerPatcher.vcxproj | 2 + ExplorerPatcher/StartExperience.cpp | 139 ++++++++++++++++++++++++ ExplorerPatcher/StartExperience.h | 45 ++++++++ ExplorerPatcher/dllmain.c | 32 ++++++ 4 files changed, 218 insertions(+) create mode 100644 ExplorerPatcher/StartExperience.cpp create mode 100644 ExplorerPatcher/StartExperience.h diff --git a/ExplorerPatcher/ExplorerPatcher.vcxproj b/ExplorerPatcher/ExplorerPatcher.vcxproj index 14ebc0ef0..5c66d0a3d 100644 --- a/ExplorerPatcher/ExplorerPatcher.vcxproj +++ b/ExplorerPatcher/ExplorerPatcher.vcxproj @@ -241,6 +241,7 @@ true + true @@ -299,6 +300,7 @@ + diff --git a/ExplorerPatcher/StartExperience.cpp b/ExplorerPatcher/StartExperience.cpp new file mode 100644 index 000000000..4e114bdd0 --- /dev/null +++ b/ExplorerPatcher/StartExperience.cpp @@ -0,0 +1,139 @@ +#include "StartExperience.h" + +#include +#include + +using namespace Microsoft::WRL; + +namespace wis = Windows::Internal::Shell; +namespace wf = ABI::Windows::Foundation; + +using namespace ABI; + +class CStartExperienceWrapper + : public RuntimeClass + , wis::StartUI::IStartExperience + > +{ + InspectableClass(L"", BaseTrust); + +public: + CStartExperienceWrapper() = default; + HRESULT RuntimeClassInitialize(IStartExperience* pInner); + + //~ Begin wis::StartUI::IStartExperience Interface + STDMETHODIMP ProcessBackgroundImage(IInspectable* a1, int a2, INT64* a3) override; + STDMETHODIMP get_WaitableExplorerProcessHandle(UINT64* a1) override; + STDMETHODIMP PromoteAppsToTopOfFrequentList(wf::Collections::IVector* a1) override; + STDMETHODIMP add_GlobalAnimationRequested( + wf::ITypedEventHandler< + wis::StartUI::StartExperience*, wis::StartUI::StartExperienceAnimationRequestedEventArgs*>* a1, + EventRegistrationToken* token) override; + STDMETHODIMP remove_GlobalAnimationRequested(EventRegistrationToken token) override; + STDMETHODIMP add_ShellModeChanged( + wf::ITypedEventHandler* a1, + EventRegistrationToken* token) override; + STDMETHODIMP remove_ShellModeChanged(EventRegistrationToken token) override; + //~ End wis::StartUI::IStartExperience Interface + +private: + ComPtr _spInner; +}; + +HRESULT CStartExperienceWrapper::RuntimeClassInitialize(IStartExperience* pInner) +{ + _spInner = pInner; + RETURN_HR(S_OK); +} + +HRESULT CStartExperienceWrapper::ProcessBackgroundImage(IInspectable* a1, int a2, INT64* a3) +{ + RETURN_HR(_spInner->ProcessBackgroundImage(a1, a2, a3)); +} + +HRESULT CStartExperienceWrapper::get_WaitableExplorerProcessHandle(UINT64* a1) +{ + RETURN_HR(_spInner->get_WaitableExplorerProcessHandle(a1)); +} + +HRESULT CStartExperienceWrapper::PromoteAppsToTopOfFrequentList(wf::Collections::IVector* a1) +{ + RETURN_HR(_spInner->PromoteAppsToTopOfFrequentList(a1)); +} + +HRESULT CStartExperienceWrapper::add_GlobalAnimationRequested( + wf::ITypedEventHandler< + wis::StartUI::StartExperience*, wis::StartUI::StartExperienceAnimationRequestedEventArgs*>* a1, + EventRegistrationToken* token) +{ + RETURN_HR(_spInner->add_GlobalAnimationRequested(a1, token)); +} + +HRESULT CStartExperienceWrapper::remove_GlobalAnimationRequested(EventRegistrationToken token) +{ + RETURN_HR(_spInner->remove_GlobalAnimationRequested(token)); +} + +HRESULT CStartExperienceWrapper::add_ShellModeChanged( + wf::ITypedEventHandler< + wis::StartUI::StartExperience*, wis::StartUI::ShellModeChangedEventArgs*>* a1, EventRegistrationToken* token) +{ + *token = {}; + RETURN_HR(S_OK); +} + +HRESULT CStartExperienceWrapper::remove_ShellModeChanged(EventRegistrationToken token) +{ + RETURN_HR(S_OK); +} + +class CStartExperienceStaticsWrapper + : public RuntimeClass + , wis::StartUI::IStartExperienceStatics + > +{ + InspectableClass(L"", BaseTrust); + +public: + CStartExperienceStaticsWrapper() = default; + HRESULT RuntimeClassInitialize(IStartExperienceStatics* pInner); + + //~ Begin wis::StartUI::IStartExperienceStatics Interface + STDMETHODIMP GetForCurrentView(wis::StartUI::IStartExperience** ppStartExperience) override; + STDMETHODIMP GetIfNoCurrentView(wis::StartUI::IStartExperience** ppStartExperience) override; + //~ End wis::StartUI::IStartExperienceStatics Interface + +private: + ComPtr _spInner; +}; + +HRESULT CStartExperienceStaticsWrapper::RuntimeClassInitialize(IStartExperienceStatics* pInner) +{ + _spInner = pInner; + RETURN_HR(S_OK); +} + +HRESULT CStartExperienceStaticsWrapper::GetForCurrentView(wis::StartUI::IStartExperience** ppStartExperience) +{ + ComPtr spStartExperience; + RETURN_IF_FAILED(_spInner->GetForCurrentView(&spStartExperience)); + RETURN_HR(MakeAndInitialize(ppStartExperience, spStartExperience.Get())); +} + +HRESULT CStartExperienceStaticsWrapper::GetIfNoCurrentView(wis::StartUI::IStartExperience** ppStartExperience) +{ + ComPtr spStartExperience; + RETURN_IF_FAILED(_spInner->GetIfNoCurrentView(&spStartExperience)); + RETURN_HR(MakeAndInitialize(ppStartExperience, spStartExperience.Get())); +} + +EXTERN_C HRESULT StartExperienceWrapper_Wrap(REFIID riid, void** ppv) +{ + ComPtr spInner; + spInner.Attach(*reinterpret_cast(ppv)); + *ppv = nullptr; + + ComPtr spInstance; + RETURN_IF_FAILED(MakeAndInitialize(&spInstance, spInner.Get())); + RETURN_HR(spInstance.CopyTo(riid, ppv)); +} diff --git a/ExplorerPatcher/StartExperience.h b/ExplorerPatcher/StartExperience.h new file mode 100644 index 000000000..565a1114e --- /dev/null +++ b/ExplorerPatcher/StartExperience.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include + +#include +DEFINE_GUID(IID_IStartExperience, 0x4C4D0C66, 0x5BD5, 0xFD8C, 0x61, 0x7F, 0x3C, 0x77, 0x78, 0xF4, 0x6B, 0xB6); +DEFINE_GUID(IID_IStartExperienceStatics, 0xFB2E3E59, 0xB442, 0x4B5B, 0x91, 0x28, 0x23, 0x19, 0xBF, 0x8D, 0xE3, 0xB0); + +namespace Windows::Internal::Shell::StartUI +{ + +struct StartExperience; + +class StartExperienceAnimationRequestedEventArgs; +class ShellModeChangedEventArgs; + +MIDL_INTERFACE("4c4d0c66-5bd5-fd8c-617f-3c7778f46bb6") +IStartExperience : IInspectable +{ + virtual HRESULT STDMETHODCALLTYPE ProcessBackgroundImage(IInspectable*, int, INT64*) = 0; + virtual HRESULT STDMETHODCALLTYPE get_WaitableExplorerProcessHandle(UINT64*) = 0; + virtual HRESULT STDMETHODCALLTYPE PromoteAppsToTopOfFrequentList( + ABI::Windows::Foundation::Collections::IVector*) = 0; + virtual HRESULT STDMETHODCALLTYPE add_GlobalAnimationRequested( + ABI::Windows::Foundation::ITypedEventHandler< + StartExperience*, StartExperienceAnimationRequestedEventArgs*>*, EventRegistrationToken*) = 0; + virtual HRESULT STDMETHODCALLTYPE remove_GlobalAnimationRequested(EventRegistrationToken) = 0; + virtual HRESULT STDMETHODCALLTYPE add_ShellModeChanged( + ABI::Windows::Foundation::ITypedEventHandler< + StartExperience*, ShellModeChangedEventArgs*>*, EventRegistrationToken*) = 0; + virtual HRESULT STDMETHODCALLTYPE remove_ShellModeChanged(EventRegistrationToken) = 0; +}; + +MIDL_INTERFACE("fb2e3e59-b442-4b5b-9128-2319bf8de3b0") +IStartExperienceStatics : IInspectable +{ + virtual HRESULT STDMETHODCALLTYPE GetForCurrentView(IStartExperience**) = 0; + virtual HRESULT STDMETHODCALLTYPE GetIfNoCurrentView(IStartExperience**) = 0; +}; + +} // Windows::Internal::Shell::StartUI + +EXTERN_C HRESULT StartExperienceWrapper_Wrap(REFIID riid, void** ppv); diff --git a/ExplorerPatcher/dllmain.c b/ExplorerPatcher/dllmain.c index b216e06d2..e6baa2b3b 100644 --- a/ExplorerPatcher/dllmain.c +++ b/ExplorerPatcher/dllmain.c @@ -12215,6 +12215,27 @@ HRESULT StartUI_CoCreateInstanceHook(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD return CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv); } +HRESULT StartExperienceWrapper_Wrap(REFIID riid, void** ppv); + +EXTERN_C const IID IID_IStartExperienceStatics; + +HRESULT (STDAPICALLTYPE *StartUI_GetActivationFactoryByPCWSTRFunc)(PCWSTR activatableClassId, REFIID riid, void** ppv); +HRESULT STDAPICALLTYPE StartUI_GetActivationFactoryByPCWSTRHook(PCWSTR activatableClassId, REFIID riid, void** ppv) +{ + if (wcscmp(activatableClassId, L"Windows.Internal.Shell.StartUI.StartExperience") == 0 + && IsEqualIID(riid, &IID_IStartExperienceStatics)) + { + HRESULT hr = StartUI_GetActivationFactoryByPCWSTRFunc(activatableClassId, riid, ppv); + if (SUCCEEDED(hr)) + { + hr = StartExperienceWrapper_Wrap(riid, ppv); + } + return hr; + } + + return StartUI_GetActivationFactoryByPCWSTRFunc(activatableClassId, riid, ppv); +} + int Start_SetWindowRgn(HWND hWnd, HRGN hRgn, BOOL bRedraw) { WCHAR wszDebug[MAX_PATH]; @@ -12846,6 +12867,17 @@ DWORD InjectStartMenu() VnPatchIAT(hWindowsCloudStore, "api-ms-win-core-registry-l1-1-0.dll", "RegOpenKeyExW", StartUI_RegOpenKeyExW); VnPatchIAT(hWindowsCloudStore, "api-ms-win-core-registry-l1-1-0.dll", "RegQueryValueExW", StartUI_RegQueryValueExW); VnPatchIAT(hWindowsCloudStore, "api-ms-win-core-registry-l1-1-0.dll", "RegCloseKey", StartUI_RegCloseKey); + + // Adds compatibility with RLTM ("Remove Legacy Tablet Mode" / 61558864) feature flag + HANDLE hWincorlib = GetModuleHandleW(L"wincorlib.DLL"); + if (hWincorlib) + { + StartUI_GetActivationFactoryByPCWSTRFunc = GetProcAddress(hWincorlib, "?GetActivationFactoryByPCWSTR@@YAJPEAXAEAVGuid@Platform@@PEAPEAX@Z"); + } + if (StartUI_GetActivationFactoryByPCWSTRFunc) + { + VnPatchIAT(hStartUI, "wincorlib.DLL", "?GetActivationFactoryByPCWSTR@@YAJPEAXAEAVGuid@Platform@@PEAPEAX@Z", StartUI_GetActivationFactoryByPCWSTRHook); + } } } else From 25030cfa73522ab006168dbf40738f43bf930004 Mon Sep 17 00:00:00 2001 From: AllieTheFox Date: Sun, 14 Jun 2026 16:02:05 -0600 Subject: [PATCH 2/2] chore(StartExperience): Some convention fixes requested by amr. --- ExplorerPatcher/StartExperience.cpp | 20 ++++++++++---------- ExplorerPatcher/StartExperience.h | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ExplorerPatcher/StartExperience.cpp b/ExplorerPatcher/StartExperience.cpp index 4e114bdd0..9b96167b9 100644 --- a/ExplorerPatcher/StartExperience.cpp +++ b/ExplorerPatcher/StartExperience.cpp @@ -5,7 +5,7 @@ using namespace Microsoft::WRL; -namespace wis = Windows::Internal::Shell; +namespace wis = ABI::Windows::Internal::Shell; namespace wf = ABI::Windows::Foundation; using namespace ABI; @@ -43,22 +43,22 @@ class CStartExperienceWrapper HRESULT CStartExperienceWrapper::RuntimeClassInitialize(IStartExperience* pInner) { _spInner = pInner; - RETURN_HR(S_OK); + return S_OK; } HRESULT CStartExperienceWrapper::ProcessBackgroundImage(IInspectable* a1, int a2, INT64* a3) { - RETURN_HR(_spInner->ProcessBackgroundImage(a1, a2, a3)); + return _spInner->ProcessBackgroundImage(a1, a2, a3); } HRESULT CStartExperienceWrapper::get_WaitableExplorerProcessHandle(UINT64* a1) { - RETURN_HR(_spInner->get_WaitableExplorerProcessHandle(a1)); + return _spInner->get_WaitableExplorerProcessHandle(a1); } HRESULT CStartExperienceWrapper::PromoteAppsToTopOfFrequentList(wf::Collections::IVector* a1) { - RETURN_HR(_spInner->PromoteAppsToTopOfFrequentList(a1)); + return _spInner->PromoteAppsToTopOfFrequentList(a1); } HRESULT CStartExperienceWrapper::add_GlobalAnimationRequested( @@ -66,12 +66,12 @@ HRESULT CStartExperienceWrapper::add_GlobalAnimationRequested( wis::StartUI::StartExperience*, wis::StartUI::StartExperienceAnimationRequestedEventArgs*>* a1, EventRegistrationToken* token) { - RETURN_HR(_spInner->add_GlobalAnimationRequested(a1, token)); + return _spInner->add_GlobalAnimationRequested(a1, token); } HRESULT CStartExperienceWrapper::remove_GlobalAnimationRequested(EventRegistrationToken token) { - RETURN_HR(_spInner->remove_GlobalAnimationRequested(token)); + return _spInner->remove_GlobalAnimationRequested(token); } HRESULT CStartExperienceWrapper::add_ShellModeChanged( @@ -79,12 +79,12 @@ HRESULT CStartExperienceWrapper::add_ShellModeChanged( wis::StartUI::StartExperience*, wis::StartUI::ShellModeChangedEventArgs*>* a1, EventRegistrationToken* token) { *token = {}; - RETURN_HR(S_OK); + return S_OK; } HRESULT CStartExperienceWrapper::remove_ShellModeChanged(EventRegistrationToken token) { - RETURN_HR(S_OK); + return S_OK; } class CStartExperienceStaticsWrapper @@ -110,7 +110,7 @@ class CStartExperienceStaticsWrapper HRESULT CStartExperienceStaticsWrapper::RuntimeClassInitialize(IStartExperienceStatics* pInner) { _spInner = pInner; - RETURN_HR(S_OK); + return S_OK; } HRESULT CStartExperienceStaticsWrapper::GetForCurrentView(wis::StartUI::IStartExperience** ppStartExperience) diff --git a/ExplorerPatcher/StartExperience.h b/ExplorerPatcher/StartExperience.h index 565a1114e..b727eb5dd 100644 --- a/ExplorerPatcher/StartExperience.h +++ b/ExplorerPatcher/StartExperience.h @@ -8,7 +8,7 @@ DEFINE_GUID(IID_IStartExperience, 0x4C4D0C66, 0x5BD5, 0xFD8C, 0x61, 0x7F, 0x3C, 0x77, 0x78, 0xF4, 0x6B, 0xB6); DEFINE_GUID(IID_IStartExperienceStatics, 0xFB2E3E59, 0xB442, 0x4B5B, 0x91, 0x28, 0x23, 0x19, 0xBF, 0x8D, 0xE3, 0xB0); -namespace Windows::Internal::Shell::StartUI +namespace ABI::Windows::Internal::Shell::StartUI { struct StartExperience; @@ -40,6 +40,6 @@ IStartExperienceStatics : IInspectable virtual HRESULT STDMETHODCALLTYPE GetIfNoCurrentView(IStartExperience**) = 0; }; -} // Windows::Internal::Shell::StartUI +} // ABI::Windows::Internal::Shell::StartUI EXTERN_C HRESULT StartExperienceWrapper_Wrap(REFIID riid, void** ppv);