diff --git a/ExplorerPatcher/ExplorerPatcher.vcxproj b/ExplorerPatcher/ExplorerPatcher.vcxproj
index 0f3e999..ba2daba 100644
--- a/ExplorerPatcher/ExplorerPatcher.vcxproj
+++ b/ExplorerPatcher/ExplorerPatcher.vcxproj
@@ -266,6 +266,10 @@
true
true
+
+ true
+ true
+
true
@@ -334,6 +338,7 @@
+
diff --git a/ExplorerPatcher/InputSwitch.cpp b/ExplorerPatcher/InputSwitch.cpp
new file mode 100644
index 0000000..0bce70a
--- /dev/null
+++ b/ExplorerPatcher/InputSwitch.cpp
@@ -0,0 +1,198 @@
+#include "InputSwitch.h"
+
+#include
+#include
+#include
+
+#define TB_POS_NOWHERE 0
+#define TB_POS_BOTTOM 1
+#define TB_POS_TOP 2
+#define TB_POS_LEFT 3
+#define TB_POS_RIGHT 4
+extern "C" UINT GetTaskbarLocationAndSize(POINT ptCursor, RECT* rc);
+
+extern "C" __MIDL___MIDL_itf_inputswitchserver_0000_0000_0001 dwIMEStyle;
+extern "C" HRESULT CInputSwitchControl_ModifyAnchor(UINT dwNumberOfProfiles, RECT* lpRect);
+
+HRESULT CInputSwitchControl_ModifyAnchor(UINT dwNumberOfProfiles, RECT* lpRect)
+{
+ if (!dwIMEStyle) // impossible case (this is not called for the Windows 11 language switcher), but just in case
+ {
+ return S_FALSE;
+ }
+
+ HWND hWndTaskbar = FindWindowW(L"Shell_TrayWnd", NULL);
+
+ UINT dpiX = 96, dpiY = 96;
+ HRESULT hr = GetDpiForMonitor(
+ MonitorFromWindow(hWndTaskbar, MONITOR_DEFAULTTOPRIMARY),
+ MDT_DEFAULT,
+ &dpiX,
+ &dpiY
+ );
+ double dpix = dpiX / 96.0;
+ double dpiy = dpiY / 96.0;
+
+ //printf("RECT %d %d %d %d - %d %d\n", lpRect->left, lpRect->right, lpRect->top, lpRect->bottom, dwNumberOfProfiles, a3);
+
+ RECT rc;
+ GetWindowRect(hWndTaskbar, &rc);
+ POINT pt;
+ pt.x = rc.left;
+ pt.y = rc.top;
+ UINT tbPos = GetTaskbarLocationAndSize(pt, &rc);
+ if (tbPos == TB_POS_BOTTOM)
+ {
+ }
+ else if (tbPos == TB_POS_TOP)
+ {
+ if (dwIMEStyle == 1) // Windows 10 (with Language preferences link)
+ {
+ lpRect->top = rc.top + (rc.bottom - rc.top) + (UINT)(((double)dwNumberOfProfiles * (60.0 * dpiy)) + (5.0 * dpiy * 4.0) + (dpiy) + (48.0 * dpiy));
+ }
+ else if (dwIMEStyle == 2 || dwIMEStyle == 3 || dwIMEStyle == 4 || dwIMEStyle == 5) // LOGONUI, UAC, Windows 10, OOBE
+ {
+ lpRect->top = rc.top + (rc.bottom - rc.top) + (UINT)(((double)dwNumberOfProfiles * (60.0 * dpiy)) + (5.0 * dpiy * 2.0));
+ }
+ }
+ else if (tbPos == TB_POS_LEFT)
+ {
+ if (dwIMEStyle == 1 || dwIMEStyle == 2 || dwIMEStyle == 3 || dwIMEStyle == 4 || dwIMEStyle == 5)
+ {
+ lpRect->right = rc.left + (rc.right - rc.left) + (UINT)((double)(300.0 * dpix));
+ lpRect->top += (lpRect->bottom - lpRect->top);
+ }
+ }
+ if (tbPos == TB_POS_RIGHT)
+ {
+ if (dwIMEStyle == 1 || dwIMEStyle == 2 || dwIMEStyle == 3 || dwIMEStyle == 4 || dwIMEStyle == 5)
+ {
+ lpRect->right = lpRect->right - (rc.right - rc.left);
+ lpRect->top += (lpRect->bottom - lpRect->top);
+ }
+ }
+
+ if (dwIMEStyle == 4)
+ {
+ lpRect->right -= (UINT)((double)(300.0 * dpix)) - (lpRect->right - lpRect->left);
+ }
+
+ return S_OK;
+}
+
+class CInputSwitchControlProxy : public Microsoft::WRL::RuntimeClass, IInputSwitchControl>
+{
+public:
+ CInputSwitchControlProxy()
+ : m_type((__MIDL___MIDL_itf_inputswitchserver_0000_0000_0001)-1)
+ {
+ }
+
+ HRESULT RuntimeClassInitialize(IInputSwitchControl* original)
+ {
+ m_original = original;
+ return S_OK;
+ }
+
+ STDMETHODIMP Init(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0001 type) override
+ {
+ m_type = type;
+ return m_original->Init(type == ISCT_IDL_DESKTOP && dwIMEStyle != ISCT_IDL_DESKTOP ? dwIMEStyle : type);
+ }
+
+ STDMETHODIMP ShowInputSwitch(const RECT* rect) override
+ {
+ RECT myRect = *rect;
+ if (m_type == ISCT_IDL_DESKTOP)
+ {
+ UINT dwNumberOfProfiles = 0;
+ BOOL bImePresent = FALSE;
+ m_original->GetProfileCount(&dwNumberOfProfiles, &bImePresent);
+ CInputSwitchControl_ModifyAnchor(dwNumberOfProfiles, &myRect);
+ }
+ return m_original->ShowInputSwitch(&myRect);
+ }
+
+ STDMETHODIMP SetCallback(IInputSwitchCallback* callback) override { return m_original->SetCallback(callback); }
+ STDMETHODIMP GetProfileCount(UINT* count, BOOL* bOutImePresent) override { return m_original->GetProfileCount(count, bOutImePresent); }
+ STDMETHODIMP GetCurrentProfile(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0002* data) override { return m_original->GetCurrentProfile(data); }
+ STDMETHODIMP RegisterHotkeys() override { return m_original->RegisterHotkeys(); }
+ STDMETHODIMP ClickImeModeItem(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0004 type, POINT point, const RECT* rect) override { return m_original->ClickImeModeItem(type, point, rect); }
+ STDMETHODIMP ForceHide() override { return m_original->ForceHide(); }
+ STDMETHODIMP ShowTouchKeyboardInputSwitch(const RECT* rect, __MIDL___MIDL_itf_inputswitchserver_0000_0000_0006 align, int a3, DWORD a4, __MIDL___MIDL_itf_inputswitchserver_0000_0000_0005 a5) override { return m_original->ShowTouchKeyboardInputSwitch(rect, align, a3, a4, a5); }
+ STDMETHODIMP GetContextFlags(DWORD* flags) override { return m_original->GetContextFlags(flags); }
+ STDMETHODIMP SetContextOverrideMode(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0008 mode) override { return m_original->SetContextOverrideMode(mode); }
+ STDMETHODIMP GetCurrentImeModeItem(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0003* data) override { return m_original->GetCurrentImeModeItem(data); }
+ STDMETHODIMP ActivateInputProfile(const WCHAR* profile) override { return m_original->ActivateInputProfile(profile); }
+ STDMETHODIMP SetUserSid(const WCHAR* sid) override { return m_original->SetUserSid(sid); }
+
+private:
+ Microsoft::WRL::ComPtr m_original;
+ __MIDL___MIDL_itf_inputswitchserver_0000_0000_0001 m_type;
+};
+
+HRESULT CInputSwitchControlProxy_CreateInstance(IInputSwitchControl* original, REFIID riid, void** ppvObject)
+{
+ Microsoft::WRL::ComPtr proxy;
+ RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&proxy, original));
+ RETURN_HR(proxy.CopyTo(riid, ppvObject));
+}
+
+class CInputSwitchControlProxySV2 : public Microsoft::WRL::RuntimeClass, IInputSwitchControlSV2>
+{
+public:
+ CInputSwitchControlProxySV2()
+ : m_type((__MIDL___MIDL_itf_inputswitchserver_0000_0000_0001)-1)
+ {
+ }
+
+ HRESULT RuntimeClassInitialize(IInputSwitchControlSV2* original)
+ {
+ m_original = original;
+ return S_OK;
+ }
+
+ STDMETHODIMP Init(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0001 type) override
+ {
+ m_type = type;
+ return m_original->Init(type == ISCT_IDL_DESKTOP && dwIMEStyle != ISCT_IDL_DESKTOP ? dwIMEStyle : type);
+ }
+
+ STDMETHODIMP ShowInputSwitch(const RECT* rect) override
+ {
+ RECT myRect = *rect;
+ if (m_type == ISCT_IDL_DESKTOP)
+ {
+ UINT dwNumberOfProfiles = 0;
+ BOOL bImePresent = FALSE;
+ m_original->GetProfileCount(&dwNumberOfProfiles, &bImePresent);
+ CInputSwitchControl_ModifyAnchor(dwNumberOfProfiles, &myRect);
+ }
+ return m_original->ShowInputSwitch(&myRect);
+ }
+
+ STDMETHODIMP SetCallback(IInputSwitchCallback* callback) override { return m_original->SetCallback(callback); }
+ STDMETHODIMP GetProfileCount(UINT* count, BOOL* bOutImePresent) override { return m_original->GetProfileCount(count, bOutImePresent); }
+ STDMETHODIMP GetCurrentProfile(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0002* data) override { return m_original->GetCurrentProfile(data); }
+ STDMETHODIMP RegisterHotkeys() override { return m_original->RegisterHotkeys(); }
+ STDMETHODIMP ClickImeModeItem(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0004 type, POINT point, const RECT* rect) override { return m_original->ClickImeModeItem(type, point, rect); }
+ STDMETHODIMP ClickImeModeItemWithAnchor(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0004 type, IUnknown* anchor) override { return m_original->ClickImeModeItemWithAnchor(type, anchor); }
+ STDMETHODIMP ForceHide() override { return m_original->ForceHide(); }
+ STDMETHODIMP ShowTouchKeyboardInputSwitch(const RECT* rect, __MIDL___MIDL_itf_inputswitchserver_0000_0000_0006 align, int a3, DWORD a4, __MIDL___MIDL_itf_inputswitchserver_0000_0000_0005 a5) override { return m_original->ShowTouchKeyboardInputSwitch(rect, align, a3, a4, a5); }
+ STDMETHODIMP GetContextFlags(DWORD* flags) override { return m_original->GetContextFlags(flags); }
+ STDMETHODIMP SetContextOverrideMode(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0008 mode) override { return m_original->SetContextOverrideMode(mode); }
+ STDMETHODIMP GetCurrentImeModeItem(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0003* data) override { return m_original->GetCurrentImeModeItem(data); }
+ STDMETHODIMP ActivateInputProfile(const WCHAR* profile) override { return m_original->ActivateInputProfile(profile); }
+ STDMETHODIMP SetUserSid(const WCHAR* sid) override { return m_original->SetUserSid(sid); }
+
+private:
+ Microsoft::WRL::ComPtr m_original;
+ __MIDL___MIDL_itf_inputswitchserver_0000_0000_0001 m_type;
+};
+
+HRESULT CInputSwitchControlProxySV2_CreateInstance(IInputSwitchControlSV2* original, REFIID riid, void** ppvObject)
+{
+ Microsoft::WRL::ComPtr proxy;
+ RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&proxy, original));
+ RETURN_HR(proxy.CopyTo(riid, ppvObject));
+}
diff --git a/ExplorerPatcher/InputSwitch.h b/ExplorerPatcher/InputSwitch.h
new file mode 100644
index 0000000..daa1ef0
--- /dev/null
+++ b/ExplorerPatcher/InputSwitch.h
@@ -0,0 +1,122 @@
+#pragma once
+
+#include
+
+DEFINE_GUID(CLSID_InputSwitchControl, 0xb9bc2a50, 0x43c3, 0x41aa, 0xa0, 0x86, 0x5d, 0xb1, 0x4e, 0x18, 0x4b, 0xae);
+DEFINE_GUID(IID_IInputSwitchControl, 0xb9bc2a50, 0x43c3, 0x41aa, 0xa0, 0x82, 0x5d, 0xb1, 0x4e, 0x18, 0x4b, 0xae);
+
+enum __MIDL___MIDL_itf_inputswitchserver_0000_0000_0001
+{
+ ISCT_IDL_DESKTOP,
+ ISCT_IDL_TOUCHKEYBOARD,
+ ISCT_IDL_LOGONUI,
+ ISCT_IDL_UAC,
+ ISCT_IDL_SETTINGSPANE,
+ ISCT_IDL_OOBE,
+ ISCT_IDL_USEROOBE
+};
+
+struct __MIDL___MIDL_itf_inputswitchserver_0000_0000_0002
+{
+ int dummy; // We don't need its contents
+};
+
+struct __MIDL___MIDL_itf_inputswitchserver_0000_0000_0003
+{
+ WCHAR* pszTooltip;
+ HICON hIcon;
+ BOOL fDisabled;
+ BOOL fHidden;
+ WCHAR* pszIconGlyph;
+};
+
+enum __MIDL___MIDL_itf_inputswitchserver_0000_0000_0004
+{
+ INPUT_SWITCH_IDL_IME_CLICK_TYPE_LEFT,
+ INPUT_SWITCH_IDL_IME_CLICK_TYPE_RIGHT,
+ INPUT_SWITCH_IDL_IME_CLICK_TYPE_LEFT_DISABLED
+};
+
+enum __MIDL___MIDL_itf_inputswitchserver_0000_0000_0005
+{
+ INPUT_SWITCH_IDL_MODALITY_STANDARDKEYBOARD = 0x1,
+ INPUT_SWITCH_IDL_MODALITY_SPLITKEYBOARD = 0x2,
+ INPUT_SWITCH_IDL_MODALITY_CLASSICKEYBOARD = 0x4,
+ INPUT_SWITCH_IDL_MODALITY_HANDWRITING = 0x8,
+ INPUT_SWITCH_IDL_MODALITY_HIDE = 0x10,
+ INPUT_SWITCH_IDL_MODALITY_ONEHANDEDKEYBOARD = 0x20,
+};
+
+enum __MIDL___MIDL_itf_inputswitchserver_0000_0000_0006
+{
+ INPUT_SWITCH_IDL_ALIGN_DEFAULT,
+ INPUT_SWITCH_IDL_ALIGN_RIGHT_EDGE,
+ INPUT_SWITCH_IDL_ALIGN_LEFT_EDGE,
+};
+
+enum __MIDL___MIDL_itf_inputswitchserver_0000_0000_0008
+{
+ INPUT_SWITCH_IDL_CFOM_NO_OVERRIDE,
+ INPUT_SWITCH_IDL_CFOM_DESKTOP,
+ INPUT_SWITCH_IDL_CFOM_IMMERSIVE,
+};
+
+interface IInputSwitchCallback;
+
+#ifdef __cplusplus
+MIDL_INTERFACE("b9bc2a50-43c3-41aa-a082-5db14e184bae")
+IInputSwitchControl : IUnknown
+{
+ virtual HRESULT STDMETHODCALLTYPE Init(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0001) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetCallback(IInputSwitchCallback*) = 0;
+ virtual HRESULT STDMETHODCALLTYPE ShowInputSwitch(const RECT*) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetProfileCount(UINT*, BOOL*) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentProfile(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0002*) = 0;
+ virtual HRESULT STDMETHODCALLTYPE RegisterHotkeys() = 0;
+ virtual HRESULT STDMETHODCALLTYPE ClickImeModeItem(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0004, POINT, const RECT*) = 0;
+ virtual HRESULT STDMETHODCALLTYPE ForceHide() = 0;
+ virtual HRESULT STDMETHODCALLTYPE ShowTouchKeyboardInputSwitch(const RECT*, __MIDL___MIDL_itf_inputswitchserver_0000_0000_0006, int, DWORD, __MIDL___MIDL_itf_inputswitchserver_0000_0000_0005) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetContextFlags(DWORD*) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetContextOverrideMode(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0008) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentImeModeItem(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0003*) = 0;
+ virtual HRESULT STDMETHODCALLTYPE ActivateInputProfile(const WCHAR*) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetUserSid(const WCHAR*) = 0;
+};
+#else
+typedef interface IInputSwitchControl IInputSwitchControl;
+#endif
+
+#ifdef __cplusplus
+MIDL_INTERFACE("b9bc2a50-43c3-41aa-a082-5db14e184bae")
+IInputSwitchControlSV2 : IUnknown
+{
+ virtual HRESULT STDMETHODCALLTYPE Init(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0001) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetCallback(IInputSwitchCallback*) = 0;
+ virtual HRESULT STDMETHODCALLTYPE ShowInputSwitch(const RECT*) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetProfileCount(UINT*, BOOL*) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentProfile(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0002*) = 0;
+ virtual HRESULT STDMETHODCALLTYPE RegisterHotkeys() = 0;
+ virtual HRESULT STDMETHODCALLTYPE ClickImeModeItem(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0004, POINT, const RECT*) = 0;
+ virtual HRESULT STDMETHODCALLTYPE ClickImeModeItemWithAnchor(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0004, IUnknown*) = 0;
+ virtual HRESULT STDMETHODCALLTYPE ForceHide() = 0;
+ virtual HRESULT STDMETHODCALLTYPE ShowTouchKeyboardInputSwitch(const RECT*, __MIDL___MIDL_itf_inputswitchserver_0000_0000_0006, int, DWORD, __MIDL___MIDL_itf_inputswitchserver_0000_0000_0005) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetContextFlags(DWORD*) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetContextOverrideMode(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0008) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentImeModeItem(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0003*) = 0;
+ virtual HRESULT STDMETHODCALLTYPE ActivateInputProfile(const WCHAR*) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetUserSid(const WCHAR*) = 0;
+};
+#else
+typedef interface IInputSwitchControlSV2 IInputSwitchControlSV2;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+HRESULT CInputSwitchControlProxy_CreateInstance(IInputSwitchControl* original, REFIID riid, void** ppvObject);
+HRESULT CInputSwitchControlProxySV2_CreateInstance(IInputSwitchControlSV2* original, REFIID riid, void** ppvObject);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/ExplorerPatcher/dllmain.c b/ExplorerPatcher/dllmain.c
index 1934100..f620431 100644
--- a/ExplorerPatcher/dllmain.c
+++ b/ExplorerPatcher/dllmain.c
@@ -205,6 +205,7 @@ BOOL g_bIsDesktopRaised = FALSE;
#include "symbols.h"
#include "dxgi_imp.h"
#include "ArchiveMenu.h"
+#include "InputSwitch.h"
#include "StartupSound.h"
#include "StartMenu.h"
#include "TaskbarCenter.h"
@@ -8807,197 +8808,32 @@ HRESULT ExplorerFrame_CoCreateInstanceHook(REFCLSID rclsid, LPUNKNOWN pUnkOuter,
#pragma region "Change language UI style + Enable old taskbar"
#ifdef _WIN64
-DEFINE_GUID(CLSID_InputSwitchControl,
- 0xB9BC2A50,
- 0x43C3, 0x41AA, 0xa0, 0x86,
- 0x5D, 0xB1, 0x4e, 0x18, 0x4b, 0xae
-);
-
-DEFINE_GUID(IID_IInputSwitchControl,
- 0xB9BC2A50,
- 0x43C3, 0x41AA, 0xa0, 0x82,
- 0x5D, 0xB1, 0x4e, 0x18, 0x4b, 0xae
-);
-
-#define LANGUAGEUI_STYLE_DESKTOP 0 // Windows 11 style
-#define LANGUAGEUI_STYLE_TOUCHKEYBOARD 1 // Windows 10 style
-#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;
-
-typedef interface IInputSwitchControl IInputSwitchControl;
-
-typedef struct IInputSwitchControlVtbl
-{
- BEGIN_INTERFACE
-
- HRESULT(STDMETHODCALLTYPE* QueryInterface)(
- IInputSwitchControl* This,
- /* [in] */ REFIID riid,
- /* [annotation][iid_is][out] */
- _COM_Outptr_ void** ppvObject);
-
- ULONG(STDMETHODCALLTYPE* AddRef)(
- IInputSwitchControl* This);
-
- ULONG(STDMETHODCALLTYPE* Release)(
- IInputSwitchControl* This);
-
- HRESULT(STDMETHODCALLTYPE* Init)(
- IInputSwitchControl* This,
- /* [in] */ unsigned int clientType);
-
- HRESULT(STDMETHODCALLTYPE* SetCallback)(
- IInputSwitchControl* This,
- /* [in] */ void* pInputSwitchCallback);
-
- HRESULT(STDMETHODCALLTYPE* ShowInputSwitch)(
- IInputSwitchControl* This,
- /* [in] */ RECT* lpRect);
-
- HRESULT(STDMETHODCALLTYPE* GetProfileCount)(
- IInputSwitchControl* This,
- /* [in] */ unsigned int* pOutNumberOfProfiles,
- /* [in] */ int* a3);
-
- // ...
-
- END_INTERFACE
-} IInputSwitchControlVtbl;
-
-interface IInputSwitchControl
-{
- CONST_VTBL struct IInputSwitchControlVtbl* lpVtbl;
-};
-
-IInputSwitchControl* g_pDesktopInputSwitchControl;
-
-HRESULT(*CInputSwitchControl_InitFunc)(IInputSwitchControl*, unsigned int);
-HRESULT CInputSwitchControl_InitHook(IInputSwitchControl* _this, unsigned int dwOriginalIMEStyle)
-{
- // Note: Other than in explorer.exe!CTrayInputIndicator::_RegisterInputSwitch, we're also called by
- // explorer.exe!HostAppEnvironment::_SetupInputSwitchServer which passes ISCT_IDL_USEROOBE (6) as the style.
- if (dwOriginalIMEStyle == 0) // ISCT_IDL_DESKTOP
- {
- g_pDesktopInputSwitchControl = _this;
- }
- return CInputSwitchControl_InitFunc(_this, dwOriginalIMEStyle == 0 && dwIMEStyle ? dwIMEStyle : dwOriginalIMEStyle);
-}
-
-HRESULT (*CInputSwitchControl_ShowInputSwitchFunc)(IInputSwitchControl*, RECT*);
-HRESULT CInputSwitchControl_ShowInputSwitchHook(IInputSwitchControl* _this, RECT* lpRect)
-{
- if (_this != g_pDesktopInputSwitchControl || !dwIMEStyle) // impossible case (this is not called for the Windows 11 language switcher), but just in case
- {
- return CInputSwitchControl_ShowInputSwitchFunc(_this, lpRect);
- }
-
- unsigned int dwNumberOfProfiles = 0;
- int a3 = 0;
- _this->lpVtbl->GetProfileCount(_this, &dwNumberOfProfiles, &a3);
-
- HWND hWndTaskbar = FindWindowW(L"Shell_TrayWnd", NULL);
-
- UINT dpiX = 96, dpiY = 96;
- HRESULT hr = GetDpiForMonitor(
- MonitorFromWindow(hWndTaskbar, MONITOR_DEFAULTTOPRIMARY),
- MDT_DEFAULT,
- &dpiX,
- &dpiY
- );
- double dpix = dpiX / 96.0;
- double dpiy = dpiY / 96.0;
-
- //printf("RECT %d %d %d %d - %d %d\n", lpRect->left, lpRect->right, lpRect->top, lpRect->bottom, dwNumberOfProfiles, a3);
-
- RECT rc;
- GetWindowRect(hWndTaskbar, &rc);
- POINT pt;
- pt.x = rc.left;
- pt.y = rc.top;
- UINT tbPos = GetTaskbarLocationAndSize(pt, &rc);
- if (tbPos == TB_POS_BOTTOM)
- {
- }
- else if (tbPos == TB_POS_TOP)
- {
- if (dwIMEStyle == 1) // Windows 10 (with Language preferences link)
- {
- lpRect->top = rc.top + (rc.bottom - rc.top) + (UINT)(((double)dwNumberOfProfiles * (60.0 * dpiy)) + (5.0 * dpiy * 4.0) + (dpiy) + (48.0 * dpiy));
- }
- else if (dwIMEStyle == 2 || dwIMEStyle == 3 || dwIMEStyle == 4 || dwIMEStyle == 5) // LOGONUI, UAC, Windows 10, OOBE
- {
- lpRect->top = rc.top + (rc.bottom - rc.top) + (UINT)(((double)dwNumberOfProfiles * (60.0 * dpiy)) + (5.0 * dpiy * 2.0));
- }
- }
- else if (tbPos == TB_POS_LEFT)
- {
- if (dwIMEStyle == 1 || dwIMEStyle == 2 || dwIMEStyle == 3 || dwIMEStyle == 4 || dwIMEStyle == 5)
- {
- lpRect->right = rc.left + (rc.right - rc.left) + (UINT)((double)(300.0 * dpix));
- lpRect->top += (lpRect->bottom - lpRect->top);
- }
- }
- if (tbPos == TB_POS_RIGHT)
- {
- if (dwIMEStyle == 1 || dwIMEStyle == 2 || dwIMEStyle == 3 || dwIMEStyle == 4 || dwIMEStyle == 5)
- {
- lpRect->right = lpRect->right - (rc.right - rc.left);
- lpRect->top += (lpRect->bottom - lpRect->top);
- }
- }
-
- if (dwIMEStyle == 4)
- {
- lpRect->right -= (UINT)((double)(300.0 * dpix)) - (lpRect->right - lpRect->left);
- }
-
- return CInputSwitchControl_ShowInputSwitchFunc(_this, lpRect);
-}
-
DEFINE_GUID(CLSID_TrayUIComponent,
0x88FC85D3,
0x7090, 0x4F53, 0x8F, 0x7A,
0xEB, 0x02, 0x68, 0x16, 0x27, 0x88
);
-HRESULT explorer_CoCreateInstanceHook(
- REFCLSID rclsid,
- LPUNKNOWN pUnkOuter,
- DWORD dwClsContext,
- REFIID riid,
- IUnknown** ppv
-)
+HRESULT EPTrayUIComponent_CreateInstance(REFIID riid, void** ppvObject);
+
+__declspec(dllexport) HRESULT explorer_CoCreateInstanceHook(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, void** ppv)
{
if (IsEqualCLSID(rclsid, &CLSID_InputSwitchControl) && IsEqualIID(riid, &IID_IInputSwitchControl))
{
HRESULT hr = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv);
if (SUCCEEDED(hr) && bOldTaskbar && dwIMEStyle)
{
- // The commented method below is no longer required as I have now came to patching
- // the interface's vtable.
- // Also, make sure to read the explanation below as well, it's useful for understanding
- // how this worked.
- IInputSwitchControl* pInputSwitchControl = *ppv;
- DWORD flOldProtect = 0;
- if (VirtualProtect(pInputSwitchControl->lpVtbl, sizeof(IInputSwitchControlVtbl), PAGE_EXECUTE_READWRITE, &flOldProtect))
+ // The commented method below is no longer required as I have now came to creating a wrapper class.
+ // Also, make sure to read the explanation below as well, it's useful for understanding how this worked.
+ // Note: Other than in explorer.exe!CTrayInputIndicator::_RegisterInputSwitch, we're also called by
+ // explorer.exe!HostAppEnvironment::_SetupInputSwitchServer which passes ISCT_IDL_USEROOBE (6) as the style.
+ if (IsWindows11Version22H2OrHigher())
{
- if (pInputSwitchControl->lpVtbl->ShowInputSwitch != CInputSwitchControl_ShowInputSwitchHook)
- {
- CInputSwitchControl_ShowInputSwitchFunc = pInputSwitchControl->lpVtbl->ShowInputSwitch;
- pInputSwitchControl->lpVtbl->ShowInputSwitch = CInputSwitchControl_ShowInputSwitchHook;
- }
- if (pInputSwitchControl->lpVtbl->Init != CInputSwitchControl_InitHook)
- {
- CInputSwitchControl_InitFunc = pInputSwitchControl->lpVtbl->Init;
- pInputSwitchControl->lpVtbl->Init = CInputSwitchControl_InitHook;
- }
- VirtualProtect(pInputSwitchControl->lpVtbl, sizeof(IInputSwitchControlVtbl), flOldProtect, &flOldProtect);
+ hr = CInputSwitchControlProxySV2_CreateInstance(*ppv, riid, ppv);
+ }
+ else
+ {
+ hr = CInputSwitchControlProxy_CreateInstance(*ppv, riid, ppv);
}
// Pff... how this works:
//