/ src / modules / Hosts / HostsModuleInterface / dllmain.cpp
dllmain.cpp
  1  #include "pch.h"
  2  
  3  #include "trace.h"
  4  #include <common/logger/logger.h>
  5  #include <common/utils/logger_helper.h>
  6  #include <interface/powertoy_module_interface.h>
  7  #include "Generated Files/resource.h"
  8  
  9  #include <shellapi.h>
 10  #include <common/interop/shared_constants.h>
 11  #include <common/utils/EventWaiter.h>
 12  #include <common/utils/resources.h>
 13  #include <common/utils/winapi_error.h>
 14  #include <common/SettingsAPI/settings_objects.h>
 15  #include <string>
 16  
 17  extern "C" IMAGE_DOS_HEADER __ImageBase;
 18  
 19  BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*lpReserved*/)
 20  {
 21      switch (ul_reason_for_call)
 22      {
 23      case DLL_PROCESS_ATTACH:
 24          Trace::RegisterProvider();
 25          break;
 26      case DLL_THREAD_ATTACH:
 27      case DLL_THREAD_DETACH:
 28          break;
 29      case DLL_PROCESS_DETACH:
 30          Trace::UnregisterProvider();
 31          break;
 32      }
 33      return TRUE;
 34  }
 35  
 36  namespace
 37  {
 38      // Name of the powertoy module.
 39      inline const std::wstring ModuleKey = L"Hosts";
 40  }
 41  
 42  class HostsModuleInterface : public PowertoyModuleIface
 43  {
 44  private:
 45      bool m_enabled = false;
 46  
 47      std::wstring app_name;
 48  
 49      //contains the non localized key of the powertoy
 50      std::wstring app_key;
 51  
 52      HANDLE m_hProcess = nullptr;
 53  
 54      HANDLE m_hShowEvent{};
 55  
 56      HANDLE m_hShowAdminEvent{};
 57  
 58      HANDLE m_hTerminateEvent{};
 59  
 60      bool is_process_running()
 61      {
 62          return WaitForSingleObject(m_hProcess, 0) == WAIT_TIMEOUT;
 63      }
 64  
 65      void bring_process_to_front()
 66      {
 67          auto enum_windows = [](HWND hwnd, LPARAM param) -> BOOL {
 68              HANDLE process_handle = reinterpret_cast<HANDLE>(param);
 69              DWORD window_process_id = 0;
 70  
 71              GetWindowThreadProcessId(hwnd, &window_process_id);
 72              if (GetProcessId(process_handle) == window_process_id)
 73              {
 74                  SetForegroundWindow(hwnd);
 75                  return FALSE;
 76              }
 77              return TRUE;
 78          };
 79  
 80          EnumWindows(enum_windows, (LPARAM)m_hProcess);
 81      }
 82  
 83      void launch_process(bool runas)
 84      {
 85          Logger::trace(L"Starting Hosts process");
 86          unsigned long powertoys_pid = GetCurrentProcessId();
 87  
 88          std::wstring executable_args = L"";
 89          executable_args.append(std::to_wstring(powertoys_pid));
 90  
 91          SHELLEXECUTEINFOW sei{ sizeof(sei) };
 92          sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
 93          sei.lpFile = L"WinUI3Apps\\PowerToys.Hosts.exe";
 94          sei.nShow = SW_SHOWNORMAL;
 95          sei.lpParameters = executable_args.data();
 96  
 97          if (runas)
 98          {
 99              sei.lpVerb = L"runas";
100          }
101  
102          if (ShellExecuteExW(&sei))
103          {
104              Logger::trace("Successfully started the Hosts process");
105          }
106          else
107          {
108              Logger::error(L"Hosts failed to start. {}", get_last_error_or_default(GetLastError()));
109          }
110  
111          m_hProcess = sei.hProcess;
112      }
113  
114  public:
115      EventWaiter m_showEventWaiter;
116  
117      EventWaiter m_showAdminEventWaiter;
118  
119      HostsModuleInterface()
120      {
121          app_name = GET_RESOURCE_STRING(IDS_HOSTS_NAME);
122          app_key = ModuleKey;
123          LoggerHelpers::init_logger(app_key, L"ModuleInterface", LogSettings::hostsLoggerName);
124  
125          m_hShowEvent = CreateDefaultEvent(CommonSharedConstants::SHOW_HOSTS_EVENT);
126          if (!m_hShowEvent)
127          {
128              Logger::error(L"Failed to create show hosts event");
129              auto message = get_last_error_message(GetLastError());
130              if (message.has_value())
131              {
132                  Logger::error(message.value());
133              }
134          }
135  
136          m_hShowAdminEvent = CreateDefaultEvent(CommonSharedConstants::SHOW_HOSTS_ADMIN_EVENT);
137          if (!m_hShowAdminEvent)
138          {
139              Logger::error(L"Failed to create show hosts admin event");
140              auto message = get_last_error_message(GetLastError());
141              if (message.has_value())
142              {
143                  Logger::error(message.value());
144              }
145          }
146  
147          m_hTerminateEvent = CreateDefaultEvent(CommonSharedConstants::TERMINATE_HOSTS_EVENT);
148          if (!m_hTerminateEvent)
149          {
150              Logger::error(L"Failed to create terminate hosts event");
151              auto message = get_last_error_message(GetLastError());
152              if (message.has_value())
153              {
154                  Logger::error(message.value());
155              }
156          }
157  
158          m_showEventWaiter.start(CommonSharedConstants::SHOW_HOSTS_EVENT, [&](DWORD err)
159          {
160              if (m_enabled && err == ERROR_SUCCESS)
161              {
162                  Logger::trace(L"{} event was signaled", CommonSharedConstants::SHOW_HOSTS_EVENT);
163  
164                  if (is_process_running())
165                  {
166                      bring_process_to_front();
167                  }
168                  else
169                  {
170                      launch_process(false);
171                  }
172  
173                  Trace::ActivateEditor();
174              }
175          });
176  
177          m_showAdminEventWaiter.start(CommonSharedConstants::SHOW_HOSTS_ADMIN_EVENT, [&](DWORD err)
178          {
179              if (m_enabled && err == ERROR_SUCCESS)
180              {
181                  Logger::trace(L"{} event was signaled", CommonSharedConstants::SHOW_HOSTS_ADMIN_EVENT);
182                  
183                  if (is_process_running())
184                  {
185                      bring_process_to_front();
186                  }
187                  else
188                  {
189                      launch_process(true);
190                  }
191  
192                  Trace::ActivateEditor();
193              }
194          });
195      }
196  
197      ~HostsModuleInterface()
198      {
199          m_enabled = false;
200      }
201  
202      // Destroy the powertoy and free memory
203      virtual void destroy() override
204      {
205          Logger::trace("HostsModuleInterface::destroy()");
206  
207          if (m_hShowEvent)
208          {
209              CloseHandle(m_hShowEvent);
210              m_hShowEvent = nullptr;
211          }
212  
213          if (m_hShowAdminEvent)
214          {
215              CloseHandle(m_hShowAdminEvent);
216              m_hShowAdminEvent = nullptr;
217          }
218  
219          if (m_hTerminateEvent)
220          {
221              CloseHandle(m_hTerminateEvent);
222              m_hTerminateEvent = nullptr;
223          }
224  
225          delete this;
226      }
227  
228      // Return the localized display name of the powertoy
229      virtual const wchar_t* get_name() override
230      {
231          return app_name.c_str();
232      }
233  
234      // Return the non localized key of the powertoy, this will be cached by the runner
235      virtual const wchar_t* get_key() override
236      {
237          return app_key.c_str();
238      }
239  
240      // Return the configured status for the gpo policy for the module
241      virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override
242      {
243          return powertoys_gpo::getConfiguredHostsFileEditorEnabledValue();
244      }
245  
246      virtual bool get_config(wchar_t* /*buffer*/, int* /*buffer_size*/) override
247      {
248          return false;
249      }
250  
251      virtual void call_custom_action(const wchar_t* /*action*/) override
252      {
253      }
254  
255      virtual void set_config(const wchar_t* /*config*/) override
256      {
257      }
258  
259      virtual bool is_enabled() override
260      {
261          return m_enabled;
262      }
263  
264      virtual void enable()
265      {
266          Logger::trace("HostsModuleInterface::enable()");
267          m_enabled = true;
268          Trace::EnableHostsFileEditor(true);
269      };
270  
271      virtual void disable()
272      {
273          Logger::trace("HostsModuleInterface::disable()");
274          if (m_enabled)
275          {
276              if (m_hShowEvent)
277              {
278                  ResetEvent(m_hShowEvent);
279              }
280  
281              if (m_hShowAdminEvent)
282              {
283                  ResetEvent(m_hShowAdminEvent);
284              }
285  
286              SetEvent(m_hTerminateEvent);
287              WaitForSingleObject(m_hProcess, 1500);
288              TerminateProcess(m_hProcess, 1);
289              ResetEvent(m_hTerminateEvent);
290          }
291  
292          m_enabled = false;
293          Trace::EnableHostsFileEditor(false);
294      }
295  };
296  
297  extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
298  {
299      return new HostsModuleInterface();
300  }