dllmain.cpp
1 #include "pch.h" 2 #include <interface/powertoy_module_interface.h> 3 #include <common/SettingsAPI/settings_objects.h> 4 #include <common/utils/resources.h> 5 #include "Generated Files/resource.h" 6 #include <keyboardmanager/common/KeyboardManagerConstants.h> 7 #include <common/utils/winapi_error.h> 8 #include <keyboardmanager/dll/trace.h> 9 #include <shellapi.h> 10 #include <common/utils/logger_helper.h> 11 #include <common/interop/shared_constants.h> 12 13 BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*lpReserved*/) 14 { 15 switch (ul_reason_for_call) 16 { 17 case DLL_PROCESS_ATTACH: 18 Trace::RegisterProvider(); 19 break; 20 case DLL_THREAD_ATTACH: 21 case DLL_THREAD_DETACH: 22 break; 23 case DLL_PROCESS_DETACH: 24 Trace::UnregisterProvider(); 25 break; 26 } 27 28 return TRUE; 29 } 30 31 // Implement the PowerToy Module Interface and all the required methods. 32 class KeyboardManager : public PowertoyModuleIface 33 { 34 private: 35 // The PowerToy state. 36 bool m_enabled = false; 37 38 // The PowerToy name that will be shown in the settings. 39 const std::wstring app_name = GET_RESOURCE_STRING(IDS_KEYBOARDMANAGER); 40 41 //contains the non localized key of the powertoy 42 std::wstring app_key = KeyboardManagerConstants::ModuleName; 43 44 HANDLE m_hProcess = nullptr; 45 46 HANDLE m_hTerminateEngineEvent = nullptr; 47 48 public: 49 // Constructor 50 KeyboardManager() 51 { 52 LoggerHelpers::init_logger(KeyboardManagerConstants::ModuleName, L"ModuleInterface", LogSettings::keyboardManagerLoggerName); 53 54 std::filesystem::path oldLogPath(PTSettingsHelper::get_module_save_folder_location(app_key)); 55 oldLogPath.append("Logs"); 56 LoggerHelpers::delete_old_log_folder(oldLogPath); 57 58 m_hTerminateEngineEvent = CreateDefaultEvent(CommonSharedConstants::TERMINATE_KBM_SHARED_EVENT); 59 if (!m_hTerminateEngineEvent) 60 { 61 Logger::error(L"Failed to create terminate Engine event"); 62 auto message = get_last_error_message(GetLastError()); 63 if (message.has_value()) 64 { 65 Logger::error(message.value()); 66 } 67 } 68 }; 69 70 // Destroy the powertoy and free memory 71 virtual void destroy() override 72 { 73 delete this; 74 } 75 76 // Return the localized display name of the powertoy 77 virtual const wchar_t* get_name() override 78 { 79 return app_name.c_str(); 80 } 81 82 // Return the non localized key of the powertoy, this will be cached by the runner 83 virtual const wchar_t* get_key() override 84 { 85 return app_key.c_str(); 86 } 87 88 // Return the configured status for the gpo policy for the module 89 virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override 90 { 91 return powertoys_gpo::getConfiguredKeyboardManagerEnabledValue(); 92 } 93 94 // Return JSON with the configuration options. 95 virtual bool get_config(wchar_t* buffer, int* buffer_size) override 96 { 97 HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase); 98 99 // Create a Settings object. 100 PowerToysSettings::Settings settings(hinstance, get_name()); 101 settings.set_description(IDS_SETTINGS_DESCRIPTION); 102 settings.set_overview_link(L"https://aka.ms/PowerToysOverview_KeyboardManager"); 103 104 return settings.serialize_to_buffer(buffer, buffer_size); 105 } 106 107 // Signal from the Settings editor to call a custom action. 108 virtual void call_custom_action(const wchar_t* /*action*/) override 109 { 110 } 111 112 // Called by the runner to pass the updated settings values as a serialized JSON. 113 virtual void set_config(const wchar_t* config) override 114 { 115 try 116 { 117 // Parse the input JSON string. 118 PowerToysSettings::PowerToyValues values = 119 PowerToysSettings::PowerToyValues::from_json_string(config, get_key()); 120 121 // If you don't need to do any custom processing of the settings, proceed 122 // to persists the values calling: 123 values.save_to_settings_file(); 124 } 125 catch (std::exception&) 126 { 127 // Improper JSON. 128 } 129 } 130 131 // Enable the powertoy 132 virtual void enable() 133 { 134 m_enabled = true; 135 // Log telemetry 136 Trace::EnableKeyboardManager(true); 137 138 unsigned long powertoys_pid = GetCurrentProcessId(); 139 std::wstring executable_args = L""; 140 executable_args.append(std::to_wstring(powertoys_pid)); 141 142 SHELLEXECUTEINFOW sei{ sizeof(sei) }; 143 sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI }; 144 sei.lpFile = L"KeyboardManagerEngine\\PowerToys.KeyboardManagerEngine.exe"; 145 sei.nShow = SW_SHOWNORMAL; 146 sei.lpParameters = executable_args.data(); 147 if (ShellExecuteExW(&sei) == false) 148 { 149 Logger::error(L"Failed to start keyboard manager engine"); 150 auto message = get_last_error_message(GetLastError()); 151 if (message.has_value()) 152 { 153 Logger::error(message.value()); 154 } 155 } 156 else 157 { 158 m_hProcess = sei.hProcess; 159 if (m_hProcess) 160 { 161 SetPriorityClass(m_hProcess, REALTIME_PRIORITY_CLASS); 162 } 163 } 164 } 165 166 // Disable the powertoy 167 virtual void disable() 168 { 169 m_enabled = false; 170 // Log telemetry 171 Trace::EnableKeyboardManager(false); 172 173 if (m_hProcess) 174 { 175 SetEvent(m_hTerminateEngineEvent); 176 WaitForSingleObject(m_hProcess, 1500); 177 178 TerminateProcess(m_hProcess, 0); 179 m_hProcess = nullptr; 180 } 181 } 182 183 // Returns if the powertoys is enabled 184 virtual bool is_enabled() override 185 { 186 return m_enabled; 187 } 188 189 // Returns whether the PowerToys should be enabled by default 190 virtual bool is_enabled_by_default() const override 191 { 192 return false; 193 } 194 195 }; 196 197 extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create() 198 { 199 return new KeyboardManager(); 200 }