FancyZonesApp.cpp
1 #include "pch.h" 2 #include "FancyZonesApp.h" 3 4 #include <common/display/dpi_aware.h> 5 #include <common/utils/logger_helper.h> 6 #include <common/utils/resources.h> 7 #include <common/utils/UnhandledExceptionHandler.h> 8 #include <common/interop/shared_constants.h> 9 10 #include <FancyZonesLib/Generated Files/resource.h> 11 #include <FancyZonesLib/FancyZonesData.h> 12 #include <FancyZonesLib/FancyZonesWinHookEventIDs.h> 13 #include <FancyZonesLib/Settings.h> 14 #include <FancyZonesLib/trace.h> 15 16 17 FancyZonesApp::FancyZonesApp(const std::wstring& appName, const std::wstring& appKey) 18 { 19 DPIAware::EnableDPIAwarenessForThisProcess(); 20 21 InitializeWinhookEventIds(); 22 m_app = MakeFancyZones(reinterpret_cast<HINSTANCE>(&__ImageBase), std::bind(&FancyZonesApp::DisableModule, this)); 23 24 m_mainThreadId = GetCurrentThreadId(); 25 m_exitEventWaiter.start(CommonSharedConstants::FZE_EXIT_EVENT, [&](DWORD err) { 26 if (err == ERROR_SUCCESS) 27 { 28 DisableModule(); 29 } 30 }); 31 32 InitHooks(); 33 34 s_instance = this; 35 } 36 37 FancyZonesApp::~FancyZonesApp() 38 { 39 if (m_app) 40 { 41 m_app->Destroy(); 42 m_app = nullptr; 43 44 if (s_llKeyboardHook) 45 { 46 if (UnhookWindowsHookEx(s_llKeyboardHook)) 47 { 48 s_llKeyboardHook = nullptr; 49 } 50 } 51 52 m_staticWinEventHooks.erase(std::remove_if(begin(m_staticWinEventHooks), 53 end(m_staticWinEventHooks), 54 [](const HWINEVENTHOOK hook) { 55 return UnhookWinEvent(hook); 56 }), 57 end(m_staticWinEventHooks)); 58 if (m_objectLocationWinEventHook) 59 { 60 if (UnhookWinEvent(m_objectLocationWinEventHook)) 61 { 62 m_objectLocationWinEventHook = nullptr; 63 } 64 } 65 } 66 } 67 68 void FancyZonesApp::Run() 69 { 70 if (m_app) 71 { 72 m_app->Run(); 73 } 74 } 75 76 void FancyZonesApp::InitHooks() 77 { 78 #if defined(DISABLE_LOWLEVEL_HOOKS_WHEN_DEBUGGED) 79 const bool hook_disabled = IsDebuggerPresent(); 80 #else 81 const bool hook_disabled = false; 82 #endif 83 84 if (!hook_disabled) 85 { 86 s_llKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), NULL); 87 if (!s_llKeyboardHook) 88 { 89 DWORD errorCode = GetLastError(); 90 show_last_error_message(L"SetWindowsHookEx", errorCode, GET_RESOURCE_STRING(IDS_POWERTOYS_FANCYZONES).c_str()); 91 auto errorMessage = get_last_error_message(errorCode); 92 Trace::FancyZones::Error(errorCode, errorMessage.has_value() ? errorMessage.value() : L"", L"enable.SetWindowsHookEx"); 93 } 94 } 95 96 std::array<DWORD, 6> events_to_subscribe = { 97 EVENT_SYSTEM_MOVESIZESTART, 98 EVENT_SYSTEM_MOVESIZEEND, 99 EVENT_OBJECT_NAMECHANGE, 100 EVENT_OBJECT_UNCLOAKED, 101 EVENT_OBJECT_SHOW, 102 EVENT_OBJECT_CREATE 103 }; 104 for (const auto event : events_to_subscribe) 105 { 106 auto hook = SetWinEventHook(event, event, nullptr, WinHookProc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); 107 if (hook) 108 { 109 m_staticWinEventHooks.emplace_back(hook); 110 } 111 else 112 { 113 MessageBoxW(NULL, 114 GET_RESOURCE_STRING(IDS_WINDOW_EVENT_LISTENER_ERROR).c_str(), 115 GET_RESOURCE_STRING(IDS_POWERTOYS_FANCYZONES).c_str(), 116 MB_OK | MB_ICONERROR); 117 } 118 } 119 } 120 121 void FancyZonesApp::DisableModule() noexcept 122 { 123 PostThreadMessage(m_mainThreadId, WM_QUIT, 0, 0); 124 } 125 126 void FancyZonesApp::HandleWinHookEvent(WinHookEvent* data) noexcept 127 { 128 auto fzCallback = m_app.as<IFancyZonesCallback>(); 129 switch (data->event) 130 { 131 case EVENT_SYSTEM_MOVESIZESTART: 132 { 133 fzCallback->HandleWinHookEvent(data); 134 if (!m_objectLocationWinEventHook) 135 { 136 m_objectLocationWinEventHook = SetWinEventHook(EVENT_OBJECT_LOCATIONCHANGE, 137 EVENT_OBJECT_LOCATIONCHANGE, 138 nullptr, 139 WinHookProc, 140 0, 141 0, 142 WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); 143 } 144 } 145 break; 146 147 case EVENT_SYSTEM_MOVESIZEEND: 148 { 149 if (UnhookWinEvent(m_objectLocationWinEventHook)) 150 { 151 m_objectLocationWinEventHook = nullptr; 152 } 153 fzCallback->HandleWinHookEvent(data); 154 } 155 break; 156 157 case EVENT_OBJECT_LOCATIONCHANGE: 158 { 159 fzCallback->HandleWinHookEvent(data); 160 } 161 break; 162 163 case EVENT_OBJECT_NAMECHANGE: 164 { 165 // The accessibility name of the desktop window changes whenever the user 166 // switches virtual desktops. 167 if (data->hwnd == GetDesktopWindow()) 168 { 169 m_app.as<IFancyZonesCallback>()->VirtualDesktopChanged(); 170 } 171 } 172 break; 173 174 case EVENT_OBJECT_UNCLOAKED: 175 case EVENT_OBJECT_SHOW: 176 case EVENT_OBJECT_CREATE: 177 { 178 fzCallback->HandleWinHookEvent(data); 179 } 180 break; 181 182 default: 183 break; 184 } 185 } 186 187 intptr_t FancyZonesApp::HandleKeyboardHookEvent(LowlevelKeyboardEvent* data) noexcept 188 { 189 return m_app.as<IFancyZonesCallback>()->OnKeyDown(data->lParam); 190 }