dllmain.cpp
  1  #include "pch.h"
  2  
  3  #include <interface/powertoy_module_interface.h>
  4  
  5  #include <common/interop/shared_constants.h>
  6  #include <common/logger/logger.h>
  7  #include <common/utils/resources.h>
  8  #include <common/utils/winapi_error.h>
  9  
 10  #include <FancyZonesLib/Generated Files/resource.h>
 11  #include <FancyZonesLib/trace.h>
 12  #include <FancyZonesLib/Settings.h>
 13  #include <FancyZonesLib/ModuleConstants.h>
 14  
 15  #include <shellapi.h>
 16  
 17  // Non-localizable
 18  const std::wstring fancyZonesPath = L"PowerToys.FancyZones.exe";
 19  
 20  BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*lpReserved*/)
 21  {
 22      switch (ul_reason_for_call)
 23      {
 24      case DLL_PROCESS_ATTACH:
 25          Trace::RegisterProvider();
 26          break;
 27  
 28      case DLL_THREAD_ATTACH:
 29      case DLL_THREAD_DETACH:
 30          break;
 31  
 32      case DLL_PROCESS_DETACH:
 33          Trace::UnregisterProvider();
 34          break;
 35      }
 36      return TRUE;
 37  }
 38  
 39  class FancyZonesModuleInterface : public PowertoyModuleIface
 40  {
 41  public:
 42      // Return the localized display name of the powertoy
 43      virtual PCWSTR get_name() override
 44      {
 45          return app_name.c_str();
 46      }
 47  
 48      // Return the non localized key of the powertoy, this will be cached by the runner
 49      virtual const wchar_t* get_key() override
 50      {
 51          return app_key.c_str();
 52      }
 53  
 54      // Return the configured status for the gpo policy for the module
 55      virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override
 56      {
 57          return powertoys_gpo::getConfiguredFancyZonesEnabledValue();
 58      }
 59  
 60      // Return JSON with the configuration options.
 61      // These are the settings shown on the settings page along with their current values.
 62      virtual bool get_config(_Out_ PWSTR /*buffer*/, _Out_ int* /*buffer_size*/) override
 63      {
 64          return false;
 65      }
 66  
 67      // Passes JSON with the configuration settings for the powertoy.
 68      // This is called when the user hits Save on the settings page.
 69      virtual void set_config(PCWSTR /*config*/) override
 70      {
 71      }
 72  
 73      // Signal from the Settings editor to call a custom action.
 74      // This can be used to spawn more complex editors.
 75      virtual void call_custom_action(const wchar_t* /*action*/) override
 76      {
 77          SetEvent(m_toggleEditorEvent);
 78      }
 79  
 80      // Enable the powertoy
 81      virtual void enable()
 82      {
 83          Logger::info("FancyZones enabling");
 84  
 85          Enable();
 86      }
 87  
 88      // Disable the powertoy
 89      virtual void disable()
 90      {
 91          Logger::info("FancyZones disabling");
 92  
 93          Disable(true);
 94      }
 95  
 96      // Returns if the powertoy is enabled
 97      virtual bool is_enabled() override
 98      {
 99          return m_enabled;
100      }
101  
102      // Destroy the powertoy and free memory
103      virtual void destroy() override
104      {
105          Disable(false);
106  
107          if (m_toggleEditorEvent)
108          {
109              CloseHandle(m_toggleEditorEvent);
110              m_toggleEditorEvent = nullptr;
111          }
112  
113          delete this;
114      }
115  
116      virtual void send_settings_telemetry() override
117      {
118          Logger::info("Send settings telemetry");
119          FancyZonesSettings::instance().LoadSettings();
120          Trace::SettingsTelemetry(FancyZonesSettings::settings());
121      }
122  
123      FancyZonesModuleInterface()
124      {
125          app_name = GET_RESOURCE_STRING(IDS_FANCYZONES);
126          app_key = NonLocalizable::ModuleKey;
127  
128          m_toggleEditorEvent = CreateDefaultEvent(CommonSharedConstants::FANCY_ZONES_EDITOR_TOGGLE_EVENT);
129          if (!m_toggleEditorEvent)
130          {
131              Logger::error(L"Failed to create toggle editor event");
132              auto message = get_last_error_message(GetLastError());
133              if (message.has_value())
134              {
135                  Logger::error(message.value());
136              }
137          }
138      }
139  
140  private:
141      void Enable()
142      {
143          m_enabled = true;
144  
145          // Log telemetry
146          Trace::FancyZones::EnableFancyZones(true);
147  
148          unsigned long powertoys_pid = GetCurrentProcessId();
149          std::wstring executable_args = L"";
150          executable_args.append(std::to_wstring(powertoys_pid));
151  
152          SHELLEXECUTEINFOW sei{ sizeof(sei) };
153          sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
154          sei.lpFile = fancyZonesPath.c_str();
155          sei.nShow = SW_SHOWNORMAL;
156          sei.lpParameters = executable_args.data();
157          if (ShellExecuteExW(&sei) == false)
158          {
159              Logger::error(L"Failed to start FancyZones");
160              auto message = get_last_error_message(GetLastError());
161              if (message.has_value())
162              {
163                  Logger::error(message.value());
164              }
165          }
166          else
167          {
168              m_hProcess = sei.hProcess;
169          }
170      }
171  
172      void SendFZECloseEvent()
173      {
174          auto exitEvent = CreateEventW(nullptr, false, false, CommonSharedConstants::FZE_EXIT_EVENT);
175          if (!exitEvent)
176          {
177              Logger::warn(L"Failed to create exitEvent. {}", get_last_error_or_default(GetLastError()));
178          }
179          else
180          {
181              Logger::trace(L"Signaled exitEvent");
182              if (!SetEvent(exitEvent))
183              {
184                  Logger::warn(L"Failed to signal exitEvent. {}", get_last_error_or_default(GetLastError()));
185              }
186  
187              ResetEvent(exitEvent);
188              CloseHandle(exitEvent);
189          }
190      }
191  
192      void Disable(bool const traceEvent)
193      {
194          m_enabled = false;
195          // Log telemetry
196          if (traceEvent)
197          {
198              Trace::FancyZones::EnableFancyZones(false);
199          }
200  
201          if (m_toggleEditorEvent)
202          {
203              ResetEvent(m_toggleEditorEvent);
204          }
205  
206          if (m_hProcess)
207          {
208              SendFZECloseEvent();
209              WaitForSingleObject(m_hProcess, 1500);
210              TerminateProcess(m_hProcess, 0);
211              m_hProcess = nullptr;
212          }
213      }
214  
215      std::wstring app_name;
216      //contains the non localized key of the powertoy
217      std::wstring app_key;
218  
219      bool m_enabled = false;
220      HANDLE m_hProcess = nullptr;
221  
222      // Handle to event used to invoke FancyZones Editor
223      HANDLE m_toggleEditorEvent;
224  };
225  
226  extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
227  {
228      return new FancyZonesModuleInterface();
229  }