diff --git a/ExplorerPatcher/dllmain.c b/ExplorerPatcher/dllmain.c index 4aa44c0..df04210 100644 --- a/ExplorerPatcher/dllmain.c +++ b/ExplorerPatcher/dllmain.c @@ -4076,6 +4076,11 @@ LSTATUS stobject_RegGetValueW( return RegGetValueW(hkey, lpSubKey, lpValue, dwFlags, pdwType, pvData, pcbData); } +DEFINE_GUID(CLSID_NetworkTraySSO, 0xC2796011, 0x81BA, 0x4148, 0x8F, 0xCA, 0xC6, 0x64, 0x32, 0x45, 0x11, 0x3F); +DEFINE_GUID(CLSID_WindowsToGoSSO, 0x4DC9C264, 0x730E, 0x4CF6, 0x83, 0x74, 0x70, 0xF0, 0x79, 0xE4, 0xF8, 0x2B); + +typedef HRESULT(WINAPI* DllGetClassObject_t)(REFCLSID rclsid, REFIID riid, LPVOID* ppv); + HRESULT stobject_CoCreateInstanceHook( REFCLSID rclsid, LPUNKNOWN pUnkOuter, @@ -4084,6 +4089,28 @@ HRESULT stobject_CoCreateInstanceHook( LPVOID* ppv ) { + if (global_rovi.dwBuildNumber >= 25000 && IsEqualGUID(rclsid, &CLSID_NetworkTraySSO)) + { + 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"\\pnidui.dll"); + HMODULE hPnidui = LoadLibraryW(szPath); + DllGetClassObject_t pfnDllGetClassObject = hPnidui ? (DllGetClassObject_t)GetProcAddress(hPnidui, "DllGetClassObject") : NULL; + if (!pfnDllGetClassObject) + { + return REGDB_E_CLASSNOTREG; + } + IClassFactory* pClassFactory = NULL; + HRESULT hr = pfnDllGetClassObject(rclsid, &IID_IClassFactory, (LPVOID*)&pClassFactory); + if (SUCCEEDED(hr)) + { + hr = pClassFactory->lpVtbl->CreateInstance(pClassFactory, pUnkOuter, riid, ppv); + pClassFactory->lpVtbl->Release(pClassFactory); + } + return hr; + } + DWORD dwVal = 0, dwSize = sizeof(DWORD); if (IsEqualGUID(rclsid, &CLSID_ImmersiveShell) && IsEqualGUID(riid, &IID_IServiceProvider) && @@ -10240,6 +10267,10 @@ DWORD InjectBasicFunctions(BOOL bIsExplorer, BOOL bInstall) { DWORD dwSize = sizeof(DWORD); RegGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", L"Start_ShowClassicMode", RRF_RT_DWORD, NULL, &dwStartShowClassicMode, &dwSize); + if (!DoesWindows10StartMenuExist()) + { + dwStartShowClassicMode = 0; + } } #ifdef _WIN64 @@ -11797,6 +11828,179 @@ BOOL CrashCounterHandleEntryPoint() #pragma endregion +#pragma region "Loader for alternate taskbar implementation" +#ifdef _WIN64 +void PrepareAlternateTaskbarImplementation(symbols_addr* symbols_PTRS) +{ + if (!IsWindows11Version22H2OrHigher()) + return; // Definitely unsupported + + if (bOldTaskbar <= 1) + return; // Not enabled + + const WCHAR* pszTaskbarDll = PickTaskbarDll(); + if (!pszTaskbarDll) + { + wprintf(L"[TB] Unsupported build\n"); + return; + } + + bool bAllValid = true; + for (SIZE_T j = 0; j < ARRAYSIZE(symbols_PTRS->explorer_PTRS); ++j) + { + DWORD i = symbols_PTRS->explorer_PTRS[j]; + bAllValid &= i && i != 0xFFFFFFFF; + if (!bAllValid) + break; + } + + if (!bAllValid) + { + wprintf(L"[TB] Missing offsets\n"); + return; + } + + 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); + HMODULE hMyTaskbar = LoadLibraryW(szPath); + if (!hMyTaskbar) + { + wprintf(L"[TB] '%s' not found\n", pszTaskbarDll); + return; + } + + explorer_TrayUI_CreateInstanceFunc = GetProcAddress(hMyTaskbar, "EP_TrayUI_CreateInstance"); + + typedef DWORD (*GetVersion_t)(); + GetVersion_t GetVersion = (GetVersion_t)GetProcAddress(hMyTaskbar, "GetVersion"); + if (GetVersion) + { + DWORD version = GetVersion(); + if (version != 1) + { + wprintf(L"[TB] Version mismatch: %d\n", version); + return; + } + } + + typedef void (*CopyExplorerSymbols_t)(symbols_addr* symbols); + CopyExplorerSymbols_t CopyExplorerSymbols = (CopyExplorerSymbols_t)GetProcAddress(hMyTaskbar, "CopyExplorerSymbols"); + if (CopyExplorerSymbols) + { + CopyExplorerSymbols(symbols_PTRS); + } + + typedef void (*SetImmersiveMenuFunctions_t)(void* a, void* b, void* c); + SetImmersiveMenuFunctions_t SetImmersiveMenuFunctions = (SetImmersiveMenuFunctions_t)GetProcAddress(hMyTaskbar, "SetImmersiveMenuFunctions"); + if (SetImmersiveMenuFunctions) + { + SetImmersiveMenuFunctions( + CImmersiveContextMenuOwnerDrawHelper_s_ContextMenuWndProcFunc, + ImmersiveContextMenuHelper_ApplyOwnerDrawToMenuFunc, + ImmersiveContextMenuHelper_RemoveOwnerDrawFromMenuFunc + ); + } + + wprintf(L"[TB] Using '%s'\n", pszTaskbarDll); +} +#endif +#pragma endregion + + +#pragma region "Restore network icon on builds without pnidui.dll shipped" +#ifdef _WIN64 +typedef struct SSOEntry +{ + GUID* pguid; + int sharedThread; + DWORD dwFlags; + bool (*pfnCheckEnabled)(); +} SSOEntry; + +void PatchStobject(HANDLE hStobject) +{ + PBYTE beginRData = NULL; + DWORD sizeRData = 0; + + // Our target is in .rdata + PIMAGE_DOS_HEADER dosHeader = hStobject; + if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE) + { + PIMAGE_NT_HEADERS64 ntHeader = (PIMAGE_NT_HEADERS64)((u_char*)dosHeader + dosHeader->e_lfanew); + if (ntHeader->Signature == IMAGE_NT_SIGNATURE) + { + for (unsigned int i = 0; i < ntHeader->FileHeader.NumberOfSections; ++i) + { + PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(ntHeader) + i; + if (!strncmp(section->Name, ".rdata", 6)) + { + beginRData = (PBYTE)dosHeader + section->VirtualAddress; + sizeRData = section->SizeOfRawData; + break; + } + } + } + } + if (!beginRData || !sizeRData) + { + return; + } + + // We'll sacrifice the Windows To Go SSO for this + GUID* pguidTarget = memmem(beginRData, sizeRData, &CLSID_WindowsToGoSSO, sizeof(GUID)); + if (!pguidTarget) + { + return; + } + printf("[SSO] pguidTarget = %llX\n", (PBYTE)pguidTarget - (PBYTE)hStobject); + + // Find where it's used + SSOEntry* pssoEntryTarget = NULL; + SIZE_T searchSize = (SIZE_T)sizeRData - sizeof(SSOEntry); + for (SIZE_T i = 0; i < searchSize; i += 8) // We know the struct is aligned, save some iterations + { + SSOEntry* current = (SSOEntry*)(beginRData + i); + if (current->pguid == pguidTarget && current->sharedThread == 0 && current->dwFlags == 0 && current->pfnCheckEnabled) + { + pssoEntryTarget = current; + break; + } + } + if (!pssoEntryTarget) + { + return; + } + printf("[SSO] pssoEntryTarget = %llX\n", (PBYTE)pssoEntryTarget - (PBYTE)hStobject); + + // Make sure it's really not used + if (pssoEntryTarget->pfnCheckEnabled && pssoEntryTarget->pfnCheckEnabled()) + { + return; + } + + // Modify the GUID + DWORD dwOldProtect = 0; + if (VirtualProtect(pguidTarget, sizeof(GUID), PAGE_EXECUTE_READWRITE, &dwOldProtect)) + { + *pguidTarget = CLSID_NetworkTraySSO; + VirtualProtect(pguidTarget, sizeof(GUID), dwOldProtect, &dwOldProtect); + } + + // Modify the SSOEntry + if (VirtualProtect(pssoEntryTarget, sizeof(SSOEntry), PAGE_EXECUTE_READWRITE, &dwOldProtect)) + { + pssoEntryTarget->sharedThread = 1; + pssoEntryTarget->dwFlags = 0; + pssoEntryTarget->pfnCheckEnabled = NULL; + VirtualProtect(pssoEntryTarget, sizeof(SSOEntry), dwOldProtect, &dwOldProtect); + } +} +#endif +#pragma endregion + DWORD Inject(BOOL bIsExplorer) { #if defined(DEBUG) | defined(_DEBUG) @@ -12346,7 +12550,7 @@ DWORD Inject(BOOL bIsExplorer) if (symbols_PTRS.twinui_pcshell_PTRS[7] && symbols_PTRS.twinui_pcshell_PTRS[7] != 0xFFFFFFFF) { twinui_pcshell_CMultitaskingViewManager__CreateDCompMTVHostFunc = (INT64(*)(void*, POINT*)) - ((uintptr_t)hTwinuiPcshell + symbols_PTRS.twinui_pcshell_PTRS[TWINUI_PCSHELL_SB_CNT - 1]); + ((uintptr_t)hTwinuiPcshell + symbols_PTRS.twinui_pcshell_PTRS[8]); twinui_pcshell_CMultitaskingViewManager__CreateXamlMTVHostFunc = (INT64(*)(void*, POINT*)) ((uintptr_t)hTwinuiPcshell + symbols_PTRS.twinui_pcshell_PTRS[7]); rv = funchook_prepare( @@ -12449,6 +12653,7 @@ DWORD Inject(BOOL bIsExplorer) #endif VnPatchIAT(hTwinuiPcshell, "API-MS-WIN-CORE-REGISTRY-L1-1-0.DLL", "RegGetValueW", twinuipcshell_RegGetValueW); + PrepareAlternateTaskbarImplementation(&symbols_PTRS); printf("Setup twinui.pcshell functions done\n"); @@ -12493,6 +12698,10 @@ DWORD Inject(BOOL bIsExplorer) VnPatchIAT(hStobject, "user32.dll", "TrackPopupMenu", stobject_TrackPopupMenuHook); VnPatchIAT(hStobject, "user32.dll", "TrackPopupMenuEx", stobject_TrackPopupMenuExHook); } + if (global_rovi.dwBuildNumber >= 25000) + { + PatchStobject(hStobject); + } #ifdef USE_PRIVATE_INTERFACES if (bSkinIcons) { @@ -12576,11 +12785,11 @@ DWORD Inject(BOOL bIsExplorer) } // Allow clasic drive groupings in This PC - HRESULT(*SHELL32_DllGetClassObject)(REFCLSID rclsid, REFIID riid, LPVOID* ppv) = GetProcAddress(hShell32, "DllGetClassObject"); + DllGetClassObject_t SHELL32_DllGetClassObject = (DllGetClassObject_t)GetProcAddress(hShell32, "DllGetClassObject"); if (SHELL32_DllGetClassObject) { IClassFactory* pClassFactory = NULL; - SHELL32_DllGetClassObject(&CLSID_DriveTypeCategorizer, &IID_IClassFactory, &pClassFactory); + SHELL32_DllGetClassObject(&CLSID_DriveTypeCategorizer, &IID_IClassFactory, (LPVOID*)&pClassFactory); if (pClassFactory) { @@ -13094,6 +13303,10 @@ void StartMenu_LoadSettings(BOOL bRestartIfChanged) &dwVal, &dwSize ); + if (!DoesWindows10StartMenuExist()) + { + dwVal = 0; + } if (bRestartIfChanged && dwVal != dwStartShowClassicMode) { exit(0); diff --git a/ExplorerPatcher/utility.h b/ExplorerPatcher/utility.h index 7198238..e656c7a 100644 --- a/ExplorerPatcher/utility.h +++ b/ExplorerPatcher/utility.h @@ -682,6 +682,54 @@ inline HMODULE LoadGuiModule() 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"); + return FileExistsW(szPath); +} + +inline const WCHAR* PickTaskbarDll() +{ + DWORD b = global_rovi.dwBuildNumber; + + 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 + { + return L"ep_taskbar.3.dll"; + } + + if (b >= 25921) // Canary channel with nuked classic system tray + { + return L"ep_taskbar.4.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); +} + #ifdef __cplusplus } #endif diff --git a/ep_gui/GUI.c b/ep_gui/GUI.c index 513605b..93991cf 100644 --- a/ep_gui/GUI.c +++ b/ep_gui/GUI.c @@ -972,6 +972,18 @@ static void GUI_UpdateLanguages() EP_L10N_GetCurrentThreadLanguage(wszThreadLanguage, ARRAYSIZE(wszThreadLanguage)); } +DWORD GUI_GetTaskbarStyle() +{ + DWORD dwRes = IsWindows11() ? 0 : 1; + DWORD dwSize = sizeof(DWORD); + RegGetValueW(HKEY_CURRENT_USER, _T(REGPATH), L"OldTaskbar", RRF_RT_DWORD, NULL, &dwRes, &dwSize); + if (dwRes >= 2 && !DoesTaskbarDllExist()) + { + dwRes = 1; + } + return dwRes; +} + static BOOL GUI_Build(HDC hDC, HWND hwnd, POINT pt) { GUI* _this; @@ -1121,14 +1133,19 @@ static BOOL GUI_Build(HDC hDC, HWND hwnd, POINT pt) if (!_stricmp(funcName, "DoesOSBuildSupportSpotlight") && !DoesOSBuildSupportSpotlight()) bSkipLines = TRUE; else if (!_stricmp(funcName, "IsSpotlightEnabled") && !IsSpotlightEnabled()) bSkipLines = TRUE; else if (!_stricmp(funcName, "IsSWSEnabled") && (dwRes = 0, RegGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer", L"AltTabSettings", RRF_RT_DWORD, NULL, &dwRes, &dwSize), (dwRes != 2))) bSkipLines = TRUE; - else if (!_stricmp(funcName, "IsOldTaskbar") && (dwRes = 1, RegGetValueW(HKEY_CURRENT_USER, _T(REGPATH), L"OldTaskbar", RRF_RT_DWORD, NULL, &dwRes, &dwSize), (dwRes != 1))) bSkipLines = TRUE; - else if (!_stricmp(funcName, "!IsOldTaskbar") && (dwRes = 1, RegGetValueW(HKEY_CURRENT_USER, _T(REGPATH), L"OldTaskbar", RRF_RT_DWORD, NULL, &dwRes, &dwSize), (dwRes == 1))) bSkipLines = TRUE; - else if (!_stricmp(funcName, "IsWindows10StartMenu") && (dwRes = 0, RegGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", L"Start_ShowClassicMode", RRF_RT_DWORD, NULL, &dwRes, &dwSize), (dwRes != 1))) bSkipLines = TRUE; - else if (!_stricmp(funcName, "!IsWindows10StartMenu") && (dwRes = 0, RegGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", L"Start_ShowClassicMode", RRF_RT_DWORD, NULL, &dwRes, &dwSize), (dwRes == 1))) bSkipLines = TRUE; + else if (!_stricmp(funcName, "IsOldTaskbar") && GUI_GetTaskbarStyle() == 0) bSkipLines = TRUE; + else if (!_stricmp(funcName, "!IsOldTaskbar") && GUI_GetTaskbarStyle() != 0) bSkipLines = TRUE; + else if (!_stricmp(funcName, "IsStockWin10Taskbar") && GUI_GetTaskbarStyle() != 1) bSkipLines = TRUE; + else if (!_stricmp(funcName, "IsAltImplTaskbar") && GUI_GetTaskbarStyle() <= 1) bSkipLines = TRUE; + else if (!_stricmp(funcName, "DoesTaskbarDllExist") && !DoesTaskbarDllExist()) bSkipLines = TRUE; + else if (!_stricmp(funcName, "!DoesTaskbarDllExist") && DoesTaskbarDllExist()) bSkipLines = TRUE; + else if (!_stricmp(funcName, "IsWindows10StartMenu") && (!DoesWindows10StartMenuExist() || (dwRes = 0, RegGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", L"Start_ShowClassicMode", RRF_RT_DWORD, NULL, &dwRes, &dwSize), (dwRes != 1)))) bSkipLines = TRUE; + else if (!_stricmp(funcName, "!IsWindows10StartMenu") && (DoesWindows10StartMenuExist() && (dwRes = 0, RegGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", L"Start_ShowClassicMode", RRF_RT_DWORD, NULL, &dwRes, &dwSize), (dwRes == 1)))) bSkipLines = TRUE; + else if (!_stricmp(funcName, "DoesWindows10StartMenuExist") && !DoesWindows10StartMenuExist()) bSkipLines = TRUE; else if (!_stricmp(funcName, "IsWeatherEnabled") && (dwRes = 0, RegGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced\\People", L"PeopleBand", RRF_RT_DWORD, NULL, &dwRes, &dwSize), (dwRes != 1))) bSkipLines = TRUE; else if (!_stricmp(funcName, "IsWindows11Version22H2OrHigher") && !IsWindows11Version22H2OrHigher()) bSkipLines = TRUE; else if (!_stricmp(funcName, "!IsWindows11Version22H2OrHigher") && IsWindows11Version22H2OrHigher()) bSkipLines = TRUE; - else if (!_stricmp(funcName, "!(IsWindows11Version22H2OrHigher&&!IsOldTaskbar)") && (IsWindows11Version22H2OrHigher() && (dwRes = 1, RegGetValueW(HKEY_CURRENT_USER, _T(REGPATH), L"OldTaskbar", RRF_RT_DWORD, NULL, &dwRes, &dwSize), (dwRes != 1)))) bSkipLines = TRUE; + else if (!_stricmp(funcName, "!(IsWindows11Version22H2OrHigher&&!IsOldTaskbar)") && (IsWindows11Version22H2OrHigher() && GUI_GetTaskbarStyle() == 0)) bSkipLines = TRUE; if (bSkipLines) { do diff --git a/ep_gui/resources/EPSettingsResources.h b/ep_gui/resources/EPSettingsResources.h index f6196e3..f5824de 100644 --- a/ep_gui/resources/EPSettingsResources.h +++ b/ep_gui/resources/EPSettingsResources.h @@ -48,6 +48,7 @@ #define IDS_TB_ICONSIZE 1044 #define IDS_TB_ICONSIZE_1 1045 #define IDS_TB_ICONSIZE_0 1046 +#define IDS_TB_STYLE_2 1047 #define IDS_TRAY 1101 #define IDS_TRAY_SKINMENUS 1102 diff --git a/ep_gui/resources/lang/ep_gui.en-US.rc b/ep_gui/resources/lang/ep_gui.en-US.rc index 22dced8..492b056 100644 --- a/ep_gui/resources/lang/ep_gui.en-US.rc +++ b/ep_gui/resources/lang/ep_gui.en-US.rc @@ -40,6 +40,7 @@ BEGIN IDS_TB_STYLE "Taskbar style" IDS_TB_STYLE_0 "Windows 11 (default)" IDS_TB_STYLE_1 "Windows 10" + IDS_TB_STYLE_2 "Windows 10 (ExplorerPatcher)" IDS_TB_MORE "More taskbar options in the Settings app" IDS_TB_CUSTOMIZETRAYICONS "Customize notification area icons" IDS_TB_CUSTOMIZESYSTEMICONS "Customize system icons in the notification area" diff --git a/ep_gui/resources/settings.reg b/ep_gui/resources/settings.reg index 6b0559e..db883fb 100644 --- a/ep_gui/resources/settings.reg +++ b/ep_gui/resources/settings.reg @@ -5,11 +5,21 @@ ;q ;T %R:1001% +;s Taskbar_StyleSection1 DoesTaskbarDllExist +[HKEY_CURRENT_USER\Software\ExplorerPatcher] +;z 3 %R:1002% * +;x 0 %R:1003% +;x 1 %R:1004% +;x 2 %R:1047% +"OldTaskbar"=dword:00000001 +;g Taskbar_StyleSection1 +;s Taskbar_StyleSection2 !DoesTaskbarDllExist [HKEY_CURRENT_USER\Software\ExplorerPatcher] ;z 2 %R:1002% * ;x 0 %R:1003% ;x 1 %R:1004% "OldTaskbar"=dword:00000001 +;g Taskbar_StyleSection2 ;y %R:1005% 🡕 ;ms-settings:taskbar ;y %R:1006% 🡕 @@ -246,11 +256,13 @@ ;T %R:1301% +;s StartMenu_StyleSection DoesWindows10StartMenuExist [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced] ;z 2 %R:1302% * ;x 0 %R:1303% ;x 1 %R:1304% "Start_ShowClassicMode"=dword:00000000 +;g StartMenu_StyleSection ;y %R:1305% 🡕 ;ms-settings:personalization-start [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced] @@ -475,7 +487,7 @@ -;s Weather_Windows10 IsOldTaskbar +;s Weather_Windows10 IsStockWin10Taskbar ;T %R:1501% [HKEY_CURRENT_USER\Software\ExplorerPatcher] ;b %R:1502%