dllmain.cpp
1 // dllmain.cpp : Defines the entry point for the DLL application. 2 #include "pch.h" 3 4 #include <interface/powertoy_module_interface.h> 5 #include "trace.h" 6 #include "Generated Files/resource.h" 7 #include <common/logger/logger.h> 8 #include <common/SettingsAPI/settings_objects.h> 9 #include <common/utils/resources.h> 10 11 #include <PowerOCR/PowerOCRModuleInterface/PowerOcrConstants.h> 12 #include <common/interop/shared_constants.h> 13 #include <common/utils/logger_helper.h> 14 #include <common/utils/winapi_error.h> 15 #include <common/utils/package.h> 16 17 BOOL APIENTRY DllMain(HMODULE /*hModule*/, 18 DWORD ul_reason_for_call, 19 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 break; 28 case DLL_THREAD_DETACH: 29 break; 30 case DLL_PROCESS_DETACH: 31 Trace::UnregisterProvider(); 32 break; 33 } 34 35 return TRUE; 36 } 37 38 namespace 39 { 40 const wchar_t JSON_KEY_PROPERTIES[] = L"properties"; 41 const wchar_t JSON_KEY_WIN[] = L"win"; 42 const wchar_t JSON_KEY_ALT[] = L"alt"; 43 const wchar_t JSON_KEY_CTRL[] = L"ctrl"; 44 const wchar_t JSON_KEY_SHIFT[] = L"shift"; 45 const wchar_t JSON_KEY_CODE[] = L"code"; 46 const wchar_t JSON_KEY_ACTIVATION_SHORTCUT[] = L"ActivationShortcut"; 47 } 48 49 struct ModuleSettings 50 { 51 } g_settings; 52 53 class PowerOCR : public PowertoyModuleIface 54 { 55 private: 56 bool m_enabled = false; 57 58 std::wstring app_name; 59 60 //contains the non localized key of the powertoy 61 std::wstring app_key; 62 63 HANDLE m_hProcess; 64 65 // Time to wait for process to close after sending WM_CLOSE signal 66 static const int MAX_WAIT_MILLISEC = 10000; 67 68 Hotkey m_hotkey; 69 70 // Handle to event used to invoke PowerOCR 71 HANDLE m_hInvokeEvent; 72 // Handle to event used to terminate PowerOCR 73 HANDLE m_hTerminateEvent; 74 75 void parse_hotkey(PowerToysSettings::PowerToyValues& settings) 76 { 77 auto settingsObject = settings.get_raw_json(); 78 if (settingsObject.GetView().Size()) 79 { 80 try 81 { 82 auto jsonHotkeyObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_ACTIVATION_SHORTCUT); 83 m_hotkey.win = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_WIN); 84 m_hotkey.alt = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_ALT); 85 m_hotkey.shift = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_SHIFT); 86 m_hotkey.ctrl = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_CTRL); 87 m_hotkey.key = static_cast<unsigned char>(jsonHotkeyObject.GetNamedNumber(JSON_KEY_CODE)); 88 } 89 catch (...) 90 { 91 Logger::error("Failed to initialize TextExtractor start shortcut"); 92 } 93 } 94 else 95 { 96 Logger::info("TextExtractor settings are empty"); 97 } 98 99 if (!m_hotkey.key) 100 { 101 Logger::info("TextExtractor is going to use default shortcut"); 102 m_hotkey.win = true; 103 m_hotkey.alt = false; 104 m_hotkey.shift = true; 105 m_hotkey.ctrl = false; 106 m_hotkey.key = 'T'; 107 } 108 } 109 110 bool is_process_running() 111 { 112 return WaitForSingleObject(m_hProcess, 0) == WAIT_TIMEOUT; 113 } 114 115 void launch_process() 116 { 117 Logger::trace(L"Starting TextExtractor process"); 118 unsigned long powertoys_pid = GetCurrentProcessId(); 119 120 std::wstring executable_args = L""; 121 executable_args.append(std::to_wstring(powertoys_pid)); 122 123 SHELLEXECUTEINFOW sei{ sizeof(sei) }; 124 sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI }; 125 sei.lpFile = L"PowerToys.PowerOCR.exe"; 126 sei.nShow = SW_SHOWNORMAL; 127 sei.lpParameters = executable_args.data(); 128 if (ShellExecuteExW(&sei)) 129 { 130 Logger::trace("Successfully started the TextExtractor process"); 131 } 132 else 133 { 134 Logger::error(L"TextExtractor failed to start. {}", get_last_error_or_default(GetLastError())); 135 } 136 137 m_hProcess = sei.hProcess; 138 } 139 140 // Load the settings file. 141 void init_settings() 142 { 143 try 144 { 145 // Load and parse the settings file for this PowerToy. 146 PowerToysSettings::PowerToyValues settings = 147 PowerToysSettings::PowerToyValues::load_from_settings_file(get_key()); 148 149 parse_hotkey(settings); 150 } 151 catch (std::exception&) 152 { 153 Logger::warn(L"An exception occurred while loading the settings file"); 154 // Error while loading from the settings file. Let default values stay as they are. 155 } 156 } 157 158 public: 159 PowerOCR() 160 { 161 app_name = GET_RESOURCE_STRING(IDS_TEXTEXTRACTOR_NAME); 162 app_key = PowerOcrConstants::ModuleKey; 163 LoggerHelpers::init_logger(app_key, L"ModuleInterface", "TextExtractor"); 164 m_hInvokeEvent = CreateDefaultEvent(CommonSharedConstants::SHOW_POWEROCR_SHARED_EVENT); 165 m_hTerminateEvent = CreateDefaultEvent(CommonSharedConstants::TERMINATE_POWEROCR_SHARED_EVENT); 166 init_settings(); 167 } 168 169 ~PowerOCR() 170 { 171 if (m_enabled) 172 { 173 } 174 m_enabled = false; 175 } 176 177 // Destroy the powertoy and free memory 178 virtual void destroy() override 179 { 180 Logger::trace("TextExtractor::destroy()"); 181 delete this; 182 } 183 184 // Return the localized display name of the powertoy 185 virtual const wchar_t* get_name() override 186 { 187 return app_name.c_str(); 188 } 189 190 // Return the non localized key of the powertoy, this will be cached by the runner 191 virtual const wchar_t* get_key() override 192 { 193 return app_key.c_str(); 194 } 195 196 // Return the configured status for the gpo policy for the module 197 virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override 198 { 199 return powertoys_gpo::getConfiguredTextExtractorEnabledValue(); 200 } 201 202 virtual bool get_config(wchar_t* buffer, int* buffer_size) override 203 { 204 HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase); 205 206 // Create a Settings object. 207 PowerToysSettings::Settings settings(hinstance, get_name()); 208 settings.set_description(GET_RESOURCE_STRING(IDS_TEXTEXTRACTOR_SETTINGS_DESC)); 209 210 settings.set_overview_link(L"https://aka.ms/PowerToysOverview_TextExtractor"); 211 212 return settings.serialize_to_buffer(buffer, buffer_size); 213 } 214 215 virtual void call_custom_action(const wchar_t* /*action*/) override 216 { 217 } 218 219 virtual void set_config(const wchar_t* config) override 220 { 221 try 222 { 223 // Parse the input JSON string. 224 PowerToysSettings::PowerToyValues values = 225 PowerToysSettings::PowerToyValues::from_json_string(config, get_key()); 226 227 parse_hotkey(values); 228 // If you don't need to do any custom processing of the settings, proceed 229 // to persists the values calling: 230 values.save_to_settings_file(); 231 // Otherwise call a custom function to process the settings before saving them to disk: 232 // save_settings(); 233 } 234 catch (std::exception&) 235 { 236 // Improper JSON. 237 } 238 } 239 240 virtual void enable() 241 { 242 Logger::trace("TextExtractor::enable()"); 243 ResetEvent(m_hInvokeEvent); 244 launch_process(); 245 m_enabled = true; 246 Trace::EnablePowerOCR(true); 247 }; 248 249 virtual void disable() 250 { 251 Logger::trace("TextExtractor::disable()"); 252 if (m_enabled) 253 { 254 ResetEvent(m_hInvokeEvent); 255 SetEvent(m_hTerminateEvent); 256 WaitForSingleObject(m_hProcess, 1500); 257 TerminateProcess(m_hProcess, 1); 258 } 259 260 m_enabled = false; 261 Trace::EnablePowerOCR(false); 262 } 263 264 virtual bool on_hotkey(size_t /*hotkeyId*/) override 265 { 266 if (m_enabled) 267 { 268 Logger::trace(L"TextExtractor hotkey pressed"); 269 if (!is_process_running()) 270 { 271 launch_process(); 272 } 273 274 SetEvent(m_hInvokeEvent); 275 return true; 276 } 277 278 return false; 279 } 280 281 virtual size_t get_hotkeys(Hotkey* hotkeys, size_t buffer_size) override 282 { 283 if (m_hotkey.key) 284 { 285 if (hotkeys && buffer_size >= 1) 286 { 287 hotkeys[0] = m_hotkey; 288 } 289 290 return 1; 291 } 292 else 293 { 294 return 0; 295 } 296 } 297 298 virtual bool is_enabled() override 299 { 300 return m_enabled; 301 } 302 303 // Returns whether the PowerToys should be enabled by default 304 virtual bool is_enabled_by_default() const override 305 { 306 // disabled by default for Windows 11 and enabled by default on Windows 10 307 return !package::IsWin11OrGreater(); 308 } 309 }; 310 311 extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create() 312 { 313 return new PowerOCR(); 314 }