/ src / modules / fancyzones / FancyZones / FancyZonesApp.cpp
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  }