settings_window.cpp
1 #include "pch.h" 2 #include <WinSafer.h> 3 #include <Sddl.h> 4 #include <sstream> 5 #include <aclapi.h> 6 7 #include "powertoy_module.h" 8 #include <common/interop/two_way_pipe_message_ipc.h> 9 #include <common/interop/shared_constants.h> 10 #include "tray_icon.h" 11 #include "general_settings.h" 12 #include "restart_elevated.h" 13 #include "UpdateUtils.h" 14 #include "centralized_kb_hook.h" 15 #include "Generated files/resource.h" 16 #include "hotkey_conflict_detector.h" 17 18 #include <common/utils/json.h> 19 #include <common/SettingsAPI/settings_helpers.cpp> 20 #include <common/version/version.h> 21 #include <common/version/helper.h> 22 #include <common/logger/logger.h> 23 #include <common/utils/resources.h> 24 #include <common/utils/elevation.h> 25 #include <common/utils/process_path.h> 26 #include <common/utils/timeutil.h> 27 #include <common/utils/winapi_error.h> 28 #include <common/updating/updateState.h> 29 #include <common/themes/windows_colors.h> 30 #include "settings_window.h" 31 #include "bug_report.h" 32 33 #define BUFSIZE 1024 34 35 TwoWayPipeMessageIPC* current_settings_ipc = NULL; 36 std::mutex ipc_mutex; 37 std::atomic_bool g_isLaunchInProgress = false; 38 std::atomic_bool isUpdateCheckThreadRunning = false; 39 HANDLE g_terminateSettingsEvent = CreateEventW(nullptr, false, false, CommonSharedConstants::TERMINATE_SETTINGS_SHARED_EVENT); 40 41 json::JsonObject get_power_toys_settings() 42 { 43 json::JsonObject result; 44 for (const auto& [name, powertoy] : modules()) 45 { 46 try 47 { 48 result.SetNamedValue(name, powertoy.json_config()); 49 } 50 catch (...) 51 { 52 Logger::error(L"get_power_toys_settings(): got malformed json for {} module", name); 53 } 54 } 55 return result; 56 } 57 58 json::JsonObject get_all_settings() 59 { 60 json::JsonObject result; 61 62 result.SetNamedValue(L"general", get_general_settings().to_json()); 63 result.SetNamedValue(L"powertoys", get_power_toys_settings()); 64 return result; 65 } 66 67 std::optional<std::wstring> dispatch_json_action_to_module(const json::JsonObject& powertoys_configs) 68 { 69 std::optional<std::wstring> result; 70 for (const auto& powertoy_element : powertoys_configs) 71 { 72 const std::wstring name{ powertoy_element.Key().c_str() }; 73 // Currently, there is only one custom action in the general settings screen, 74 // so it has to be the "restart as (non-)elevated" button. 75 if (name == L"general") 76 { 77 try 78 { 79 const auto value = powertoy_element.Value().GetObjectW(); 80 const auto action = value.GetNamedString(L"action_name"); 81 if (action == L"restart_elevation") 82 { 83 if (is_process_elevated()) 84 { 85 schedule_restart_as_non_elevated(); 86 PostQuitMessage(0); 87 } 88 else 89 { 90 schedule_restart_as_elevated(true); 91 PostQuitMessage(0); 92 } 93 } 94 else if (action == L"restart_maintain_elevation") 95 { 96 // this was added to restart and maintain elevation, which is needed after settings are change from outside the normal process. 97 // since a normal PostQuitMessage(0) would usually cause this process to save its in memory settings to disk, we need to 98 // send a PostQuitMessage(1) and check for that on exit, and skip the settings-flush. 99 auto loaded = PTSettingsHelper::load_general_settings(); 100 101 if (is_process_elevated()) 102 { 103 schedule_restart_as_elevated(true); 104 PostQuitMessage(1); 105 } 106 else 107 { 108 schedule_restart_as_non_elevated(true); 109 PostQuitMessage(1); 110 } 111 } 112 else if (action == L"check_for_updates") 113 { 114 bool expected_isUpdateCheckThreadRunning = false; 115 if (isUpdateCheckThreadRunning.compare_exchange_strong(expected_isUpdateCheckThreadRunning, true)) 116 { 117 std::thread([]() { 118 CheckForUpdatesCallback(); 119 isUpdateCheckThreadRunning.store(false); 120 }).detach(); 121 } 122 } 123 else if (action == L"request_update_state_date") 124 { 125 json::JsonObject json; 126 127 auto update_state = UpdateState::read(); 128 if (update_state.githubUpdateLastCheckedDate) 129 { 130 const time_t date = *update_state.githubUpdateLastCheckedDate; 131 json.SetNamedValue(L"updateStateDate", json::value(std::to_wstring(date))); 132 } 133 134 result.emplace(json.Stringify()); 135 } 136 } 137 catch (...) 138 { 139 } 140 } 141 else if (modules().find(name) != modules().end()) 142 { 143 const auto element = powertoy_element.Value().Stringify(); 144 modules().at(name)->call_custom_action(element.c_str()); 145 } 146 } 147 148 return result; 149 } 150 151 void send_json_config_to_module(const std::wstring& module_key, const std::wstring& settings, bool hotkeyUpdated) 152 { 153 auto moduleIt = modules().find(module_key); 154 if (moduleIt != modules().end()) 155 { 156 moduleIt->second->set_config(settings.c_str()); 157 158 if (hotkeyUpdated) 159 { 160 moduleIt->second.remove_hotkey_records(); 161 moduleIt->second.update_hotkeys(); 162 moduleIt->second.UpdateHotkeyEx(); 163 } 164 } 165 } 166 167 void dispatch_json_config_to_modules(const json::JsonObject& powertoys_configs) 168 { 169 for (const auto& powertoy_element : powertoys_configs) 170 { 171 const auto element = powertoy_element.Value().Stringify(); 172 173 /* As PowerToys Run hotkeys are not registered by the runner, hotkey updates are 174 * triggered only when hotkey properties change to avoid incorrect conflict detection; 175 * otherwise, the existing logic remains. 176 */ 177 auto settings = powertoy_element.Value().GetObjectW(); 178 bool hotkeyUpdated = true; 179 if (settings.HasKey(L"properties")) 180 { 181 const auto properties = settings.GetNamedObject(L"properties"); 182 183 // Currently, only PowerToys Run settings use the 'hotkey_changed' property. 184 if (properties.HasKey(L"hotkey_changed")) 185 { 186 json::get(properties, L"hotkey_changed", hotkeyUpdated, true); 187 } 188 } 189 190 send_json_config_to_module(powertoy_element.Key().c_str(), element.c_str(), hotkeyUpdated); 191 } 192 }; 193 194 void dispatch_received_json(const std::wstring& json_to_parse) 195 { 196 json::JsonObject j; 197 const bool ok = json::JsonObject::TryParse(json_to_parse, j); 198 if (!ok) 199 { 200 Logger::error(L"dispatch_received_json: got malformed json: {}", json_to_parse); 201 return; 202 } 203 204 Logger::info(L"dispatch_received_json: {}", json_to_parse); 205 206 for (const auto& base_element : j) 207 { 208 const auto name = base_element.Key(); 209 const auto value = base_element.Value(); 210 211 if (name == L"general") 212 { 213 apply_general_settings(value.GetObjectW()); 214 // const std::wstring settings_string{ get_all_settings().Stringify().c_str() }; 215 // { 216 // std::unique_lock lock{ ipc_mutex }; 217 // if (current_settings_ipc) 218 // current_settings_ipc->send(settings_string); 219 // } 220 } 221 else if (name == L"module_status") 222 { 223 // Handle single module enable/disable update 224 // Expected format: {"module_status": {"ModuleName": true/false}} 225 apply_module_status_update(value.GetObjectW()); 226 } 227 else if (name == L"powertoys") 228 { 229 dispatch_json_config_to_modules(value.GetObjectW()); 230 const std::wstring settings_string{ get_all_settings().Stringify().c_str() }; 231 { 232 std::unique_lock lock{ ipc_mutex }; 233 if (current_settings_ipc) 234 current_settings_ipc->send(settings_string); 235 } 236 } 237 else if (name == L"refresh") 238 { 239 const std::wstring settings_string{ get_all_settings().Stringify().c_str() }; 240 { 241 std::unique_lock lock{ ipc_mutex }; 242 if (current_settings_ipc) 243 current_settings_ipc->send(settings_string); 244 } 245 } 246 else if (name == L"action") 247 { 248 auto result = dispatch_json_action_to_module(value.GetObjectW()); 249 if (result.has_value()) 250 { 251 { 252 std::unique_lock lock{ ipc_mutex }; 253 if (current_settings_ipc) 254 current_settings_ipc->send(result.value()); 255 } 256 } 257 } 258 else if (name == L"bugreport") 259 { 260 launch_bug_report(); 261 } 262 else if (name == L"bug_report_status") 263 { 264 json::JsonObject result; 265 result.SetNamedValue(L"bug_report_running", winrt::Windows::Data::Json::JsonValue::CreateBooleanValue(is_bug_report_running())); 266 std::unique_lock lock{ ipc_mutex }; 267 if (current_settings_ipc) 268 current_settings_ipc->send(result.Stringify().c_str()); 269 } 270 else if (name == L"killrunner") 271 { 272 const auto pt_main_window = FindWindowW(pt_tray_icon_window_class, nullptr); 273 if (pt_main_window != nullptr) 274 { 275 SendMessageW(pt_main_window, WM_CLOSE, 0, 0); 276 } 277 } 278 else if (name == L"language") 279 { 280 constexpr const wchar_t* language_filename = L"\\language.json"; 281 const std::wstring save_file_location = PTSettingsHelper::get_root_save_folder_location() + language_filename; 282 json::to_file(save_file_location, j); 283 } 284 else if (name == L"check_hotkey_conflict") 285 { 286 try 287 { 288 PowertoyModuleIface::Hotkey hotkey; 289 hotkey.win = value.GetObjectW().GetNamedBoolean(L"win", false); 290 hotkey.ctrl = value.GetObjectW().GetNamedBoolean(L"ctrl", false); 291 hotkey.shift = value.GetObjectW().GetNamedBoolean(L"shift", false); 292 hotkey.alt = value.GetObjectW().GetNamedBoolean(L"alt", false); 293 hotkey.key = static_cast<unsigned char>(value.GetObjectW().GetNamedNumber(L"key", 0)); 294 295 std::wstring requestId = value.GetObjectW().GetNamedString(L"request_id", L"").c_str(); 296 297 auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); 298 bool hasConflict = hkmng.HasConflict(hotkey); 299 300 json::JsonObject response; 301 response.SetNamedValue(L"response_type", json::JsonValue::CreateStringValue(L"hotkey_conflict_result")); 302 response.SetNamedValue(L"request_id", json::JsonValue::CreateStringValue(requestId)); 303 response.SetNamedValue(L"has_conflict", json::JsonValue::CreateBooleanValue(hasConflict)); 304 305 if (hasConflict) 306 { 307 auto conflicts = hkmng.GetAllConflicts(hotkey); 308 if (!conflicts.empty()) 309 { 310 // Include all conflicts in the response 311 json::JsonArray allConflicts; 312 for (const auto& conflict : conflicts) 313 { 314 json::JsonObject conflictObj; 315 conflictObj.SetNamedValue(L"module", json::JsonValue::CreateStringValue(conflict.moduleName)); 316 conflictObj.SetNamedValue(L"hotkeyID", json::JsonValue::CreateNumberValue(conflict.hotkeyID)); 317 allConflicts.Append(conflictObj); 318 } 319 response.SetNamedValue(L"all_conflicts", allConflicts); 320 } 321 } 322 323 std::unique_lock lock{ ipc_mutex }; 324 if (current_settings_ipc) 325 { 326 current_settings_ipc->send(response.Stringify().c_str()); 327 } 328 } 329 catch (...) 330 { 331 Logger::error(L"Failed to process hotkey conflict check request"); 332 } 333 } 334 else if (name == L"get_all_hotkey_conflicts") 335 { 336 try 337 { 338 auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); 339 auto conflictsJson = hkmng.GetHotkeyConflictsAsJson(); 340 341 // Add response type identifier 342 conflictsJson.SetNamedValue(L"response_type", json::JsonValue::CreateStringValue(L"all_hotkey_conflicts")); 343 344 std::unique_lock lock{ ipc_mutex }; 345 if (current_settings_ipc) 346 { 347 current_settings_ipc->send(conflictsJson.Stringify().c_str()); 348 } 349 } 350 catch (...) 351 { 352 Logger::error(L"Failed to process get all hotkey conflicts request"); 353 } 354 } 355 } 356 return; 357 } 358 359 void dispatch_received_json_callback(PVOID data) 360 { 361 std::wstring* msg = static_cast<std::wstring*>(data); 362 dispatch_received_json(*msg); 363 delete msg; 364 } 365 366 void receive_json_send_to_main_thread(const std::wstring& msg) 367 { 368 std::wstring* copy = new std::wstring(msg); 369 dispatch_run_on_main_ui_thread(dispatch_received_json_callback, copy); 370 } 371 372 // Try to run the Settings process with non-elevated privileges. 373 BOOL run_settings_non_elevated(LPCWSTR executable_path, LPWSTR executable_args, PROCESS_INFORMATION* process_info) 374 { 375 HWND hwnd = GetShellWindow(); 376 if (!hwnd) 377 { 378 return false; 379 } 380 381 DWORD pid; 382 GetWindowThreadProcessId(hwnd, &pid); 383 384 winrt::handle process{ OpenProcess(PROCESS_CREATE_PROCESS, FALSE, pid) }; 385 if (!process) 386 { 387 return false; 388 } 389 390 SIZE_T size = 0; 391 InitializeProcThreadAttributeList(nullptr, 1, 0, &size); 392 auto pproc_buffer = std::unique_ptr<char[]>{ new (std::nothrow) char[size] }; 393 auto pptal = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(pproc_buffer.get()); 394 if (!pptal) 395 { 396 return false; 397 } 398 399 if (!InitializeProcThreadAttributeList(pptal, 1, 0, &size)) 400 { 401 return false; 402 } 403 404 if (!UpdateProcThreadAttribute(pptal, 405 0, 406 PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, 407 &process, 408 sizeof(process), 409 nullptr, 410 nullptr)) 411 { 412 return false; 413 } 414 415 STARTUPINFOEX siex = { 0 }; 416 siex.lpAttributeList = pptal; 417 siex.StartupInfo.cb = sizeof(siex); 418 419 BOOL process_created = CreateProcessW(executable_path, 420 executable_args, 421 nullptr, 422 nullptr, 423 FALSE, 424 EXTENDED_STARTUPINFO_PRESENT, 425 nullptr, 426 nullptr, 427 &siex.StartupInfo, 428 process_info); 429 g_isLaunchInProgress = false; 430 return process_created; 431 } 432 433 DWORD g_settings_process_id = 0; 434 435 void run_settings_window(bool show_oobe_window, bool show_scoobe_window, std::optional<std::wstring> settings_window) 436 { 437 g_isLaunchInProgress = true; 438 439 PROCESS_INFORMATION process_info = { 0 }; 440 HANDLE hToken = nullptr; 441 442 // Arguments for calling the settings executable: 443 // "C:\powertoys_path\PowerToysSettings.exe" powertoys_pipe settings_pipe powertoys_pid settings_theme 444 // powertoys_pipe: PowerToys pipe server. 445 // settings_pipe : Settings pipe server. 446 // powertoys_pid : PowerToys process pid. 447 // settings_theme: pass "dark" to start the settings window in dark mode 448 449 // Arg 1: executable path. 450 std::wstring executable_path = get_module_folderpath(); 451 452 executable_path.append(L"\\WinUI3Apps\\PowerToys.Settings.exe"); 453 454 // Args 2,3: pipe server. Generate unique names for the pipes, if getting a UUID is possible. 455 std::wstring powertoys_pipe_name(L"\\\\.\\pipe\\powertoys_runner_"); 456 std::wstring settings_pipe_name(L"\\\\.\\pipe\\powertoys_settings_"); 457 UUID temp_uuid; 458 wchar_t* uuid_chars = nullptr; 459 if (UuidCreate(&temp_uuid) == RPC_S_UUID_NO_ADDRESS) 460 { 461 auto val = get_last_error_message(GetLastError()); 462 Logger::warn(L"UuidCreate cannot create guid. {}", val.has_value() ? val.value() : L""); 463 } 464 else if (UuidToString(&temp_uuid, reinterpret_cast<RPC_WSTR*>(&uuid_chars)) != RPC_S_OK) 465 { 466 auto val = get_last_error_message(GetLastError()); 467 Logger::warn(L"UuidToString cannot convert to string. {}", val.has_value() ? val.value() : L""); 468 } 469 470 if (uuid_chars != nullptr) 471 { 472 powertoys_pipe_name += std::wstring(uuid_chars); 473 settings_pipe_name += std::wstring(uuid_chars); 474 RpcStringFree(reinterpret_cast<RPC_WSTR*>(&uuid_chars)); 475 uuid_chars = nullptr; 476 } 477 478 // Arg 4: process pid. 479 DWORD powertoys_pid = GetCurrentProcessId(); 480 481 GeneralSettings save_settings = get_general_settings(); 482 483 // Arg 5: settings theme. 484 const std::wstring settings_theme_setting{ save_settings.theme }; 485 std::wstring settings_theme = L"system"; 486 if (settings_theme_setting == L"dark" || (settings_theme_setting == L"system" && WindowsColors::is_dark_mode())) 487 { 488 settings_theme = L"dark"; 489 } 490 491 // Arg 6: elevated status 492 bool isElevated{ save_settings.isElevated }; 493 std::wstring settings_elevatedStatus = isElevated ? L"true" : L"false"; 494 495 // Arg 7: is user an admin 496 bool isAdmin{ save_settings.isAdmin }; 497 std::wstring settings_isUserAnAdmin = isAdmin ? L"true" : L"false"; 498 499 // Arg 8: should oobe window be shown 500 std::wstring settings_showOobe = show_oobe_window ? L"true" : L"false"; 501 502 // Arg 9: should scoobe window be shown 503 std::wstring settings_showScoobe = show_scoobe_window ? L"true" : L"false"; 504 505 // Arg 10: contains if there's a settings window argument. If true, will add one extra argument with the value to the call. 506 std::wstring settings_containsSettingsWindow = settings_window.has_value() ? L"true" : L"false"; 507 508 // Args 11, .... : Optional arguments depending on the options presented before. All by the same value. 509 510 // create general settings file to initialize the settings file with installation configurations like : 511 // 1. Run on start up. 512 PTSettingsHelper::save_general_settings(save_settings.to_json()); 513 514 std::wstring executable_args = fmt::format(L"\"{}\" {} {} {} {} {} {} {} {} {}", 515 executable_path, 516 powertoys_pipe_name, 517 settings_pipe_name, 518 std::to_wstring(powertoys_pid), 519 settings_theme, 520 settings_elevatedStatus, 521 settings_isUserAnAdmin, 522 settings_showOobe, 523 settings_showScoobe, 524 settings_containsSettingsWindow); 525 526 if (settings_window.has_value()) 527 { 528 executable_args.append(L" "); 529 executable_args.append(settings_window.value()); 530 } 531 532 BOOL process_created = false; 533 534 // Commented out to fix #22659 535 // Running settings non-elevated and modules elevated when PowerToys is running elevated results 536 // in settings making changes in one file (non-elevated user dir) and modules are reading settings 537 // from different (elevated user) dir 538 //if (is_process_elevated()) 539 //{ 540 541 // auto res = RunNonElevatedFailsafe(executable_path, executable_args, get_module_folderpath()); 542 // process_created = res.has_value(); 543 // if (process_created) 544 // { 545 // process_info.dwProcessId = res->processID; 546 // process_info.hProcess = res->processHandle.release(); 547 // g_isLaunchInProgress = false; 548 // } 549 //} 550 551 if (FALSE == process_created) 552 { 553 // The runner is not elevated or we failed to create the process using the 554 // attribute list from Windows Explorer (this happens when PowerToys is executed 555 // as Administrator from a non-Administrator user or an error occur trying). 556 // In the second case the Settings process will run elevated. 557 STARTUPINFO startup_info = { sizeof(startup_info) }; 558 if (!CreateProcessW(executable_path.c_str(), 559 executable_args.data(), 560 nullptr, 561 nullptr, 562 FALSE, 563 0, 564 nullptr, 565 nullptr, 566 &startup_info, 567 &process_info)) 568 { 569 goto LExit; 570 } 571 else 572 { 573 g_isLaunchInProgress = false; 574 } 575 } 576 577 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) 578 { 579 goto LExit; 580 } 581 582 { 583 std::unique_lock lock{ ipc_mutex }; 584 current_settings_ipc = new TwoWayPipeMessageIPC(powertoys_pipe_name, settings_pipe_name, receive_json_send_to_main_thread); 585 current_settings_ipc->start(hToken); 586 587 // Register callback for bug report status changes 588 BugReportManager::instance().register_callback([](bool isRunning) { 589 json::JsonObject result; 590 result.SetNamedValue(L"bug_report_running", winrt::Windows::Data::Json::JsonValue::CreateBooleanValue(isRunning)); 591 592 std::unique_lock lock{ ipc_mutex }; 593 if (current_settings_ipc) 594 current_settings_ipc->send(result.Stringify().c_str()); 595 }); 596 } 597 598 g_settings_process_id = process_info.dwProcessId; 599 600 if (process_info.hProcess) 601 { 602 WaitForSingleObject(process_info.hProcess, INFINITE); 603 if (WaitForSingleObject(process_info.hProcess, INFINITE) != WAIT_OBJECT_0) 604 { 605 show_last_error_message(L"Couldn't wait on the Settings Window to close.", GetLastError(), L"PowerToys - runner"); 606 } 607 } 608 else 609 { 610 auto val = get_last_error_message(GetLastError()); 611 Logger::error(L"Process handle is empty. {}", val.has_value() ? val.value() : L""); 612 } 613 614 LExit: 615 616 if (process_info.hProcess) 617 { 618 CloseHandle(process_info.hProcess); 619 } 620 621 if (process_info.hThread) 622 { 623 CloseHandle(process_info.hThread); 624 } 625 { 626 std::unique_lock lock{ ipc_mutex }; 627 if (current_settings_ipc) 628 { 629 current_settings_ipc->end(); 630 delete current_settings_ipc; 631 current_settings_ipc = nullptr; 632 } 633 } 634 635 if (hToken) 636 { 637 CloseHandle(hToken); 638 } 639 640 g_settings_process_id = 0; 641 } 642 643 #define MAX_TITLE_LENGTH 100 644 void bring_settings_to_front() 645 { 646 auto callback = [](HWND hwnd, LPARAM /*data*/) -> BOOL { 647 DWORD processId; 648 if (GetWindowThreadProcessId(hwnd, &processId) && processId == g_settings_process_id) 649 { 650 std::wstring windowTitle = L"PowerToys Settings"; 651 652 WCHAR title[MAX_TITLE_LENGTH]; 653 int len = GetWindowTextW(hwnd, title, MAX_TITLE_LENGTH); 654 if (len <= 0) 655 { 656 return TRUE; 657 } 658 if (wcsncmp(title, windowTitle.c_str(), len) == 0) 659 { 660 auto lStyles = GetWindowLong(hwnd, GWL_STYLE); 661 662 if (lStyles & WS_MAXIMIZE) 663 { 664 ShowWindow(hwnd, SW_MAXIMIZE); 665 } 666 else 667 { 668 ShowWindow(hwnd, SW_RESTORE); 669 } 670 671 SetForegroundWindow(hwnd); 672 return FALSE; 673 } 674 } 675 676 return TRUE; 677 }; 678 679 EnumWindows(callback, 0); 680 } 681 682 void open_settings_window(std::optional<std::wstring> settings_window) 683 { 684 if (g_settings_process_id != 0) 685 { 686 // nl instead of showing the window, send message to it (flyout might need to be hidden, main setting window activated) 687 // bring_settings_to_front(); 688 if (current_settings_ipc) 689 { 690 if (settings_window.has_value()) 691 { 692 std::wstring msg = L"{\"ShowYourself\":\"" + settings_window.value() + L"\"}"; 693 current_settings_ipc->send(msg); 694 } 695 else 696 { 697 current_settings_ipc->send(L"{\"ShowYourself\":\"Dashboard\"}"); 698 } 699 } 700 } 701 else 702 { 703 if (!g_isLaunchInProgress) 704 { 705 std::thread([settings_window]() { 706 run_settings_window(false, false, settings_window); 707 }).detach(); 708 } 709 } 710 } 711 712 void close_settings_window() 713 { 714 if (g_settings_process_id != 0) 715 { 716 SetEvent(g_terminateSettingsEvent); 717 wil::unique_handle proc{ OpenProcess(PROCESS_ALL_ACCESS, false, g_settings_process_id) }; 718 if (proc) 719 { 720 WaitForSingleObject(proc.get(), 1500); 721 TerminateProcess(proc.get(), 0); 722 } 723 } 724 } 725 726 void open_oobe_window() 727 { 728 std::thread([]() { 729 run_settings_window(true, false, std::nullopt); 730 }).detach(); 731 } 732 733 void open_scoobe_window() 734 { 735 std::thread([]() { 736 run_settings_window(false, true, std::nullopt); 737 }).detach(); 738 } 739 740 std::string ESettingsWindowNames_to_string(ESettingsWindowNames value) 741 { 742 switch (value) 743 { 744 case ESettingsWindowNames::Dashboard: 745 return "Dashboard"; 746 case ESettingsWindowNames::Overview: 747 return "Overview"; 748 case ESettingsWindowNames::AlwaysOnTop: 749 return "AlwaysOnTop"; 750 case ESettingsWindowNames::Awake: 751 return "Awake"; 752 case ESettingsWindowNames::ColorPicker: 753 return "ColorPicker"; 754 case ESettingsWindowNames::CmdNotFound: 755 return "CmdNotFound"; 756 case ESettingsWindowNames::LightSwitch: 757 return "LightSwitch"; 758 case ESettingsWindowNames::FancyZones: 759 return "FancyZones"; 760 case ESettingsWindowNames::FileLocksmith: 761 return "FileLocksmith"; 762 case ESettingsWindowNames::Run: 763 return "Run"; 764 case ESettingsWindowNames::ImageResizer: 765 return "ImageResizer"; 766 case ESettingsWindowNames::KBM: 767 return "KBM"; 768 case ESettingsWindowNames::MouseUtils: 769 return "MouseUtils"; 770 case ESettingsWindowNames::MouseWithoutBorders: 771 return "MouseWithoutBorders"; 772 case ESettingsWindowNames::Peek: 773 return "Peek"; 774 case ESettingsWindowNames::PowerAccent: 775 return "PowerAccent"; 776 case ESettingsWindowNames::PowerLauncher: 777 return "PowerLauncher"; 778 case ESettingsWindowNames::PowerPreview: 779 return "PowerPreview"; 780 case ESettingsWindowNames::PowerRename: 781 return "PowerRename"; 782 case ESettingsWindowNames::FileExplorer: 783 return "FileExplorer"; 784 case ESettingsWindowNames::ShortcutGuide: 785 return "ShortcutGuide"; 786 case ESettingsWindowNames::Hosts: 787 return "Hosts"; 788 case ESettingsWindowNames::MeasureTool: 789 return "MeasureTool"; 790 case ESettingsWindowNames::PowerOCR: 791 return "PowerOcr"; 792 case ESettingsWindowNames::Workspaces: 793 return "Workspaces"; 794 case ESettingsWindowNames::RegistryPreview: 795 return "RegistryPreview"; 796 case ESettingsWindowNames::CropAndLock: 797 return "CropAndLock"; 798 case ESettingsWindowNames::EnvironmentVariables: 799 return "EnvironmentVariables"; 800 case ESettingsWindowNames::AdvancedPaste: 801 return "AdvancedPaste"; 802 case ESettingsWindowNames::NewPlus: 803 return "NewPlus"; 804 case ESettingsWindowNames::CmdPal: 805 return "CmdPal"; 806 case ESettingsWindowNames::ZoomIt: 807 return "ZoomIt"; 808 case ESettingsWindowNames::PowerDisplay: 809 return "PowerDisplay"; 810 default: 811 { 812 Logger::error(L"Can't convert ESettingsWindowNames value={} to string", static_cast<int>(value)); 813 assert(false); 814 } 815 } 816 return ""; 817 } 818 819 ESettingsWindowNames ESettingsWindowNames_from_string(std::string value) 820 { 821 if (value == "Dashboard") 822 { 823 return ESettingsWindowNames::Dashboard; 824 } 825 else if (value == "Overview") 826 { 827 return ESettingsWindowNames::Overview; 828 } 829 else if (value == "AlwaysOnTop") 830 { 831 return ESettingsWindowNames::AlwaysOnTop; 832 } 833 else if (value == "Awake") 834 { 835 return ESettingsWindowNames::Awake; 836 } 837 else if (value == "ColorPicker") 838 { 839 return ESettingsWindowNames::ColorPicker; 840 } 841 else if (value == "CmdNotFound") 842 { 843 return ESettingsWindowNames::CmdNotFound; 844 } 845 else if (value == "LightSwitch") 846 { 847 return ESettingsWindowNames::LightSwitch; 848 } 849 else if (value == "FancyZones") 850 { 851 return ESettingsWindowNames::FancyZones; 852 } 853 else if (value == "FileLocksmith") 854 { 855 return ESettingsWindowNames::FileLocksmith; 856 } 857 else if (value == "Run") 858 { 859 return ESettingsWindowNames::Run; 860 } 861 else if (value == "ImageResizer") 862 { 863 return ESettingsWindowNames::ImageResizer; 864 } 865 else if (value == "KBM") 866 { 867 return ESettingsWindowNames::KBM; 868 } 869 else if (value == "MouseUtils") 870 { 871 return ESettingsWindowNames::MouseUtils; 872 } 873 else if (value == "MouseWithoutBorders") 874 { 875 return ESettingsWindowNames::MouseWithoutBorders; 876 } 877 else if (value == "Peek") 878 { 879 return ESettingsWindowNames::Peek; 880 } 881 else if (value == "PowerAccent") 882 { 883 return ESettingsWindowNames::PowerAccent; 884 } 885 else if (value == "PowerLauncher") 886 { 887 return ESettingsWindowNames::PowerLauncher; 888 } 889 else if (value == "PowerPreview") 890 { 891 return ESettingsWindowNames::PowerPreview; 892 } 893 else if (value == "PowerRename") 894 { 895 return ESettingsWindowNames::PowerRename; 896 } 897 else if (value == "FileExplorer") 898 { 899 return ESettingsWindowNames::FileExplorer; 900 } 901 else if (value == "ShortcutGuide") 902 { 903 return ESettingsWindowNames::ShortcutGuide; 904 } 905 else if (value == "Hosts") 906 { 907 return ESettingsWindowNames::Hosts; 908 } 909 else if (value == "MeasureTool") 910 { 911 return ESettingsWindowNames::MeasureTool; 912 } 913 else if (value == "PowerOcr") 914 { 915 return ESettingsWindowNames::PowerOCR; 916 } 917 else if (value == "Workspaces") 918 { 919 return ESettingsWindowNames::Workspaces; 920 } 921 else if (value == "RegistryPreview") 922 { 923 return ESettingsWindowNames::RegistryPreview; 924 } 925 else if (value == "CropAndLock") 926 { 927 return ESettingsWindowNames::CropAndLock; 928 } 929 else if (value == "EnvironmentVariables") 930 { 931 return ESettingsWindowNames::EnvironmentVariables; 932 } 933 else if (value == "AdvancedPaste") 934 { 935 return ESettingsWindowNames::AdvancedPaste; 936 } 937 else if (value == "NewPlus") 938 { 939 return ESettingsWindowNames::NewPlus; 940 } 941 else if (value == "CmdPal") 942 { 943 return ESettingsWindowNames::CmdPal; 944 } 945 else if (value == "ZoomIt") 946 { 947 return ESettingsWindowNames::ZoomIt; 948 } 949 else if (value == "PowerDisplay") 950 { 951 return ESettingsWindowNames::PowerDisplay; 952 } 953 else 954 { 955 Logger::error(L"Can't convert string value={} to ESettingsWindowNames", winrt::to_hstring(value)); 956 assert(false); 957 } 958 959 return ESettingsWindowNames::Dashboard; 960 }