diff --git a/CHANGELOG.md b/CHANGELOG.md index 72400451c..79070fbb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,23 @@ This document includes the same release notes as in the [Releases](https://github.com/valinet/ExplorerPatcher/releases) section on GitHub. +## 22621.2428.59 + +Tested on OS builds 22000.2416, 22621.2428, 23555.1000, and 23560.1000. + +#### Details + +##### 1 + +* Taskbar10: Fixed Control Center and Toast Center positioning on build 25951 (Canary). (dca0b3a) +* Taskbar10: Fixed start menu position when the taskbar is at the left or right side on Moment 4 builds. (a57471f) +* Taskbar10: Fixed the Windows 10 taskbar background patch to not crash anymore on build 25951 (Canary). (b52bd79) +* Taskbar10: Made taskbar fonts (when using classic theme mitigations) more accurate (thanks @aubymori). (8fc53a1) +* Start10: Fixed a bug where certain texts in the Windows 10 Start menu stayed in English. (c6a7d3f, ed251e9) +* Start10: Properly fixed start menu showing/hiding along with its original animations on builds 22000.65+. (7e2f768) +* GUI: Fixed a bug where "Remember last used section" doesn't remember the current page after being enabled. (dcf72bb) +* Symbols: Reworked how symbols are managed so that symbols don't need to be successfully downloaded in succession. (8412bd6) + ## 22621.2361.58 Tested on OS builds 22000.2416, 22621.1, 22621.2134, 22621.2361, 22631.2338, and 23545.1000. diff --git a/ExplorerPatcher/ExplorerPatcher.rc b/ExplorerPatcher/ExplorerPatcher.rc index 1e1f3a878..3e006d955 100644 Binary files a/ExplorerPatcher/ExplorerPatcher.rc and b/ExplorerPatcher/ExplorerPatcher.rc differ diff --git a/ExplorerPatcher/ExplorerPatcher.vcxproj b/ExplorerPatcher/ExplorerPatcher.vcxproj index 694321193..b8c1b5bd2 100644 --- a/ExplorerPatcher/ExplorerPatcher.vcxproj +++ b/ExplorerPatcher/ExplorerPatcher.vcxproj @@ -96,7 +96,7 @@ true true true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + NDEBUG;_CONSOLE;WINRT_NO_SOURCE_LOCATION;%(PreprocessorDefinitions) true $(SolutionDir)libs\funchook\include;$(SolutionDir)libs\libvalinet;$(SolutionDir)libs\funchook\distorm\include;$(SolutionDir)libs\Detours\include;%(AdditionalIncludeDirectories) MultiThreaded @@ -126,7 +126,7 @@ true true true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + NDEBUG;_CONSOLE;WINRT_NO_SOURCE_LOCATION;%(PreprocessorDefinitions) true $(SolutionDir)libs\funchook\include;$(SolutionDir)libs\libvalinet;$(SolutionDir)libs\funchook\distorm\include;$(SolutionDir)libs\Detours\include;%(AdditionalIncludeDirectories) MultiThreaded diff --git a/ExplorerPatcher/GUI.c b/ExplorerPatcher/GUI.c index a3a48be91..c6f8045b5 100644 --- a/ExplorerPatcher/GUI.c +++ b/ExplorerPatcher/GUI.c @@ -1624,7 +1624,7 @@ static BOOL GUI_Build(HDC hDC, HWND hwnd, POINT pt) } else { - BeginExplorerRestart(); + BeginExplorerRestart(NULL); } } Sleep(100); diff --git a/ExplorerPatcher/RefreshedStyles.xbf b/ExplorerPatcher/RefreshedStyles.xbf new file mode 100644 index 000000000..68f84fcf4 Binary files /dev/null and b/ExplorerPatcher/RefreshedStyles.xbf differ diff --git a/ExplorerPatcher/StartMenuSettings.cpp b/ExplorerPatcher/StartMenuSettings.cpp index b0866a8f8..94cda734c 100644 --- a/ExplorerPatcher/StartMenuSettings.cpp +++ b/ExplorerPatcher/StartMenuSettings.cpp @@ -26,7 +26,7 @@ static std::vector GlobalStartData_GetPlacesFromRegistry() std::vector places; DWORD dwSize; - HRESULT hr = RegGetValueW( + LSTATUS lRes = RegGetValueW( HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Start", L"VisiblePlaces", @@ -35,11 +35,11 @@ static std::vector GlobalStartData_GetPlacesFromRegistry() nullptr, &dwSize ); - if (FAILED(hr) || dwSize == 0) + if (lRes != ERROR_SUCCESS || dwSize == 0) return places; places.resize(dwSize / sizeof(winrt::guid)); - hr = RegGetValueW( + lRes = RegGetValueW( HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Start", L"VisiblePlaces", @@ -48,7 +48,7 @@ static std::vector GlobalStartData_GetPlacesFromRegistry() places.data(), &dwSize ); - if (FAILED(hr)) + if (lRes != ERROR_SUCCESS) places.clear(); return places; diff --git a/ExplorerPatcher/def.h b/ExplorerPatcher/def.h index 3b1d683ea..ba61dc290 100644 --- a/ExplorerPatcher/def.h +++ b/ExplorerPatcher/def.h @@ -1,8 +1,8 @@ #ifndef _H_DEF_H_ #define _H_DEF_H_ #define APPID L"Microsoft.Windows.Explorer" -#define REGPATH "SOFTWARE\\ExplorerPatcher" -#define REGPATH_OLD "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ExplorerPatcher" +#define REGPATH "Software\\ExplorerPatcher" +#define REGPATH_OLD "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ExplorerPatcher" #define REGPATH_STARTMENU REGPATH_OLD #define SPECIAL_FOLDER CSIDL_PROGRAM_FILES #define SPECIAL_FOLDER_LEGACY CSIDL_APPDATA diff --git a/ExplorerPatcher/dllmain.c b/ExplorerPatcher/dllmain.c index 3076329c6..d9e963c6f 100644 --- a/ExplorerPatcher/dllmain.c +++ b/ExplorerPatcher/dllmain.c @@ -4296,6 +4296,7 @@ INT64 winrt_Windows_Internal_Shell_implementation_MeetAndChatManager_OnMessageHo #pragma region "Enable old taskbar" #ifdef _WIN64 +HRESULT(*explorer_RoGetActivationFactoryFunc)(HSTRING activatableClassId, GUID* iid, void** factory); HRESULT explorer_RoGetActivationFactoryHook(HSTRING activatableClassId, GUID* iid, void** factory) { PCWSTR StringRawBuffer = WindowsGetStringRawBuffer(activatableClassId, 0); @@ -4312,7 +4313,7 @@ HRESULT explorer_RoGetActivationFactoryHook(HSTRING activatableClassId, GUID* ii return S_OK; } } - return RoGetActivationFactory(activatableClassId, iid, factory); + return explorer_RoGetActivationFactoryFunc(activatableClassId, iid, factory); } FARPROC explorer_GetProcAddressHook(HMODULE hModule, const CHAR* lpProcName) @@ -8062,27 +8063,15 @@ HRESULT explorer_DrawThemeTextEx( SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSW), &ncm, 0); HFONT hFont = NULL; - if (bIsActiveUnhovered) + if (bIsActiveUnhovered || bIsActiveHovered) { - hFont = CreateFontIndirectW(&(ncm.lfCaptionFont)); - } - else if (bIsInactiveUnhovered) - { - hFont = CreateFontIndirectW(&(ncm.lfMenuFont)); - } - else if (bIsActiveHovered) - { - hFont = CreateFontIndirectW(&(ncm.lfCaptionFont)); - } - else if (bIsInactiveHovered) - { - hFont = CreateFontIndirectW(&(ncm.lfMenuFont)); + ncm.lfCaptionFont.lfWeight = FW_BOLD; } else { - hFont = CreateFontIndirectW(&(ncm.lfMenuFont)); - //wprintf(L"DrawThemeTextEx %d %d %s\n", iPartId, iStateId, pszText); + ncm.lfCaptionFont.lfWeight = FW_NORMAL; } + hFont = CreateFontIndirectW(&(ncm.lfCaptionFont)); if (iPartId == 5 && iStateId == 0) // clock { @@ -9693,6 +9682,15 @@ int RtlQueryFeatureConfigurationHook(UINT32 featureId, int sectionType, INT64* c break; } #endif + case 44656322: // ID44656322 + { + if (bOldTaskbar) + { + // Fixes start menu positioning when the taskbar is at the left or right side + buffer->enabledState = FEATURE_ENABLED_STATE_DISABLED; + } + break; + } } return rv; } @@ -10446,7 +10444,10 @@ BOOL explorer_IsOS(DWORD dwOS) 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 - HANDLE hFile = CreateFileW(L"twinui.pcshell.dll", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + 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, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { printf("Failed to open twinui.pcshell.dll\n"); @@ -10647,7 +10648,7 @@ static void PatchAppResolver() if (match) { match += 5; - match = match + 5 + *(int*)(match + 1); + match += 5 + *(int*)(match + 1); AppResolver_CAppResolverCacheBuilder__AddUserPinnedShortcutToStartFunc = match; printf("CAppResolverCacheBuilder::_AddUserPinnedShortcutToStart() = %llX\n", match - (PBYTE)hAppResolver); } @@ -10677,6 +10678,381 @@ static void PatchStartTileData() #pragma endregion +#pragma region "Fix Windows 10 start menu animation on 22000.65+" +#ifdef _WIN64 +static struct +{ + int startExperienceManager_singleViewShellExperience; + int startExperienceManager_singleViewShellExperienceEventHandler; + int startExperienceManager_openingAnimation; + int startExperienceManager_closingAnimation; + int startExperienceManager_bMaybeFullScreenMode; +} g_SMAnimationPatchOffsets; + +enum EDGEUI_TRAYSTUCKPLACE {}; +enum DWMTRANSITION_TARGET {}; + +HRESULT(*CStartExperienceManager_GetMonitorInformationFunc)(void* _this, void* experience, RECT* a3, enum EDGEUI_TRAYSTUCKPLACE* pTsp, bool* a5, RECT* a6, HMONITOR* a7); +HRESULT(*CExperienceManagerAnimationHelper_BeginFunc)(void* _this, void*, enum DWMTRANSITION_TARGET, const RECT*, const RECT*, const RECT*, const RECT*, const RECT*); +HRESULT(*CExperienceManagerAnimationHelper_EndFunc)(void* _this); + +HRESULT(*OnViewCloakingFunc)(void* eventHandler, void* experience); +HRESULT OnViewCloakingHook(void* eventHandler, void* experience) +{ + PBYTE _this = (PBYTE)eventHandler - g_SMAnimationPatchOffsets.startExperienceManager_singleViewShellExperienceEventHandler; + bool bMaybeFullScreenMode = *(_this + g_SMAnimationPatchOffsets.startExperienceManager_bMaybeFullScreenMode); + if (bMaybeFullScreenMode) + return S_OK; + + RECT rc; + enum EDGEUI_TRAYSTUCKPLACE tsp; + bool bUnknown; + RECT rc2; + HMONITOR hMonitor; + HRESULT hr = CStartExperienceManager_GetMonitorInformationFunc(_this, experience, &rc, &tsp, &bUnknown, &rc2, &hMonitor); + if (FAILED(hr)) + return hr; + + enum DWMTRANSITION_TARGET target = 0x51; + if (*(bool*)((PBYTE)experience + 0x34)) + target = 0x52; + else if (tsp == 0) + target = 0x4D; + else if (tsp == 1) + target = 0x4F; + else if (tsp == 2) + target = 0x4E; + else if (tsp == 3) + target = 0x50; + + hr = CExperienceManagerAnimationHelper_BeginFunc( + _this + g_SMAnimationPatchOffsets.startExperienceManager_closingAnimation, + *(void**)((PBYTE)experience + 0x18), // viewWrapper + target | 0x200000u, NULL, NULL, NULL, NULL, &rc); + + return hr; +} + +// Note: `void* experience` is never valid because the compiler optimized out the argument passing. At least on 22621.1992 +HRESULT CStartExperienceManager_GetMonitorInformationHook(void* _this, void* experience, RECT* a3, enum EDGEUI_TRAYSTUCKPLACE* pTsp, bool* a5, RECT* a6, HMONITOR* a7) +{ + HRESULT hr = CStartExperienceManager_GetMonitorInformationFunc(_this, experience, a3, pTsp, a5, a6, a7); + // We add code to OnViewUncloaking through this function + if (SUCCEEDED(hr) && *(PBYTE)_ReturnAddress() == 0x85 && *((PBYTE)_ReturnAddress() + 1) == 0xC0 && *((PBYTE)_ReturnAddress() + 2) == 0x78) + { + experience = (PBYTE)_this + g_SMAnimationPatchOffsets.startExperienceManager_singleViewShellExperience; + enum DWMTRANSITION_TARGET target = 0x51; + if (*(bool*)((PBYTE)experience + 0x34)) + target = 0x52; + else if (*pTsp == 0) + target = 0x4E; + else if (*pTsp == 1) + target = 0x50; + else if (*pTsp == 2) + target = 0x4D; + else if (*pTsp == 3) + target = 0x4F; + CExperienceManagerAnimationHelper_BeginFunc( + (PBYTE)_this + g_SMAnimationPatchOffsets.startExperienceManager_openingAnimation, + *(void**)((PBYTE)experience + 0x18), // viewWrapper + target | 0x200000u, NULL, NULL, NULL, NULL, a3); + return E_FAIL; // Don't invoke ReportUsage() called in OnViewUncloaking + } + return hr; +} + +HRESULT(*OnViewUncloakingFunc)(void* eventHandler, void* experience); + +HRESULT(*OnViewUncloakedFunc)(void* eventHandler, void* experience); +HRESULT OnViewUncloakedHook(void* eventHandler, void* experience) +{ + PBYTE _this = (PBYTE)eventHandler - g_SMAnimationPatchOffsets.startExperienceManager_singleViewShellExperienceEventHandler; + CExperienceManagerAnimationHelper_EndFunc(_this + g_SMAnimationPatchOffsets.startExperienceManager_openingAnimation); + return S_OK; +} + +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+. + + // ### Offset of SingleViewShellExperience instance and its event handler + // ``` + // 48 8D 8E ?? ?? ?? ?? 44 8D 45 ?? 48 8D 56 ?? E8 + // ^^^^^^^^^^^ SVSE ^^ SVSEEH + // ``` + // Ref: CStartExperienceManager::CStartExperienceManager() + PBYTE match1 = FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x48\x8D\x8E\x00\x00\x00\x00\x44\x8D\x45\x00\x48\x8D\x56\x00\xE8", + "xxx????xxx?xxx?x" + ); + if (match1) + { + g_SMAnimationPatchOffsets.startExperienceManager_singleViewShellExperience = *(int*)(match1 + 3); + g_SMAnimationPatchOffsets.startExperienceManager_singleViewShellExperienceEventHandler = (int)*(char*)(match1 + 14); + printf("[SMA] match1 = %llX\n", match1 - (PBYTE)mi->lpBaseOfDll); + } + + // ### Offsets of Animation Helpers + // ``` + // 40 88 AE ?? ?? ?? ?? C7 86 ?? ?? ?? ?? 38 00 00 00 + // ^^^^^^^^^^^ AH1 + // ``` + // Ref: CStartExperienceManager::CStartExperienceManager() + // AH2 is located right after AH1. AH is 32 bytes + PBYTE match2 = FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x40\x88\xAE\x00\x00\x00\x00\xC7\x86\x00\x00\x00\x00\x38\x00\x00\x00", + "xxx????xx????xxxx" + ); + if (match2) + { + g_SMAnimationPatchOffsets.startExperienceManager_openingAnimation = *(int*)(match2 + 3); + g_SMAnimationPatchOffsets.startExperienceManager_closingAnimation = g_SMAnimationPatchOffsets.startExperienceManager_openingAnimation + 32; + printf("[SMA] match2 = %llX\n", match2 - (PBYTE)mi->lpBaseOfDll); + } + + // ### Offset of bMaybeFullScreenMode + // ``` + // 80 B9 ?? ?? ?? ?? 00 0F 85 ?? ?? ?? ?? 45 33 C0 B2 01 + // ^^^^^^^^^^^ bMaybeFullScreenMode + // ``` + // Ref: CStartExperienceManager::OnViewHidden() + // TODO Broke on 25951 Canary + PBYTE match3 = FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x80\xB9\x00\x00\x00\x00\x00\x0F\x85\x00\x00\x00\x00\x45\x33\xC0\xB2\x01", + "xx????xxx????xxxxx" + ); + if (match3) + { + g_SMAnimationPatchOffsets.startExperienceManager_bMaybeFullScreenMode = g_SMAnimationPatchOffsets.startExperienceManager_singleViewShellExperienceEventHandler + *(int*)(match3 + 2); + printf("[SMA] match3 = %llX\n", match3 - (PBYTE)mi->lpBaseOfDll); + } + + // ### Offset of CStartExperienceManager::GetMonitorInformation() + // ``` + // E8 ?? ?? ?? ?? 8B ?? 85 C0 0F 88 ?? ?? ?? ?? C6 44 24 + // ^^^^^^^^^^^ + // ``` + // Ref: CStartExperienceManager::PositionMenu() + PBYTE match4 = FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\xE8\x00\x00\x00\x00\x8B\x00\x85\xC0\x0F\x88\x00\x00\x00\x00\xC6\x44\x24", + "x????x?xxxx????xxx" + ); + if (match4) + { + match4 += 5 + *(int*)(match4 + 1); + CStartExperienceManager_GetMonitorInformationFunc = match4; + printf("[SMA] CStartExperienceManager::GetMonitorInformation() = %llX\n", match4 - (PBYTE)mi->lpBaseOfDll); + } + + // ### Offset of CExperienceManagerAnimationHelper::Begin() + // ``` + // 44 8B C7 E8 ?? ?? ?? ?? 85 C0 79 19 + // ^^^^^^^^^^^ + // ``` + // Ref: CJumpViewExperienceManager::OnViewUncloaking() + PBYTE match5 = FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x44\x8B\xC7\xE8\x00\x00\x00\x00\x85\xC0\x79\x19", + "xxxx????xxxx" + ); + if (match5) + { + match5 += 3; + match5 += 5 + *(int*)(match5 + 1); + CExperienceManagerAnimationHelper_BeginFunc = match5; + printf("[SMA] CExperienceManagerAnimationHelper::Begin() = %llX\n", match5 - (PBYTE)mi->lpBaseOfDll); + } + + // ### Offset of CExperienceManagerAnimationHelper::End() + // ``` + // 40 53 48 83 EC 20 80 39 00 74 + // ``` + PBYTE match6 = FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x40\x53\x48\x83\xEC\x20\x80\x39\x00\x74", + "xxxxxxxxxx" + ); + if (match6) + { + CExperienceManagerAnimationHelper_EndFunc = match6; + printf("[SMA] CExperienceManagerAnimationHelper::End() = %llX\n", match6 - (PBYTE)mi->lpBaseOfDll); + } + + // ### CStartExperienceManager::Hide() + // ``` + // 74 ?? ?? 03 00 00 00 44 88 + // ^^ Turn jz into jmp + // ``` + // Perform on exactly two matches + PBYTE match7a = FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x74\x00\x00\x03\x00\x00\x00\x44\x88", + "x??xxxxxx" + ); + PBYTE match7b = NULL; + if (match7a) + { + printf("[SMA] match7a in CStartExperienceManager::Hide() = %llX\n", match7a - (PBYTE)mi->lpBaseOfDll); + match7b = FindPattern( + match7a + 14, + mi->SizeOfImage - (match7a + 14 - (PBYTE)mi->lpBaseOfDll), + "\x74\x00\x00\x03\x00\x00\x00\x44\x88", + "x??xxxxxx" + ); + if (match7b) + { + printf("[SMA] match7b in CStartExperienceManager::Hide() = %llX\n", match7b - (PBYTE)mi->lpBaseOfDll); + } + } + + // ### CStartExperienceManager::OnViewCloaking() + // ``` + // 48 83 EC 28 80 B9 ?? ?? ?? ?? 00 75 ?? 45 33 C0 + // ``` + // Just hook + // TODO: Broke on 25951 Canary + PBYTE match8 = FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x48\x83\xEC\x28\x80\xB9\x00\x00\x00\x00\x00\x75\x00\x45\x33\xC0", + "xxxxxx????xx?xxx" + ); + if (match8) + { + OnViewCloakingFunc = match8; + printf("[SMA] CStartExperienceManager::OnViewCloaking() = %llX\n", match8 - (PBYTE)mi->lpBaseOfDll); + } + + // ### CStartExperienceManager::OnViewHidden() + // ``` + // 80 B9 ?? ?? ?? ?? 00 0F 85 ?? ?? ?? ?? 45 33 C0 B2 01 + // ^^ Start overwriting here. 17 bytes, rest NOP + // ``` + // TODO Broke on 25951 Canary + PBYTE match9 = FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x80\xB9\x00\x00\x00\x00\x00\x0F\x85\x00\x00\x00\x00\x45\x33\xC0\xB2\x01", + "xx????xxx????xxxxx" + ); + if (match9) + { + printf("[SMA] match9 in CStartExperienceManager::OnViewHidden() = %llX\n", match9 - (PBYTE)mi->lpBaseOfDll); + } + + // ### CStartExperienceManager::OnViewUncloaked() + // ``` + // 48 83 EC 28 45 33 C0 48 8D 0D ?? ?? ?? ?? B2 01 E8 ?? ?? ?? ?? 33 C0 + // ``` + // Just hook + // TODO: Broke on 25951 Canary + PBYTE match10 = FindPattern( + mi->lpBaseOfDll, + mi->SizeOfImage, + "\x48\x83\xEC\x28\x45\x33\xC0\x48\x8D\x0D\x00\x00\x00\x00\xB2\x01\xE8\x00\x00\x00\x00\x33\xC0", + "xxxxxxxxxx????xxx????xx" + ); + if (match10) + { + OnViewUncloakedFunc = match10; + printf("[SMA] CStartExperienceManager::OnViewUncloaked() = %llX\n", match10 - (PBYTE)mi->lpBaseOfDll); + } + + if (!match1 || !match2 || !match3 || !match4 || !match5 || !match6 || !match7a || !match7b || !match8 || !match9 || !match10) + { + printf("[SMA] Not all offsets were found, cannot perform patch\n"); + return FALSE; + } + + int rv = funchook_prepare( + funchook, + (void**)&CStartExperienceManager_GetMonitorInformationFunc, + CStartExperienceManager_GetMonitorInformationHook + ); + if (rv != 0) + { + printf("Failed to hook CStartExperienceManager::GetMonitorInformation(). rv = %d\n", rv); + } + + DWORD dwOldProtect = 0; + if (VirtualProtect(match7a + 11, 1, PAGE_EXECUTE_READWRITE, &dwOldProtect)) + { + match7a[0] = 0xEB; + VirtualProtect(match7a + 11, 1, dwOldProtect, &dwOldProtect); + + dwOldProtect = 0; + if (VirtualProtect(match7b + 11, 1, PAGE_EXECUTE_READWRITE, &dwOldProtect)) + { + match7b[0] = 0xEB; + VirtualProtect(match7b + 11, 1, dwOldProtect, &dwOldProtect); + } + } + + rv = funchook_prepare( + funchook, + (void**)&OnViewCloakingFunc, + OnViewCloakingHook + ); + if (rv != 0) + { + printf("Failed to hook CStartExperienceManager::OnViewCloaking(). rv = %d\n", rv); + } + + PBYTE begin = match9 + 13; + PBYTE end = begin + 17; + + // Craft the code to call End() + BYTE code[] = { + // lea rcx, [rbx+] ; rbx is the `this`, offset to closingAnimation + 0x48, 0x8D, 0x8B, 0x11, 0x11, 0x11, 0x11, + // call CExperienceManagerAnimationHelper::End + 0xE8, 0x22, 0x22, 0x22, 0x22, + }; + + *(int*)(code + 3) = -g_SMAnimationPatchOffsets.startExperienceManager_singleViewShellExperienceEventHandler + g_SMAnimationPatchOffsets.startExperienceManager_closingAnimation; + *(int*)(code + 8) = (int)((PBYTE)CExperienceManagerAnimationHelper_EndFunc - (begin + sizeof(code))); + + PBYTE nopBegin = begin + sizeof(code); + + dwOldProtect = 0; + if (VirtualProtect(begin, end - begin, PAGE_EXECUTE_READWRITE, &dwOldProtect)) + { + memcpy(begin, code, sizeof(code)); + memset(nopBegin, 0x90, end - nopBegin); + VirtualProtect(begin, end - begin, dwOldProtect, &dwOldProtect); + } + + rv = funchook_prepare( + funchook, + (void**)&OnViewUncloakedFunc, + OnViewUncloakedHook + ); + if (rv != 0) + { + printf("Failed to hook CStartExperienceManager::OnViewUncloaked(). rv = %d\n", rv); + } + + return TRUE; +} +#endif +#pragma endregion + + DWORD Inject(BOOL bIsExplorer) { #if defined(DEBUG) | defined(_DEBUG) @@ -11009,7 +11385,9 @@ DWORD Inject(BOOL bIsExplorer) { VnPatchIAT(hExplorer, "user32.dll", (LPCSTR)2005, explorer_SetChildWindowNoActivateHook); VnPatchDelayIAT(hExplorer, "ext-ms-win-rtcore-ntuser-window-ext-l1-1-0.dll", "SendMessageW", explorer_SendMessageW); - VnPatchIAT(hExplorer, "api-ms-win-core-libraryloader-l1-2-0.dll", "GetProcAddress", explorer_GetProcAddressHook); + // A certain configuration update in 23560.1000 broke this method, this didn't get called with + // "RoGetActivationFactory" anymore. We're now hooking RoGetActivationFactory directly. + // VnPatchIAT(hExplorer, "api-ms-win-core-libraryloader-l1-2-0.dll", "GetProcAddress", explorer_GetProcAddressHook); VnPatchIAT(hExplorer, "shell32.dll", "ShellExecuteW", explorer_ShellExecuteW); VnPatchIAT(hExplorer, "shell32.dll", "ShellExecuteExW", explorer_ShellExecuteExW); VnPatchIAT(hExplorer, "API-MS-WIN-CORE-REGISTRY-L1-1-0.DLL", "RegGetValueW", explorer_RegGetValueW); @@ -11315,17 +11693,53 @@ DWORD Inject(BOOL bIsExplorer) 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+ + && global_rovi.dwBuildNumber < 25000 // But not on 25xxx (yet) + && 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. + DWORD crashCounterDisabled = 0, dwTCSize = sizeof(DWORD); + RegGetValueW(HKEY_CURRENT_USER, _T(REGPATH), L"CrashCounterDisabled", RRF_RT_DWORD, NULL, &crashCounterDisabled, &dwTCSize); dwTCSize = sizeof(DWORD); + if (crashCounterDisabled != 0 && crashCounterDisabled != 1) crashCounterDisabled = 0; + + if (!crashCounterDisabled) + { + FixStartMenuAnimation(&miTwinuiPcshell); + } + } #endif VnPatchIAT(hTwinuiPcshell, "API-MS-WIN-CORE-REGISTRY-L1-1-0.DLL", "RegGetValueW", twinuipcshell_RegGetValueW); printf("Setup twinui.pcshell functions done\n"); - if (IsWindows11Version22H2OrHigher()) + if (IsWindows11()) { HANDLE hCombase = LoadLibraryW(L"combase.dll"); - // Fixed a bug that crashed Explorer when a folder window was opened after a first one was closed on OS builds 22621+ - VnPatchIAT(hCombase, "api-ms-win-core-libraryloader-l1-2-0.dll", "LoadLibraryExW", Windows11v22H2_combase_LoadLibraryExW); + if (bOldTaskbar) + { + // Hook RoGetActivationFactory() for old taskbar + explorer_RoGetActivationFactoryFunc = GetProcAddress(hCombase, "RoGetActivationFactory"); + if (explorer_RoGetActivationFactoryFunc) + { + rv = funchook_prepare( + funchook, + (void**)&explorer_RoGetActivationFactoryFunc, + explorer_RoGetActivationFactoryHook + ); + } + if (rv != 0) + { + printf("Failed to hook RoGetActivationFactory(). rv = %d\n", rv); + } + } + if (IsWindows11Version22H2OrHigher()) + { + // Fixed a bug that crashed Explorer when a folder window was opened after a first one was closed on OS builds 22621+ + VnPatchIAT(hCombase, "api-ms-win-core-libraryloader-l1-2-0.dll", "LoadLibraryExW", Windows11v22H2_combase_LoadLibraryExW); + } printf("Setup combase functions done\n"); } @@ -12166,6 +12580,96 @@ LSTATUS StartUI_RegGetValueW(HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpValue, DWORD return RegGetValueW(hkey, lpSubKey, lpValue, dwFlags, pdwType, pvData, pcbData); } +typedef enum Parser_XamlBufferType +{ + XBT_Text, + XBT_Binary, + XBT_MemoryMappedResource +} Parser_XamlBufferType; + +typedef struct Parser_XamlBuffer +{ + unsigned int m_count; + Parser_XamlBufferType m_bufferType; + const unsigned __int8* m_buffer; +} Parser_XamlBuffer; + +static BOOL StartMenu_FillParserBuffer(Parser_XamlBuffer* pBuffer, int resourceId) +{ + HRSRC hRscr = FindResource(hModule, MAKEINTRESOURCE(resourceId), RT_RCDATA); + if (!hRscr) + return FALSE; + + HGLOBAL hgRscr = LoadResource(hModule, hRscr); + if (!hgRscr) + return FALSE; + + pBuffer->m_buffer = LockResource(hgRscr); + pBuffer->m_count = SizeofResource(hModule, hRscr); + pBuffer->m_bufferType = XBT_Binary; + return TRUE; +} + +Parser_XamlBuffer g_EmptyRefreshedStylesXbfBuffer; + +HRESULT(*CCoreServices_TryLoadXamlResourceHelperFunc)(void* _this, void* pUri, bool* pfHasBinaryFile, void** ppMemory, Parser_XamlBuffer* pBuffer, void** ppPhysicalUri); +HRESULT CCoreServices_TryLoadXamlResourceHelperHook(void* _this, void* pUri, bool* pfHasBinaryFile, void** ppMemory, Parser_XamlBuffer* pBuffer, void** ppPhysicalUri) +{ + HRESULT(*Clone)(void* _this, void** ppUri); // index 3 + HRESULT(*GetPath)(void* _this, unsigned int* pBufferLength, wchar_t* pszBuffer); // index 12 + void** vtable = *(void***)pUri; + Clone = vtable[3]; + GetPath = vtable[12]; + wchar_t thePath[MAX_PATH]; + unsigned int len = MAX_PATH; + GetPath(pUri, &len, thePath); + // OutputDebugStringW(thePath); OutputDebugStringW(L"<<<<<\n"); + + if (!wcscmp(thePath, L"/JumpViewUI/RefreshedStyles.xaml")) + { + *pfHasBinaryFile = true; + *pBuffer = g_EmptyRefreshedStylesXbfBuffer; + if (ppPhysicalUri) + Clone(pUri, ppPhysicalUri); + return pBuffer->m_buffer ? S_OK : E_FAIL; + } + + return CCoreServices_TryLoadXamlResourceHelperFunc(_this, pUri, pfHasBinaryFile, ppMemory, pBuffer, ppPhysicalUri); +} + +static BOOL StartMenu_FixContextMenuXbfHijackMethod() +{ + LoadLibraryW(L"Windows.UI.Xaml.dll"); + HANDLE hWindowsUIXaml = GetModuleHandleW(L"Windows.UI.Xaml.dll"); + MODULEINFO mi; + GetModuleInformation(GetCurrentProcess(), hWindowsUIXaml, &mi, sizeof(mi)); + + if (!StartMenu_FillParserBuffer(&g_EmptyRefreshedStylesXbfBuffer, IDR_REFRESHEDSTYLES_XBF)) + return FALSE; + + // 49 89 43 C8 E8 ?? ?? ?? ?? 85 C0 + // ^^^^^^^^^^^ + // Ref: CCoreServices::LoadXamlResource() + PBYTE match = FindPattern( + mi.lpBaseOfDll, + mi.SizeOfImage, + "\x49\x89\x43\xC8\xE8\x00\x00\x00\x00\x85\xC0", + "xxxxx????xx" + ); + if (!match) + return FALSE; + + match += 4; + match += 5 + *(int*)(match + 1); + CCoreServices_TryLoadXamlResourceHelperFunc = match; + funchook_prepare( + funchook, + (void**)&CCoreServices_TryLoadXamlResourceHelperFunc, + CCoreServices_TryLoadXamlResourceHelperHook + ); + return TRUE; +} + LSTATUS StartUI_RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) { if (wcsstr(lpSubKey, L"$start.tilegrid$windows.data.curatedtilecollection.tilecollection\\Current")) @@ -12213,7 +12717,8 @@ int Start_SetWindowRgn(HWND hWnd, HRGN hRgn, BOOL bRedraw) HRESULT hr = IsThreadCoreWindowVisible(&bIsWindowVisible); if (SUCCEEDED(hr)) { - if (IsWindows11()) ShowWindow(hWnd, bIsWindowVisible ? SW_SHOW : SW_HIDE); + if (global_rovi.dwBuildNumber >= 25000 && dwStartShowClassicMode) + ShowWindow(hWnd, bIsWindowVisible ? SW_SHOW : SW_HIDE); DWORD TaskbarAl = InterlockedAdd(&dwTaskbarAl, 0); if (bIsWindowVisible && (!TaskbarAl ? (dwStartShowClassicMode ? StartUI_EnableRoundedCornersApply : StartDocked_DisableRecommendedSectionApply) : 1)) { @@ -12797,13 +13302,17 @@ DWORD InjectStartMenu() PatchAppResolver(); PatchStartTileData(); - // Redirects to pri files from 22000.51 which work with the legacy menu - LoadLibraryW(L"MrmCoreR.dll"); - HANDLE hMrmCoreR = GetModuleHandleW(L"MrmCoreR.dll"); - VnPatchIAT(hMrmCoreR, "api-ms-win-core-file-l1-1-0.dll", "CreateFileW", StartUI_CreateFileW); - VnPatchIAT(hMrmCoreR, "api-ms-win-core-file-l1-1-0.dll", "GetFileAttributesExW", StartUI_GetFileAttributesExW); - VnPatchIAT(hMrmCoreR, "api-ms-win-core-file-l1-1-0.dll", "FindFirstFileW", StartUI_FindFirstFileW); - VnPatchIAT(hMrmCoreR, "api-ms-win-core-registry-l1-1-0.dll", "RegGetValueW", StartUI_RegGetValueW); + // Fixes context menu crashes + if (!StartMenu_FixContextMenuXbfHijackMethod()) { + // Fallback to the old method, but we'll have broken localization + // Redirects to pri files from 22000.51 which work with the legacy menu + LoadLibraryW(L"MrmCoreR.dll"); + HANDLE hMrmCoreR = GetModuleHandleW(L"MrmCoreR.dll"); + VnPatchIAT(hMrmCoreR, "api-ms-win-core-file-l1-1-0.dll", "CreateFileW", StartUI_CreateFileW); + VnPatchIAT(hMrmCoreR, "api-ms-win-core-file-l1-1-0.dll", "GetFileAttributesExW", StartUI_GetFileAttributesExW); + VnPatchIAT(hMrmCoreR, "api-ms-win-core-file-l1-1-0.dll", "FindFirstFileW", StartUI_FindFirstFileW); + VnPatchIAT(hMrmCoreR, "api-ms-win-core-registry-l1-1-0.dll", "RegGetValueW", StartUI_RegGetValueW); + } // Enables "Show more tiles" setting LoadLibraryW(L"Windows.CloudStore.dll"); diff --git a/ExplorerPatcher/fmemopen.h b/ExplorerPatcher/fmemopen.h index 3c337ee88..630d6df6f 100644 --- a/ExplorerPatcher/fmemopen.h +++ b/ExplorerPatcher/fmemopen.h @@ -5,5 +5,15 @@ #include #include #include + +#ifdef __cplusplus +extern "C" { +#endif + FILE* fmemopen(void* buf, size_t len, const char* type); + +#ifdef __cplusplus +} +#endif + #endif \ No newline at end of file diff --git a/ExplorerPatcher/getline.h b/ExplorerPatcher/getline.h index 6760bc1e4..123d9734e 100644 --- a/ExplorerPatcher/getline.h +++ b/ExplorerPatcher/getline.h @@ -5,8 +5,16 @@ #include typedef SSIZE_T ssize_t; +#ifdef __cplusplus +extern "C" { +#endif + ssize_t getdelim(char** buf, size_t* bufsiz, int delimiter, FILE* fp); ssize_t getline(char** buf, size_t* bufsiz, FILE* fp); +#ifdef __cplusplus +} +#endif + #endif \ No newline at end of file diff --git a/ExplorerPatcher/osutility.h b/ExplorerPatcher/osutility.h index 833b6484c..de3c8be24 100644 --- a/ExplorerPatcher/osutility.h +++ b/ExplorerPatcher/osutility.h @@ -20,6 +20,10 @@ #endif #define DWMWA_MICA_EFFFECT 1029 +#ifdef __cplusplus +extern "C" { +#endif + extern RTL_OSVERSIONINFOW global_rovi; extern DWORD32 global_ubr; @@ -94,4 +98,9 @@ inline BOOL IsWindows11Version22H2Build2361OrHigher() if (global_rovi.dwBuildNumber > 22621) return TRUE; return global_rovi.dwBuildNumber == 22621 && global_ubr >= 2361; } + +#ifdef __cplusplus +} +#endif + #endif diff --git a/ExplorerPatcher/resource.h b/ExplorerPatcher/resource.h index 57986c4dc..2e86782dd 100644 --- a/ExplorerPatcher/resource.h +++ b/ExplorerPatcher/resource.h @@ -16,6 +16,7 @@ #define IDS_UNINSTALL_ERROR_TEXT 112 #define IDS_OPERATION_NONE 113 #define IDR_REGISTRY2 114 +#define IDR_REFRESHEDSTYLES_XBF 115 #define IDS_DRIVECATEGORY_HARDDISKDRIVES 40000 #define IDS_DRIVECATEGORY_REMOVABLESTORAGE 40001 #define IDS_DRIVECATEGORY_OTHER 40002 diff --git a/ExplorerPatcher/utility.c b/ExplorerPatcher/utility.c index c39cfb1ad..d702a0be6 100644 --- a/ExplorerPatcher/utility.c +++ b/ExplorerPatcher/utility.c @@ -163,7 +163,7 @@ LRESULT CALLBACK BalloonWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPara return 0; } -__declspec(dllexport) CALLBACK ZZTestBalloon(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow) +__declspec(dllexport) int CALLBACK ZZTestBalloon(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow) { TCHAR* lpwszCmdLine = calloc((strlen(lpszCmdLine) + 1), sizeof(TCHAR)); if (!lpwszCmdLine) exit(0); @@ -199,6 +199,8 @@ __declspec(dllexport) CALLBACK ZZTestBalloon(HWND hWnd, HINSTANCE hInstance, LPS TranslateMessage(&msg); DispatchMessage(&msg); } + + return 0; } const wchar_t TestToastXML[] = @@ -212,7 +214,7 @@ L" \r\n" L" \r\n" L"