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 }