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 }