diff --git a/CHANGELOG.md b/CHANGELOG.md index f3fdfbe..c2da5e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ This document includes the same release notes as in the [Releases](https://github.com/valinet/ExplorerPatcher/releases) section on GitHub. +## 22000.282.33 + +Tested on build 22000.282. + +#### New features + +* Ability to choose language switcher flyout style (option available in the "Properties" - "System tray" section) + +#### Fixes + +* The key above the `Tab` key is now correctly identified for all keyboard layouts, so the per-application Windows 10 window switcher mode works correctly (#283) + ## 22000.282.32 Tested on build 22000.282. diff --git a/ExplorerPatcher/ExplorerPatcher.rc b/ExplorerPatcher/ExplorerPatcher.rc index 9375291..b195709 100644 --- a/ExplorerPatcher/ExplorerPatcher.rc +++ b/ExplorerPatcher/ExplorerPatcher.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 22000,282,32,7 - PRODUCTVERSION 22000,282,32,7 + FILEVERSION 22000,282,33,0 + PRODUCTVERSION 22000,282,33,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -69,12 +69,12 @@ BEGIN BEGIN VALUE "CompanyName", "VALINET Solutions SRL" VALUE "FileDescription", "ExplorerPatcher" - VALUE "FileVersion", "22000.282.32.7" + VALUE "FileVersion", "22000.282.33.0" VALUE "InternalName", "ExplorerPatcher.dll" VALUE "LegalCopyright", "Copyright (C) 2006-2021 VALINET Solutions SRL. All rights reserved." VALUE "OriginalFilename", "ExplorerPatcher.dll" VALUE "ProductName", "ExplorerPatcher" - VALUE "ProductVersion", "22000.282.32.7" + VALUE "ProductVersion", "22000.282.33.0" END END BLOCK "VarFileInfo" diff --git a/ExplorerPatcher/dllmain.c b/ExplorerPatcher/dllmain.c index a07e8e8..ba031ab 100644 --- a/ExplorerPatcher/dllmain.c +++ b/ExplorerPatcher/dllmain.c @@ -29,6 +29,7 @@ #define _LIBVALINET_DEBUG_HOOKING_IATPATCH #endif #include +#include #define EP_CLSID "{D17F1E1A-5919-4427-8F89-A1A8503CA3EB}" @@ -66,6 +67,7 @@ DWORD bClassicThemeMitigations = FALSE; DWORD bHookStartMenu = TRUE; DWORD bNoMenuAccelerator = FALSE; DWORD bTaskbarMonitorOverride = 0; +DWORD dwIMEStyle = 0; HMODULE hModule = NULL; HANDLE hSettingsMonitorThread = NULL; HANDLE hDelayedInjectionThread = NULL; @@ -2941,6 +2943,15 @@ void WINAPI LoadSettings(BOOL bIsExplorer) &bTaskbarMonitorOverride, &dwSize ); + dwSize = sizeof(DWORD); + RegQueryValueExW( + hKey, + TEXT("IMEStyle"), + 0, + NULL, + &dwIMEStyle, + &dwSize + ); RegCloseKey(hKey); } @@ -3613,6 +3624,7 @@ HRESULT explorer_DrawThemeTextEx( #pragma endregion +#pragma region "Change clock links" HINSTANCE explorer_ShellExecuteW( HWND hwnd, LPCWSTR lpOperation, @@ -3640,6 +3652,102 @@ HINSTANCE explorer_ShellExecuteW( } return ShellExecuteW(hwnd, lpOperation, lpFile, lpParameters, lpDirectory, nShowCmd); } +#pragma endregion + + +#pragma region "Change language UI style" +DEFINE_GUID(CLSID_InputSwitchControl, + 0xB9BC2A50, + 0x43C3, 0x41AA, 0xa0, 0x86, + 0x5D, 0xB1, 0x4e, 0x18, 0x4b, 0xae +); + +DEFINE_GUID(IID_InputSwitchControl, + 0xB9BC2A50, + 0x43C3, 0x41AA, 0xa0, 0x82, + 0x5D, 0xB1, 0x4e, 0x18, 0x4b, 0xae +); + +#define LANGUAGEUI_STYLE_DESKTOP 0 +#define LANGUAGEUI_STYLE_TOUCHKEYBOARD 1 +#define LANGUAGEUI_STYLE_LOGONUI 2 +#define LANGUAGEUI_STYLE_UAC 3 +#define LANGUAGEUI_STYLE_SETTINGSPANE 4 +#define LANGUAGEUI_STYLE_OOBE 5 +#define LANGUAGEUI_STYLE_OTHER 100 + +char mov_edx_val[6] = { 0xBA, 0x00, 0x00, 0x00, 0x00, 0xC3 }; +char* ep_pf = NULL; + +HRESULT explorer_CoCreateInstanceHook( + REFCLSID rclsid, + LPUNKNOWN pUnkOuter, + DWORD dwClsContext, + REFIID riid, + LPVOID* ppv +) +{ + if (IsEqualCLSID(rclsid, &CLSID_InputSwitchControl) && IsEqualIID(riid, &IID_InputSwitchControl)) + { + HRESULT hr = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv); + if (SUCCEEDED(hr)) + { + // Pff... how this works: + // + // * This `CoCreateInstance` call will get a pointer to an IInputSwitchControl interface + // (the call to here is made from `explorer!CTrayInputIndicator::_RegisterInputSwitch`); + // the next call on this pointer will be on the `IInputSwitchControl::Init` function. + // + // * `IInputSwitchControl::Init`'s second parameter is a number (x) which tells which + // language switcher UI to prepare (check `IsUtil::MapClientTypeToString` in + // `InputSwitch.dll`). "explorer" requests the "DESKTOP" UI (x = 0), which is the new + // Windows 11 UI; if we replace that number with something else, some other UI will + // be created + // + // * We cannot patch the vtable of the COM object because the executable is protected + // by control flow guard and we would make a jump to an invalid site (maybe there is + // some clever workaround fpr this as well, somehow telling the compiler to place a certain + // canary before our trampoline, so it matches with what the runtime support for CFG expects, + // but we'd have to keep that canary in sync with the one in explorer.exe, so not very + // future proof). + // + // * Taking advantage of the fact that the call to `IInputSwitchControl::Init` is the thing + // that happens right after we return from here, and looking on the disassembly, we see nothing + // else changes `rdx` (which is the second argument to a function call), basically x, besides the + // very `xor edx, edx` instruction before the call. Thus, we patch that out, and we also do + // `mov edx, whatever` here; afterwards, we do NOTHING else, but just return and hope that + // edx will stick + // + // * Needless to say this is **HIGHLY** amd64 + char pattern[2] = { 0x33, 0xD2 }; + DWORD dwOldProtect; + char* p_mov_edx_val = mov_edx_val; + if (!ep_pf) + { + ep_pf = memmem(_ReturnAddress(), 200, pattern, 2); + if (ep_pf) + { + // Cancel out `xor edx, edx` + VirtualProtect(ep_pf, 2, PAGE_EXECUTE_READWRITE, &dwOldProtect); + memset(ep_pf, 0x90, 2); + VirtualProtect(ep_pf, 2, dwOldProtect, &dwOldProtect); + } + VirtualProtect(p_mov_edx_val, 6, PAGE_EXECUTE_READWRITE, &dwOldProtect); + } + if (ep_pf) + { + // Craft a "function" which does `mov edx, whatever; ret` and call it + DWORD* pVal = mov_edx_val + 1; + *pVal = dwIMEStyle; + void(*pf_mov_edx_val)() = p_mov_edx_val; + pf_mov_edx_val(); + } + } + return hr; + } + return CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv); +} +#pragma endregion DWORD InjectBasicFunctions(BOOL bIsExplorer, BOOL bInstall) @@ -4161,6 +4269,10 @@ __declspec(dllexport) DWORD WINAPI main( VnPatchIAT(hExplorer, "user32.dll", "SetWindowCompositionAttribute", explorer_SetWindowCompositionAttribute); } //VnPatchDelayIAT(hExplorer, "ext-ms-win-rtcore-ntuser-window-ext-l1-1-0.dll", "CreateWindowExW", explorer_CreateWindowExW); + if (dwIMEStyle) + { + VnPatchIAT(hExplorer, "api-ms-win-core-com-l1-1-0.dll", "CoCreateInstance", explorer_CoCreateInstanceHook); + } #ifdef USE_PRIVATE_INTERFACES diff --git a/ExplorerPatcher/settings.reg b/ExplorerPatcher/settings.reg index ea525a5..c458586 100644 --- a/ExplorerPatcher/settings.reg +++ b/ExplorerPatcher/settings.reg @@ -75,6 +75,15 @@ ;x 1 Windows 7 "UseWin32TrayClockExperience"=dword:00000000 [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ExplorerPatcher] +;c 6 Language switcher flyout style * +;x 0 Windows 11 (default) +;x 1 Windows 10 +;x 2 "LOGONUI" +;x 3 "UAC" +;x 4 "SETTINGSPANE" +;x 5 "OOBE" +"IMEStyle"=dword:00000000 +[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ExplorerPatcher] ;a Choosing 'Open Network && Internet settings' when right clicking the ;c 3 network icon should open: ;x 0 Network section in the Settings app (default) diff --git a/libs/sws b/libs/sws index ce9c34c..a293c85 160000 --- a/libs/sws +++ b/libs/sws @@ -1 +1 @@ -Subproject commit ce9c34c82d01eca5c0f0ee63fc3ff18c83d38920 +Subproject commit a293c851987c5323438c48c1eb1731f092089c84