From a1ef83e2b24d3b147686d269bf92c7c37c7feaa0 Mon Sep 17 00:00:00 2001 From: aubrey <44238627+aubymori@users.noreply.github.com> Date: Mon, 26 Aug 2024 02:38:42 -0500 Subject: [PATCH] Windows 7 Alt+Tab Loader 2.0.0 (#900) - Complete rewrite - Support for UWP app icons - Aero Peek now works --- mods/win7-alttab-loader.wh.cpp | 696 +++++++++++---------------------- 1 file changed, 230 insertions(+), 466 deletions(-) diff --git a/mods/win7-alttab-loader.wh.cpp b/mods/win7-alttab-loader.wh.cpp index 41a46e571..9862889f9 100644 --- a/mods/win7-alttab-loader.wh.cpp +++ b/mods/win7-alttab-loader.wh.cpp @@ -2,11 +2,11 @@ // @id win7-alttab-loader // @name Windows 7 Alt+Tab Loader // @description Loads Windows 7 Alt+Tab on Windows 10. -// @version 1.0.3 +// @version 2.0.0 // @author aubymori // @github https://github.com/aubymori // @include explorer.exe -// @compilerOptions -lole32 -luuid -ldwmapi -luxtheme -ldbghelp +// @compilerOptions -ldwmapi -lcomctl32 -lgdi32 // @architecture x86-64 // ==/WindhawkMod== @@ -16,568 +16,332 @@ This mod allows the Windows 7 Alt+Tab UI to work on Windows 10. # ⚠ IMPORTANT: PREREQUISITES! ⚠ -- You will need a copy of `AltTab.dll` from Windows 7 (x64). Once you have this, drop it into `C:\Windows`. +- You will need a copy of `AltTab.dll` from Windows 7 (x64). Once you have this, drop it into `%SystemRoot%\System32`. - You will also need an msstyles theme with a proper `AltTab` class, or else it will not render properly (Windows 3.x System font, weird looking selection, transparent background on basic theme) - [Here is a Windows 7 theme with proper classes.](https://www.deviantart.com/vaporvance/art/Aero10-for-Windows-10-1903-22H2-909711949) - You can make one with Windows Style Builder, which allows you to add classes to theme, or you can base on one that already does, and edit using msstyleEditor (recommended). - Once you have all these and install this mod, you will need to restart `explorer.exe` for the Windows 7 Alt+Tab UI to load. - - You will also need to restart `explorer.exe` to apply any new settings. + - You will also need to restart `explorer.exe` to use the mod. ![DWM (with thumbnails)](https://raw.githubusercontent.com/aubymori/images/main/win7-alt-tab-dwm.png) ![Basic (no thumbnails)](https://raw.githubusercontent.com/aubymori/images/main/win7-alt-tab-basic.png) -*Co-authored by ephemeralViolette and aubymori.* +*Original Windhawk mod by ephemeralViolette, original implementation in ExplorerPatcher by valinet.* */ // ==/WindhawkModReadme== -// ==WindhawkModSettings== -/* -- basic: false - $name: Use basic theme - $description: Enable this if you use basic theme. This will disable thumbnails and render the AltTab background instead of DWMWindow. -*/ -// ==/WindhawkModSettings== +#include +#include +#include +#include +#include +#include +#include +#include +#include -// For some reason, this isn't guaranteed to be imported. At least the mingw64 version of -// dwmapi.h doesn't define this, but the value seems to be constant so idk I'll just define -// it myself: -#ifndef DWM_E_COMPOSITIONDISABLED - #define DWM_E_COMPOSITIONDISABLED 0x80263001 -#endif +HMODULE g_hAltTab = NULL; -#include -inline BOOL VnPatchIAT(HMODULE hMod, PSTR libName, PSTR funcName, uintptr_t hookAddr) -{ - // Increment module reference count to prevent other threads from unloading it while we're working with it - HMODULE module; - if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)hMod, &module)) return FALSE; - - // Get a reference to the import table to locate the kernel32 entry - ULONG size; - PIMAGE_IMPORT_DESCRIPTOR importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToDataEx(module, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size, NULL); - - // In the import table find the entry that corresponds to kernel32 - BOOL found = FALSE; - while (importDescriptor->Characteristics && importDescriptor->Name) { - PSTR importName = (PSTR)((PBYTE)module + importDescriptor->Name); - if (_stricmp(importName, libName) == 0) { -#ifdef _LIBVALINET_DEBUG_HOOKING_IATPATCH - printf("[PatchIAT] Found %s in IAT.\n", libName); -#endif - found = TRUE; - break; - } - importDescriptor++; - } - if (!found) { - FreeLibrary(module); - return FALSE; - } +DEFINE_GUID(CLSID_AltTabSSO, 0xA1607060, 0x5D4C, 0x467A, 0xB7,0x11, 0x2B,0x59,0xA6,0xF2,0x59,0x57); +IOleCommandTarget *g_pAltTabSSO = nullptr; - // From the kernel32 import descriptor, go over its IAT thunks to - // find the one used by the rest of the code to call GetProcAddress - PIMAGE_THUNK_DATA oldthunk = (PIMAGE_THUNK_DATA)((PBYTE)module + importDescriptor->OriginalFirstThunk); - PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA)((PBYTE)module + importDescriptor->FirstThunk); - while (thunk->u1.Function) { - PROC* funcStorage = (PROC*)&thunk->u1.Function; +typedef BOOL (WINAPI *IsShellWindow_t)(HWND); +IsShellWindow_t IsShellFrameWindow = nullptr; +IsShellWindow_t IsShellManagedWindow = nullptr; - BOOL bFound = FALSE; - if (oldthunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) - { - bFound = (!(*((WORD*)&(funcName)+1)) && IMAGE_ORDINAL32(oldthunk->u1.Ordinal) == (INT64)funcName); - } - else - { - PIMAGE_IMPORT_BY_NAME byName = (PIMAGE_IMPORT_BY_NAME)((uintptr_t)module + oldthunk->u1.AddressOfData); - bFound = ((*((WORD*)&(funcName)+1)) && !_stricmp((char*)byName->Name, funcName)); - } +typedef HWND(WINAPI *GhostWindowFromHungWindow_t)(HWND); +GhostWindowFromHungWindow_t GhostWindowFromHungWindow = nullptr; - // Found it, now let's patch it - if (bFound) { - // Get the memory page where the info is stored - MEMORY_BASIC_INFORMATION mbi; - VirtualQuery(funcStorage, &mbi, sizeof(MEMORY_BASIC_INFORMATION)); +/* Prevent background UWP windows from showing up */ +BOOL (WINAPI *IsWindowEnabled_orig)(HWND); +BOOL WINAPI IsWindowEnabled_hook(HWND hWnd) +{ + if (!IsWindowEnabled_orig(hWnd)) + return FALSE; - // Try to change the page to be writable if it's not already - if (!VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_READWRITE, &mbi.Protect)) { - FreeLibrary(module); - return FALSE; - } + BOOL bCloaked; + DwmGetWindowAttribute(hWnd, DWMWA_CLOAKED, &bCloaked, sizeof(BOOL)); + if (bCloaked) + return FALSE; - // Store our hook - *funcStorage = (PROC)hookAddr; -#ifdef _LIBVALINET_DEBUG_HOOKING_IATPATCH - if ((*((WORD*)&(funcName)+1))) - { - printf("[PatchIAT] Patched %s in %s to 0x%p.\n", funcName, libName, hookAddr); - } - else - { - printf("[PatchIAT] Patched 0x%x in %s to 0x%p.\n", funcName, libName, hookAddr); - } -#endif + if (IsShellFrameWindow(hWnd) && !GhostWindowFromHungWindow(hWnd)) + return TRUE; - // Restore the old flag on the page - DWORD dwOldProtect; - VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, &dwOldProtect); + if (IsShellManagedWindow(hWnd) && GetPropW(hWnd, L"Microsoft.Windows.ShellManagedWindowAsNormalWindow") == NULL) + return FALSE; - // Profit - FreeLibrary(module); - return TRUE; - } + return TRUE; +} - thunk++; - oldthunk++; +void removechar(wchar_t *str, wchar_t c) +{ + wchar_t *src, *dst; + for (src = dst = str; *src != L'\0'; src++) + { + *dst = *src; + if (*dst != c) dst++; } - - FreeLibrary(module); - return FALSE; + *dst = L'\0'; } -// https://stackoverflow.com/questions/50973053/how-to-hook-delay-imports -inline BOOL VnPatchDelayIAT(HMODULE hMod, PSTR libName, PSTR funcName, uintptr_t hookAddr) +/* Load strings without the MUI */ +int (WINAPI *LoadStringW_orig)(HINSTANCE, UINT, LPWSTR, int); +int WINAPI LoadStringW_hook(HINSTANCE hInstance, UINT uId, LPWSTR lpBuffer, int cchBufferMax) { - // Increment module reference count to prevent other threads from unloading it while we're working with it - HMODULE lib; - if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)hMod, &lib)) return FALSE; - - PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)lib; - PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((uintptr_t)lib + dos->e_lfanew); - PIMAGE_DELAYLOAD_DESCRIPTOR dload = (PIMAGE_DELAYLOAD_DESCRIPTOR)((uintptr_t)lib + - nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress); - while (dload->DllNameRVA) + if (hInstance == g_hAltTab) { - char* dll = (char*)((uintptr_t)lib + dload->DllNameRVA); - if (!_stricmp(dll, libName)) { -#ifdef _LIBVALINET_DEBUG_HOOKING_IATPATCH - printf("[PatchDelayIAT] Found %s in IAT.\n", libName); -#endif - - PIMAGE_THUNK_DATA firstthunk = (PIMAGE_THUNK_DATA)((uintptr_t)lib + dload->ImportNameTableRVA); - PIMAGE_THUNK_DATA functhunk = (PIMAGE_THUNK_DATA)((uintptr_t)lib + dload->ImportAddressTableRVA); - while (firstthunk->u1.AddressOfData) + switch (uId) + { + case 0x3E8: + swprintf_s(lpBuffer, cchBufferMax, L"AltTab"); + return 6; + case 0x3EA: { - if (firstthunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) + HMODULE hExplorerFrame = GetModuleHandleW(L"ExplorerFrame.dll"); + if (hExplorerFrame) { - if (!(*((WORD*)&(funcName)+1)) && IMAGE_ORDINAL32(firstthunk->u1.Ordinal) == (INT64)funcName) - { - DWORD oldProtect; - if (VirtualProtect(&functhunk->u1.Function, sizeof(uintptr_t), PAGE_EXECUTE_READWRITE, &oldProtect)) - { - functhunk->u1.Function = (uintptr_t)hookAddr; - VirtualProtect(&functhunk->u1.Function, sizeof(uintptr_t), oldProtect, &oldProtect); -#ifdef _LIBVALINET_DEBUG_HOOKING_IATPATCH - printf("[PatchDelayIAT] Patched 0x%x in %s to 0x%p.\n", funcName, libName, hookAddr); -#endif - FreeLibrary(lib); - return TRUE; - } - FreeLibrary(lib); - return FALSE; - } + WCHAR szDesktop[MAX_PATH]; + LoadStringW_orig(hExplorerFrame, 13140, szDesktop, MAX_PATH); + removechar(szDesktop, L'&'); + wcscpy_s(lpBuffer, cchBufferMax, szDesktop); + return wcslen(lpBuffer); } else { - PIMAGE_IMPORT_BY_NAME byName = (PIMAGE_IMPORT_BY_NAME)((uintptr_t)lib + firstthunk->u1.AddressOfData); - if ((*((WORD*)&(funcName)+1)) && !_stricmp((char*)byName->Name, funcName)) - { - DWORD oldProtect; - if (VirtualProtect(&functhunk->u1.Function, sizeof(uintptr_t), PAGE_EXECUTE_READWRITE, &oldProtect)) - { - functhunk->u1.Function = (uintptr_t)hookAddr; - VirtualProtect(&functhunk->u1.Function, sizeof(uintptr_t), oldProtect, &oldProtect); -#ifdef _LIBVALINET_DEBUG_HOOKING_IATPATCH - printf("[PatchDelayIAT] Patched %s in %s to 0x%p.\n", funcName, libName, hookAddr); -#endif - FreeLibrary(lib); - return TRUE; - } - FreeLibrary(lib); - return FALSE; - } + swprintf_s(lpBuffer, cchBufferMax, L"Desktop"); + return 7; } - functhunk++; - firstthunk++; } } - dload++; } - FreeLibrary(lib); - return FALSE; -} - -//========================================================================================================================================= -// ALT TAB: -// - -#include -#include -#include -#include -#include -#include - -DEFINE_GUID( - CLSID_AltTabSSO, - 0xA1607060, 0x5D4C, 0x467A, 0xB7, 0x11, 0x2B, 0x59, 0xA6, 0xF2, 0x59, 0x57 -); - -struct { - BOOL bBasic; -} settings; - -HMODULE g_hAltTab = NULL; -IOleCommandTarget *g_pAltTabSSO = NULL; - -void LoadSettings() -{ - settings.bBasic = Wh_GetIntSetting(L"basic"); + return LoadStringW_orig(hInstance, uId, lpBuffer, cchBufferMax); } -// https://undoc.airesoft.co.uk/user32.dll/GetWindowCompositionAttribute.php -struct WINCOMPATTRDATA -{ - DWORD attribute; // the attribute to query, see below - PVOID pData; // buffer to store the result - ULONG dataSize; // size of the pData buffer -}; - -// https://undoc.airesoft.co.uk/user32.dll/GhostWindowFromHungWindow.php -typedef HWND (WINAPI *GhostWindowFromHungWindow_t)(HWND hWndGhost); -GhostWindowFromHungWindow_t pGhostWindowFromHungWindow; - -// https://github.com/valinet/sws/blob/586fe7d6bdbab4eec0c4b0999efe7c8602636a0b/SimpleWindowSwitcher/sws_WindowHelpers.c#L539C57-L539C57 -void GetDesktopText(wchar_t *wszTitle) +/* I don't know what this does but it's in the original so I'll keep it. */ +BOOL (WINAPI *PostMessageW_orig)(HWND, UINT, WPARAM, LPARAM); +BOOL WINAPI PostMessageW_hook(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - HMODULE hExplorerFrame = GetModuleHandleW(L"ExplorerFrame.dll"); - - if (hExplorerFrame) - { - LoadStringW(hExplorerFrame, 13140, wszTitle, MAX_PATH); - } - else + if (hWnd == FindWindowW(L"Shell_TrayWnd", NULL) && uMsg == 0x5B7 && wParam == 0 && lParam == 0) { - wcscat_s(wszTitle, MAX_PATH, L"Desktop"); + return PostMessageW_orig(hWnd, WM_COMMAND, 407, 0); } + return PostMessageW_orig(hWnd, uMsg, wParam, lParam); } -bool IsShellFrameWindow(HWND hWnd) +/* The signature of this function changed in Windows 10. */ +HRESULT (WINAPI *DwmpActivateLivePreview_orig)(BOOL, HWND, HWND, UINT, UINT_PTR); +HRESULT WINAPI DwmpActivateLivePreview_hook( + BOOL fActivate, + HWND hPeekWnd, + HWND hTopmostWnd, + UINT uPeekType +) { - // what in god's fucking holy name... - BOOL (WINAPI *pIsShellFrameWindow)(HWND) = (BOOL (WINAPI *)(HWND))GetProcAddress(LoadLibrary(L"user32.dll"), (LPCSTR)2573); - - if (pIsShellFrameWindow) - { - return pIsShellFrameWindow(hWnd); - } - else - { - return FALSE; - } + return DwmpActivateLivePreview_orig( + fActivate, hPeekWnd, hTopmostWnd, uPeekType, 0 + ); } -// even worse than above -bool IsShellManagedWindow(HWND hWnd) -{ - // what in god's fucking holy name... - BOOL (WINAPI *pIsShellFrameWindow)(HWND) = (BOOL (WINAPI *)(HWND))GetProcAddress(LoadLibrary(L"user32.dll"), (LPCSTR)2574); +DEFINE_GUID(GUID_AppUserModelIdProperty, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8,0xD0, 0xE1,0xD4,0x2D,0xE1,0xD5,0xF3); - if (pIsShellFrameWindow) - { - return pIsShellFrameWindow(hWnd); - } - else - { - return FALSE; - } -} - -int LoadStringW_Hook(HINSTANCE hInstance, UINT uId, LPWSTR lpBuffer, int cchBufferMax) +/** + * Implementation taken from Simple Window Switcher. + * https://github.com/valinet/sws/blob/971a3f20262c065c3b001c1781b6d75f9083680e/SimpleWindowSwitcher/sws_IconPainter.c#L253 + */ +HICON GetUWPIcon(HWND hWnd) { - if (uId == 0x3E8) - { - swprintf_s(lpBuffer, cchBufferMax, L"AltTab"); - return 6; - } - else if (uId == 0x3EA) + HICON result = NULL; + HRESULT hr = S_OK; + IShellItemImageFactory *psiif = nullptr; + SIIGBF flags = SIIGBF_RESIZETOFIT | SIIGBF_ICONBACKGROUND; + + IPropertyStore *pps = nullptr; + hr = SHGetPropertyStoreForWindow( + hWnd, IID_PPV_ARGS(&pps) + ); + if (SUCCEEDED(hr)) { - if (cchBufferMax < MAX_PATH) - return 0; - - GetDesktopText(lpBuffer); - - int len = wcslen(lpBuffer); - for (int i = 0; i < len; i++) - if (lpBuffer[i] == L'&') - lpBuffer[i] = L'\u200E'; - - return len; - } + PROPERTYKEY pKey; + pKey.fmtid = GUID_AppUserModelIdProperty; + pKey.pid = 5; + PROPVARIANT prop; + ZeroMemory(&prop, sizeof(PROPVARIANT)); + pps->GetValue(pKey, &prop); + pps->Release(); + if (prop.bstrVal) + { + SHCreateItemInKnownFolder( + FOLDERID_AppsFolder, + KF_FLAG_DONT_VERIFY, + prop.bstrVal, + IID_PPV_ARGS(&psiif) + ); + if (psiif) + { + int szIcon = GetSystemMetrics(SM_CXICON); + + SIZE size; + size.cx = szIcon; + size.cy = szIcon; + HBITMAP hBitmap; + hr = psiif->GetImage( + size, + flags, + &hBitmap + ); + if (SUCCEEDED(hr)) + { + // Easiest way to get an HICON from an HBITMAP + // I have turned the Internet upside down and was unable to find this + // Only a convoluted example using GDI+ + // This is from the disassembly of StartIsBack/StartAllBack + HIMAGELIST hImageList = ImageList_Create(size.cx, size.cy, ILC_COLOR32, 1, 0); + if (ImageList_Add(hImageList, hBitmap, NULL) != -1) + { + result = ImageList_GetIcon(hImageList, 0, 0); + ImageList_Destroy(hImageList); - return LoadStringW(hInstance, uId, lpBuffer, cchBufferMax); + DeleteObject(hBitmap); + psiif->Release(); + } + DeleteObject(hBitmap); + } + psiif->Release(); + } + } + } + return result; } -BOOL PostMessageW_Hook(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +/* Support UWP icons */ +SENDASYNCPROC CWindowInfo__GetIconProc_orig; +void WINAPI CWindowInfo__GetIconProc_hook( + HWND hWnd, + UINT uMsg, + UINT_PTR upParam, + LRESULT lResult +) { - if (hWnd == FindWindowW(L"Shell_TrayWnd", NULL) && uMsg == 0x5B7 && wParam == 0 && lParam == 0) + if (NULL == lResult && IsShellFrameWindow(hWnd)) { - return PostMessageW(hWnd, WM_COMMAND, 407, 0); + lResult = (LRESULT)GetUWPIcon(hWnd); } - - return PostMessageW(hWnd, uMsg, wParam, lParam); + CWindowInfo__GetIconProc_orig(hWnd, uMsg, upParam, lResult); } -HTHEME OpenThemeData_Hook(HWND hWnd, LPCWSTR pszClassList) -{ - if (wcscmp(pszClassList, L"AltTab") == 0) +const WindhawkUtils::SYMBOL_HOOK altTabDllHooks[] = { { - if (HTHEME data = OpenThemeData(hWnd, L"AltTab")) { - return data; - } - - return OpenThemeData(hWnd, L"WINDOW"); + L"private: static void __cdecl CWindowInfo::_GetIconProc(struct HWND__ *,unsigned int,unsigned __int64,__int64)" + }, + &CWindowInfo__GetIconProc_orig, + CWindowInfo__GetIconProc_hook, + false } +}; - return OpenThemeData(hWnd, pszClassList); -} - -BOOL IsWindowEnabled_Hook(HWND hWnd) -{ - if (!IsWindowEnabled(hWnd)) - return FALSE; - - BOOL isCloaked; - DwmGetWindowAttribute(hWnd, DWMWA_CLOAKED, &isCloaked, sizeof(BOOL)); - if (isCloaked) - return FALSE; - - if (IsShellFrameWindow(hWnd) && !pGhostWindowFromHungWindow(hWnd)) - return TRUE; - - if (IsShellManagedWindow(hWnd) && GetPropW(hWnd, L"Microsoft.Windows.ShellManagedWindowAsNormalWindow") == NULL) - return FALSE; - - return TRUE; -} - -HRESULT DwmpActivateLivePreview_Hook(int s, HWND hWnd, int c, int d) -{ - return S_OK; -} - -HRESULT DwmIsCompositionEnabled_Hook(BOOL *pfEnabled) +BOOL Wh_ModInit(void) { - HRESULT result = DwmIsCompositionEnabled(pfEnabled); - - if (S_OK == result) + g_hAltTab = LoadLibraryW(L"AltTab.dll"); + if (!g_hAltTab) { - *pfEnabled = FALSE; + Wh_Log(L"Failed to load AltTab.dll"); + return FALSE; } - return result; -} - -HRESULT DwmExtendFrameIntoClientArea_Hook(HWND hWnd, const MARGINS *pMarInset) -{ - return DWM_E_COMPOSITIONDISABLED; -} - -HRESULT DwmEnableBlurBehindWindow_Hook(HWND hWnd, const DWM_BLURBEHIND *pBlurBehind) -{ - return DWM_E_COMPOSITIONDISABLED; -} + HMODULE hUser32 = GetModuleHandleW(L"user32.dll"); + IsShellFrameWindow = (IsShellWindow_t)GetProcAddress(hUser32, (LPCSTR)2573); + IsShellManagedWindow = (IsShellWindow_t)GetProcAddress(hUser32, (LPCSTR)2574); + GhostWindowFromHungWindow = (GhostWindowFromHungWindow_t)GetProcAddress(hUser32, "GhostWindowFromHungWindow"); -HRESULT WINAPI DwmSetWindowAttribute_Hook(HWND hWnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute) -{ - if (dwAttribute != DWMWA_EXTENDED_FRAME_BOUNDS) - { - if ( - (dwAttribute > 15) && - (dwAttribute != 65537) - ) - { - Wh_Log(L"SWA: %i\r\n", dwAttribute); - } + Wh_SetFunctionHook( + (void *)IsWindowEnabled, + (void *)IsWindowEnabled_hook, + (void **)&IsWindowEnabled_orig + ); + Wh_SetFunctionHook( + (void *)LoadStringW, + (void *)LoadStringW_hook, + (void **)&LoadStringW_orig + ); + Wh_SetFunctionHook( + (void *)PostMessageW, + (void *)PostMessageW_hook, + (void **)&PostMessageW_orig + ); - return DwmSetWindowAttribute(hWnd, dwAttribute, pvAttribute, cbAttribute); - } - else + HMODULE hDwmapi = LoadLibraryW(L"dwmapi.dll"); + if (!hDwmapi) { - Wh_Log(L"SWA: DWMWA_EXTENDED_FRAME_BOUNDS\r\n"); - return S_OK; + Wh_Log(L"Failed to load dwmapi.dll"); + return FALSE; } -} - -BOOL IsCompositionActive_Hook() -{ - return FALSE; -} -void Cleanup() -{ - if (g_pAltTabSSO) + void *DwmpActivateLivePreview = (void *)GetProcAddress(hDwmapi, (LPCSTR)113); + if (!DwmpActivateLivePreview) { - g_pAltTabSSO->Release(); + Wh_Log(L"Failed to find DwmpActivateLivePreview in dwmapi.dll"); + return FALSE; } -} - -// The mod is being initialized, load settings, hook functions, and do other -// initialization stuff if required. -BOOL Wh_ModInit() -{ - Wh_Log(L"Init " WH_MOD_ID L" version " WH_MOD_VERSION); - - LoadSettings(); - g_hAltTab = LoadLibraryW(L"AltTab.dll"); - - pGhostWindowFromHungWindow = (GhostWindowFromHungWindow_t)GetProcAddress(LoadLibrary(L"user32.dll"), "GhostWindowFromHungWindow"); - - VnPatchIAT( - g_hAltTab, - (char *)"dwmapi.dll", - (char *)113, - (uintptr_t)DwmpActivateLivePreview_Hook + Wh_SetFunctionHook( + DwmpActivateLivePreview, + (void *)DwmpActivateLivePreview_hook, + (void **)&DwmpActivateLivePreview_orig ); - VnPatchIAT( - g_hAltTab, - (char *)"user32.dll", - (char *)"PostMessageW", - (uintptr_t)PostMessageW_Hook - ); - - VnPatchIAT( - g_hAltTab, - (char *)"user32.dll", - (char *)"LoadStringW", - (uintptr_t)LoadStringW_Hook - ); - - VnPatchIAT( - g_hAltTab, - (char *)"user32.dll", - (char *)"IsWindowEnabled", - (uintptr_t)IsWindowEnabled_Hook + using DllGetClassObject_t = decltype(&DllGetClassObject); + DllGetClassObject_t pDllGetClassObject = (DllGetClassObject_t)GetProcAddress( + g_hAltTab, "DllGetClassObject" ); - - VnPatchDelayIAT( - g_hAltTab, - (char *)"uxtheme.dll", - (char *)"OpenThemeData", - (uintptr_t)OpenThemeData_Hook - ); - - if (settings.bBasic) + if (!pDllGetClassObject) { - VnPatchDelayIAT( - g_hAltTab, - (char *)"dwmapi.dll", - (char *)"DwmIsCompositionEnabled", - (uintptr_t)DwmIsCompositionEnabled_Hook - ); - - VnPatchDelayIAT( - g_hAltTab, - (char *)"dwmapi.dll", - (char *)"DwmExtendFrameIntoClientArea", - (uintptr_t)DwmExtendFrameIntoClientArea_Hook - ); - - VnPatchDelayIAT( - g_hAltTab, - (char *)"dwmapi.dll", - (char *)"DwmEnableBlurBehindWindow", - (uintptr_t)DwmEnableBlurBehindWindow_Hook - ); - - VnPatchDelayIAT( - g_hAltTab, - (char *)"dwmapi.dll", - (char *)"DwmSetWindowAttribute", - (uintptr_t)DwmSetWindowAttribute_Hook - ); - - VnPatchDelayIAT( - g_hAltTab, - (char *)"uxtheme.dll", - (char *)"IsCompositionActive", - (uintptr_t)IsCompositionActive_Hook - ); + Wh_Log(L"Failed to find DllGetClassObject in AltTab.dll"); + return FALSE; } - if (g_hAltTab) + IClassFactory *pFactory = nullptr; + bool bSucceeded = false; + if (SUCCEEDED(pDllGetClassObject(CLSID_AltTabSSO, IID_PPV_ARGS(&pFactory))) && pFactory) { - // I FUCKING HATE C++ I FUCKING HATE C++ I FUCKING HATE C++ - // THAT CAST WOULD NOT BE NECESSARY IN C - HRESULT(*pDllGetClassObject)(REFCLSID, REFIID, LPVOID) = - (decltype(pDllGetClassObject))GetProcAddress(g_hAltTab, "DllGetClassObject"); - - IClassFactory *pFactory = NULL; - if ( - pDllGetClassObject && - SUCCEEDED( - pDllGetClassObject(CLSID_AltTabSSO, IID_IClassFactory, &pFactory) - ) && - pFactory - ) + if (SUCCEEDED(pFactory->CreateInstance(nullptr, IID_PPV_ARGS(&g_pAltTabSSO)) && g_pAltTabSSO)) { - if (SUCCEEDED(pFactory->CreateInstance(NULL, IID_IOleCommandTarget, (void **)&g_pAltTabSSO)) && g_pAltTabSSO) + if (SUCCEEDED(g_pAltTabSSO->Exec(&CGID_ShellServiceObject, 2, 0, NULL, NULL))) { - if (SUCCEEDED(g_pAltTabSSO->Exec(&CGID_ShellServiceObject, 2, 0, NULL, NULL))) - { - Wh_Log(L"Using Windows 7 AltTab!!"); - } - else - { - Wh_Log(L"Failed at SSO->Exec"); - } + Wh_Log(L"Using Windows 7 Alt+Tab"); + bSucceeded = true; } else { - Wh_Log(L"Failed at CreateInstance"); + Wh_Log(L"Failed at Exec"); } - - pFactory->Release(); } else { - Wh_Log(L"Failed at DllGetClassObject"); + Wh_Log(L"Failed at CreateInstance"); } - //FreeLibrary(g_hAltTab); + pFactory->Release(); } else { - wchar_t emsg[1024]; - wsprintf(emsg, L"Failed to load AltTab.dll. %d", GetLastError()); - - MessageBoxW( - NULL, - emsg, - L"Windhawk : Alt-Tab Loader", - MB_OK | MB_ICONERROR - ); + Wh_Log(L"Failed at DllGetClassObject"); + } + if (!bSucceeded || !WindhawkUtils::HookSymbols( + g_hAltTab, + altTabDllHooks, + ARRAYSIZE(altTabDllHooks) + )) + { return FALSE; } - return TRUE; } -// The mod is being unloaded, free all allocated resources. -void Wh_ModUninit() +void Wh_ModUninit(void) { - Wh_Log(L"Uninit"); - Cleanup(); -} - -// The mod setting were changed, reload them. -void Wh_ModSettingsChanged() -{ - Wh_Log(L"SettingsChanged"); - - LoadSettings(); -} + if (g_pAltTabSSO) + g_pAltTabSSO->Release(); +} \ No newline at end of file