diff --git a/ExplorerPatcher/TaskbarCenter.c b/ExplorerPatcher/TaskbarCenter.c index c8b369a..62e01ca 100644 --- a/ExplorerPatcher/TaskbarCenter.c +++ b/ExplorerPatcher/TaskbarCenter.c @@ -1,62 +1,247 @@ #include "TaskbarCenter.h" -HANDLE hEvent; +extern DWORD dwOldTaskbarAl; +extern DWORD dwMMOldTaskbarAl; +extern wchar_t* EP_TASKBAR_LENGTH_PROP_NAME; +#define EP_TASKBAR_LENGTH_TOO_SMALL 20 -HRESULT TaskbarCenter_Center() +inline BOOL TaskbarCenter_IsTaskbarHorizontal(HWND hWnd) +{ + __int64 v1; + __int64 result; + v1 = *((__int64*)GetWindowLongPtrW(hWnd, 0) + 13); + result = 1i64; + if (v1) + return (*(__int64(__fastcall**)(__int64))(*(__int64*)v1 + 96))(v1); + return result; +} + +inline BOOL TaskbarCenter_ShouldCenter(DWORD dwSetting) +{ + return (dwSetting & 0b001); +} + +inline BOOL TaskbarCenter_ShouldStartBeCentered(DWORD dwSetting) +{ + return (dwSetting & 0b010); +} + +inline BOOL TaskbarCenter_ShouldLeftAlignWhenSpaceConstrained(DWORD dwSetting) +{ + return (dwSetting & 0b100); +} + +HRESULT TaskbarCenter_Center(HWND hWnd, RECT rc, BOOL bIsTaskbarHorizontal) { HRESULT hr = S_OK; - HWND hWnd = FindWindowExW(NULL, NULL, L"Shell_TrayWnd", NULL); + VARIANT vtChild[10]; + VARIANT vt; + long k = 0, kk = 0; - while (hWnd) + IAccessible* pAccessible = NULL; + AccessibleObjectFromWindow(hWnd, 0, &IID_IAccessible, &pAccessible); + if (pAccessible) { - if (SUCCEEDED(hr)) + pAccessible->lpVtbl->get_accChildCount(pAccessible, &kk); + if (kk <= 10) { - /*hr = AccessibleObjectFromWindow( - - );*/ + AccessibleChildren(pAccessible, 0, kk, vtChild, &k); + for (int i = 0; i < k; ++i) + { + if (vtChild[i].vt == VT_DISPATCH) + { + IDispatch* pDisp = vtChild[i].ppdispVal; + IAccessible* pChild = NULL; + pDisp->lpVtbl->QueryInterface(pDisp, &IID_IAccessible, &pChild); + if (pChild) + { + vt.vt = VT_I4; + vt.lVal = CHILDID_SELF; + pChild->lpVtbl->get_accRole(pChild, vt, &vt); + if (vt.lVal == ROLE_SYSTEM_TOOLBAR) + { + IAccessible* pLast = NULL; + kk = 0; + pChild->lpVtbl->get_accChildCount(pChild, &kk); + if (kk <= 1) + { + SetPropW(hWnd, EP_TASKBAR_LENGTH_PROP_NAME, -1); + } + else if (kk >= 2) + { + vt.vt = VT_I4; + vt.lVal = kk - 1; + long x = 0, y = 0, w = 0, h = 0, d = 0; + pChild->lpVtbl->accLocation(pChild, &x, &y, &w, &h, vt); + if (bIsTaskbarHorizontal ? (x == -1 || w < EP_TASKBAR_LENGTH_TOO_SMALL) : (y == -1 || h < EP_TASKBAR_LENGTH_TOO_SMALL)) + { + hr = E_FAIL; + } + else + { + if (kk >= 3) + { + d = (bIsTaskbarHorizontal ? ((x - rc.left) + w) : ((y - rc.top) + h)); + vt.vt = VT_I4; + vt.lVal = 1; + x = 0, y = 0, w = 0, h = 0; + pChild->lpVtbl->accLocation(pChild, &x, &y, &w, &h, vt); + if (bIsTaskbarHorizontal ? w == 0 : h == 0) + { + vt.vt = VT_I4; + vt.lVal = 2; + x = 0, y = 0, w = 0, h = 0; + pChild->lpVtbl->accLocation(pChild, &x, &y, &w, &h, vt); + } + if (bIsTaskbarHorizontal ? (x == -1 || w < EP_TASKBAR_LENGTH_TOO_SMALL) : (y == -1 || h < EP_TASKBAR_LENGTH_TOO_SMALL)) + { + hr == E_FAIL; + } + else + { + SetPropW(hWnd, EP_TASKBAR_LENGTH_PROP_NAME, (bIsTaskbarHorizontal ? (d - (x - rc.left)) : (d - (y - rc.top)))); + } + } + else + { + SetPropW(hWnd, EP_TASKBAR_LENGTH_PROP_NAME, bIsTaskbarHorizontal ? w : h); + } + } + } + } + pChild->lpVtbl->Release(pChild); + } + pDisp->lpVtbl->Release(pDisp); + } + } } - - hWnd = NULL; + pAccessible->lpVtbl->Release(pAccessible); } - + return hr; } -BOOL TaskbarCenter_Notify() +BOOL TaskbarCenter_GetClientRectHook(HWND hWnd, LPRECT lpRect) { - if (hEvent) + BOOL bWasCalled = FALSE; + HWND hWndStart = NULL; + RECT rcStart; + SetRect(&rcStart, 0, 0, 0, 0); + if (GetClassWord(hWnd, GCW_ATOM) == RegisterWindowMessageW(L"MSTaskListWClass")) { - SetEvent(hEvent); - return TRUE; - } - return FALSE; -} - -BOOL GetClientRectHook(HWND hWnd, LPRECT lpRect) -{ - wchar_t wszClassName[100]; - ZeroMemory(wszClassName, 100); - GetClassNameW(hWnd, wszClassName, 100); - if (!wcscmp(wszClassName, L"MSTaskListWClass")) - { - TaskbarCenter_Center(); + BOOL bIsPrimaryTaskbar = GetClassWord(GetParent(hWnd), GCW_ATOM) == RegisterWindowMessageW(L"MSTaskSwWClass"); + DWORD dwSetting = (bIsPrimaryTaskbar ? dwOldTaskbarAl : dwMMOldTaskbarAl); + HWND hWndTaskbar = NULL; + if (bIsPrimaryTaskbar) + { + hWndTaskbar = GetParent(GetParent(GetParent(hWnd))); + } + else + { + hWndTaskbar = GetParent(GetParent(hWnd)); + } + hWndStart = FindWindowExW(hWndTaskbar, NULL, L"Start", NULL); + BOOL bIsTaskbarHorizontal = TaskbarCenter_IsTaskbarHorizontal(hWnd); + if (TaskbarCenter_ShouldCenter(dwSetting)) + { + if (TaskbarCenter_ShouldStartBeCentered(dwSetting) && hWndStart) + { + GetClientRect(hWndStart, &rcStart); + } + RECT rc; + GetWindowRect(hWnd, &rc); + MONITORINFO mi; + ZeroMemory(&mi, sizeof(MONITORINFO)); + mi.cbSize = sizeof(MONITORINFO); + GetMonitorInfoW(MonitorFromWindow(hWnd, MONITOR_DEFAULTTOPRIMARY), &mi); + DWORD dwLength = 0; + TaskbarCenter_Center(hWnd, mi.rcMonitor, bIsTaskbarHorizontal); + if (dwLength = GetPropW(hWnd, EP_TASKBAR_LENGTH_PROP_NAME)) + { + if (dwLength == -1) + { + if (TaskbarCenter_ShouldStartBeCentered(dwSetting) && hWndStart) + { + if (bIsTaskbarHorizontal) + { + SetWindowPos(hWndStart, NULL, ((mi.rcMonitor.right - mi.rcMonitor.left) - (rcStart.right - rcStart.left)) / 2, rcStart.top, 0, 0, SWP_NOSIZE | SWP_FRAMECHANGED | SWP_ASYNCWINDOWPOS); + } + else + { + SetWindowPos(hWndStart, NULL, rcStart.left, ((mi.rcMonitor.bottom - mi.rcMonitor.top) - (rcStart.bottom - rcStart.top)) / 2, 0, 0, SWP_NOSIZE | SWP_FRAMECHANGED | SWP_ASYNCWINDOWPOS); + } + if (!bIsPrimaryTaskbar) InvalidateRect(hWndStart, NULL, TRUE); + } + } + else + { + if (TaskbarCenter_ShouldStartBeCentered(dwSetting) && hWndStart) + { + dwLength += (bIsTaskbarHorizontal ? (rcStart.right - rcStart.left) : (rcStart.bottom - rcStart.top)); + } + bWasCalled = GetClientRect(hWnd, lpRect); + long res = 0; + if (bIsTaskbarHorizontal) + { + res = ((mi.rcMonitor.right - mi.rcMonitor.left) - dwLength) / 2 - (!TaskbarCenter_ShouldStartBeCentered(dwSetting) ? (rc.left - mi.rcMonitor.left) : 0); + } + else + { + res = ((mi.rcMonitor.bottom - mi.rcMonitor.top) - dwLength) / 2 - (!TaskbarCenter_ShouldStartBeCentered(dwSetting) ? (rc.top - mi.rcMonitor.top) : 0); + } + if (res + dwLength + 5 - (TaskbarCenter_ShouldStartBeCentered(dwSetting) ? (bIsTaskbarHorizontal ? (rc.left - mi.rcMonitor.left) : (rc.top - mi.rcMonitor.top)) : 0) < (bIsTaskbarHorizontal ? lpRect->right : lpRect->bottom)) + { + if (bIsTaskbarHorizontal) + { + lpRect->left = res; + } + else + { + lpRect->top = res; + } + if (TaskbarCenter_ShouldLeftAlignWhenSpaceConstrained(dwSetting) || !bIsTaskbarHorizontal) + { + if (bIsTaskbarHorizontal) + { + lpRect->right = (TaskbarCenter_ShouldStartBeCentered(dwSetting) ? (rc.left - mi.rcMonitor.left) : 0) + 10 + lpRect->right; + } + else + { + lpRect->bottom = (TaskbarCenter_ShouldStartBeCentered(dwSetting) ? (rc.top - mi.rcMonitor.top) : 0) + 10 + lpRect->bottom; + } + } + } + if (TaskbarCenter_ShouldStartBeCentered(dwSetting) && hWndStart) + { + if (bIsTaskbarHorizontal) + { + SetWindowPos(hWndStart, NULL, (rc.left - mi.rcMonitor.left) + lpRect->left - (rcStart.right - rcStart.left), rcStart.top, 0, 0, SWP_NOSIZE | SWP_FRAMECHANGED | SWP_ASYNCWINDOWPOS); + } + else + { + SetWindowPos(hWndStart, NULL, rcStart.left, (rc.top - mi.rcMonitor.top) + lpRect->top - (rcStart.bottom - rcStart.top), 0, 0, SWP_NOSIZE | SWP_FRAMECHANGED | SWP_ASYNCWINDOWPOS); + } + if (!bIsPrimaryTaskbar) InvalidateRect(hWndStart, NULL, TRUE); + } + } + } + } + else + { + if (GetPropW(hWnd, EP_TASKBAR_LENGTH_PROP_NAME)) + { + RemovePropW(hWnd, EP_TASKBAR_LENGTH_PROP_NAME); + } + } + if ((!TaskbarCenter_ShouldCenter(dwSetting) || !TaskbarCenter_ShouldStartBeCentered(dwSetting)) && hWndStart) + { + GetWindowRect(hWndStart, &rcStart); + if (rcStart.left != 0 || rcStart.top != 0) + { + SetWindowPos(hWndStart, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_FRAMECHANGED | SWP_ASYNCWINDOWPOS); + if (!bIsPrimaryTaskbar) InvalidateRect(hWndStart, NULL, TRUE); + } + } } + if (bWasCalled) return bWasCalled; return GetClientRect(hWnd, lpRect); -} - -HRESULT TaskbarCenter_Initialize(HMODULE hExplorer) -{ - if (!(hEvent = CreateEventW(NULL, TRUE, FALSE, TASKBAR_CHANGED_NOTIFICATION))) - { - return E_NOTIMPL; - } - if (FindWindowExW(NULL, NULL, L"Shell_TrayWnd", NULL)) - { - return E_NOTIMPL; - } - // This is one of the methods called by explorer!CTaskListWnd::_RecomputeLayout - if (!VnPatchDelayIAT(hExplorer, "ext-ms-win-rtcore-ntuser-window-ext-l1-1-0.dll", "GetClientRect", GetClientRectHook)) - { - return E_NOTIMPL; - } - return S_OK; } \ No newline at end of file diff --git a/ExplorerPatcher/TaskbarCenter.h b/ExplorerPatcher/TaskbarCenter.h index 36060f8..102cdb2 100644 --- a/ExplorerPatcher/TaskbarCenter.h +++ b/ExplorerPatcher/TaskbarCenter.h @@ -3,10 +3,9 @@ #include #include #include +#include #pragma comment(lib, "Oleacc.lib") #include -#define TASKBAR_CHANGED_NOTIFICATION L"Global\\ExplorerPatcher_TaskbarChangedNotification_{B37553B7-425C-44F6-A04A-126849EE59CB}" - -HRESULT TaskbarCenter_Initialize(HMODULE); +BOOL TaskbarCenter_GetClientRectHook(HWND hWnd, LPRECT lpRect); #endif \ No newline at end of file diff --git a/ExplorerPatcher/dllmain.c b/ExplorerPatcher/dllmain.c index c288087..f49e572 100644 --- a/ExplorerPatcher/dllmain.c +++ b/ExplorerPatcher/dllmain.c @@ -125,6 +125,8 @@ DWORD bWasPinnedItemsActAsQuickLaunch = FALSE; DWORD bPinnedItemsActAsQuickLaunch = FALSE; DWORD bWasRemoveExtraGapAroundPinnedItems = FALSE; DWORD bRemoveExtraGapAroundPinnedItems = FALSE; +DWORD dwOldTaskbarAl = 0b110; +DWORD dwMMOldTaskbarAl = 0b110; int Code = 0; HRESULT InjectStartFromExplorer(); void InvokeClockFlyout(); @@ -179,6 +181,7 @@ DWORD S_Icon_Dark_Widgets = 0; #include "ImmersiveFlyouts.h" #include "updates.h" DWORD dwUpdatePolicy = UPDATE_POLICY_DEFAULT; +wchar_t* EP_TASKBAR_LENGTH_PROP_NAME = _T("ExplorerPatcher_") _T(EP_CLSID) _T("_Length"); HRESULT WINAPI _DllRegisterServer(); HRESULT WINAPI _DllUnregisterServer(); @@ -744,6 +747,19 @@ LRESULT CALLBACK EP_Service_Window_WndProc( InvokeClockFlyout(); return 0; } + else if (uMsg == WM_TIMER && wParam == 1) + { + SendNotifyMessageW(HWND_BROADCAST, WM_WININICHANGE, 0, (LPARAM)L"ConvertibleSlateMode"); + SetTimer(hWnd, 2, 1000, NULL); + KillTimer(hWnd, 1); + return 0; + } + else if (uMsg == WM_TIMER && wParam == 2) + { + SendNotifyMessageW(HWND_BROADCAST, WM_WININICHANGE, 0, (LPARAM)L"ConvertibleSlateMode"); + KillTimer(hWnd, 2); + return 0; + } return DefWindowProcW(hWnd, uMsg, wParam, lParam); } @@ -779,6 +795,10 @@ DWORD EP_ServiceWindowThread(DWORD unused) RegisterHotKey(hWnd, 1, MOD_WIN | MOD_NOREPEAT, 'C'); } RegisterHotKey(hWnd, 2, MOD_WIN | MOD_ALT, 'D'); + if (bOldTaskbar && (dwOldTaskbarAl || dwMMOldTaskbarAl)) + { + SetTimer(hWnd, 1, 5000, NULL); + } MSG msg; BOOL bRet; while ((bRet = GetMessageW(&msg, NULL, 0, 0)) != 0) @@ -5274,11 +5294,12 @@ DWORD WindowSwitcher(DWORD unused) #pragma region "Load Settings from registry" -#define REFRESHUI_NONE 0b0000 -#define REFRESHUI_GLOM 0b0001 -#define REFRESHUI_ORB 0b0010 -#define REFRESHUI_PEOPLE 0b0100 -#define REFRESHUI_TASKBAR 0b1000 +#define REFRESHUI_NONE 0b00000 +#define REFRESHUI_GLOM 0b00001 +#define REFRESHUI_ORB 0b00010 +#define REFRESHUI_PEOPLE 0b00100 +#define REFRESHUI_TASKBAR 0b01000 +#define REFRESHUI_CENTER 0b10000 void WINAPI LoadSettings(LPARAM lParam) { BOOL bIsExplorer = LOWORD(lParam); @@ -5471,6 +5492,36 @@ void WINAPI LoadSettings(LPARAM lParam) ); } dwSize = sizeof(DWORD); + dwTemp = 0; + RegQueryValueExW( + hKey, + TEXT("OldTaskbarAl"), + 0, + NULL, + &dwTemp, + &dwSize + ); + if (dwTemp != dwOldTaskbarAl) + { + dwOldTaskbarAl = dwTemp; + dwRefreshUIMask |= REFRESHUI_CENTER; + } + dwSize = sizeof(DWORD); + dwTemp = 0; + RegQueryValueExW( + hKey, + TEXT("MMOldTaskbarAl"), + 0, + NULL, + &dwTemp, + &dwSize + ); + if (dwTemp != dwMMOldTaskbarAl) + { + dwMMOldTaskbarAl = dwTemp; + dwRefreshUIMask |= REFRESHUI_CENTER; + } + dwSize = sizeof(DWORD); RegQueryValueExW( hKey, TEXT("HideExplorerSearchBar"), @@ -6096,6 +6147,10 @@ void WINAPI LoadSettings(LPARAM lParam) if (bOldTaskbar && (dwTemp != dwTaskbarGlomLevel)) { dwRefreshUIMask = REFRESHUI_GLOM; + if (dwOldTaskbarAl) + { + dwRefreshUIMask = REFRESHUI_CENTER; + } } dwTaskbarGlomLevel = dwTemp; dwTemp = MMTASKBARGLOMLEVEL_DEFAULT; @@ -6111,6 +6166,10 @@ void WINAPI LoadSettings(LPARAM lParam) if (bOldTaskbar && (dwTemp != dwMMTaskbarGlomLevel)) { dwRefreshUIMask = REFRESHUI_GLOM; + if (dwMMOldTaskbarAl) + { + dwRefreshUIMask = REFRESHUI_CENTER; + } } dwMMTaskbarGlomLevel = dwTemp; RegCloseKey(hKey); @@ -6341,6 +6400,15 @@ void WINAPI LoadSettings(LPARAM lParam) RegSetKeyValueW(HKEY_CURRENT_USER, IsWindows11() ? TEXT(REGPATH) : L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", L"TaskbarGlomLevel", REG_DWORD, &dwGlomLevel, sizeof(DWORD)); Explorer_RefreshUI(0);*/ } + if (dwRefreshUIMask & REFRESHUI_CENTER) + { +#ifdef _WIN64 + //SendNotifyMessageW(HWND_BROADCAST, WM_WININICHANGE, 0, (LPARAM)L"ConvertibleSlateMode"); + ToggleTaskbarAutohide(); + Sleep(1000); + ToggleTaskbarAutohide(); +#endif + } } } @@ -8938,15 +9006,15 @@ DWORD Inject(BOOL bIsExplorer) - // This notifies applications when the taskbar has recomputed its layout - /*if (SUCCEEDED(TaskbarCenter_Initialize(hExplorer))) + + if (VnPatchDelayIAT(hExplorer, "ext-ms-win-rtcore-ntuser-window-ext-l1-1-0.dll", "GetClientRect", TaskbarCenter_GetClientRectHook)) { - printf("Initialized taskbar update notification.\n"); + printf("Initialized taskbar centering module.\n"); } else { - printf("Failed to register taskbar update notification.\n"); - }*/ + printf("Failed to initialize taskbar centering module.\n"); + } diff --git a/ExplorerPatcher/settings.reg b/ExplorerPatcher/settings.reg index 223b8b1..ade5a74 100644 --- a/ExplorerPatcher/settings.reg +++ b/ExplorerPatcher/settings.reg @@ -47,12 +47,26 @@ [HKEY_CURRENT_USER\Software\ExplorerPatcher] ;b Automatically hide the taskbar ;"Virtualized_{D17F1E1A-5919-4427-8F89-A1A8503CA3EB}_AutoHideTaskbar"=dword:00000000 -;t The following settings only apply to the Windows 10 taskbar: +;t The following settings only apply to the Windows 10 taskbar: [HKEY_CURRENT_USER\Software\ExplorerPatcher] ;c 2 Start button style ;x 0 Windows 10 (default) ;x 1 Windows 11 "OrbStyle"=dword:00000000 +;c 5 Primary taskbar alignment +;x 0 At screen edge (default) +;x 1 Centered +;x 5 Centered, at screen edge when full +;x 3 Centered with Start button +;x 7 Centered with Start button, at screen edge when full +"OldTaskbarAl"=dword:00000000 +;c 5 Secondary taskbar(s) alignment +;x 0 At screen edge (default) +;x 1 Centered +;x 5 Centered, at screen edge when full +;x 3 Centered with Start button +;x 7 Centered with Start button, at screen edge when full +"MMOldTaskbarAl"=dword:00000000 ;c 3 Combine taskbar icons on primary taskbar ;x 0 Always combine ;x 1 Combine when taskbar is full @@ -223,7 +237,7 @@ "MakeAllAppsDefault"=dword:00000000 [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced] ;c 2 Position on screen -;x 0 Left +;x 0 At screen edge ;x 1 Center (default) "TaskbarAl"=dword:00000001 ;t The following settings only apply to the Windows 10 Start menu: