diff --git a/PowerToys.slnx b/PowerToys.slnx index e0bbf9820d..53eb43de15 100644 --- a/PowerToys.slnx +++ b/PowerToys.slnx @@ -1028,25 +1028,7 @@ - - - - - - - - - - - - - - - - - - - + diff --git a/src/RunnerV2/RunnerV2/Assets/PowerToysDark.ico b/src/Runner/Assets/PowerToysDark.ico similarity index 100% rename from src/RunnerV2/RunnerV2/Assets/PowerToysDark.ico rename to src/Runner/Assets/PowerToysDark.ico diff --git a/src/RunnerV2/RunnerV2/Assets/PowerToysLight.ico b/src/Runner/Assets/PowerToysLight.ico similarity index 100% rename from src/RunnerV2/RunnerV2/Assets/PowerToysLight.ico rename to src/Runner/Assets/PowerToysLight.ico diff --git a/src/RunnerV2/RunnerV2/Extensions/PackageVersionExtensions.cs b/src/Runner/Extensions/PackageVersionExtensions.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Extensions/PackageVersionExtensions.cs rename to src/Runner/Extensions/PackageVersionExtensions.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/AIHelper.cs b/src/Runner/Helpers/AIHelper.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/AIHelper.cs rename to src/Runner/Helpers/AIHelper.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/AutoStartHelper.cs b/src/Runner/Helpers/AutoStartHelper.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/AutoStartHelper.cs rename to src/Runner/Helpers/AutoStartHelper.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/COMUtils.cs b/src/Runner/Helpers/COMUtils.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/COMUtils.cs rename to src/Runner/Helpers/COMUtils.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/CentralizedKeyboardHookManager.cs b/src/Runner/Helpers/CentralizedKeyboardHookManager.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/CentralizedKeyboardHookManager.cs rename to src/Runner/Helpers/CentralizedKeyboardHookManager.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/ElevationHelper.cs b/src/Runner/Helpers/ElevationHelper.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/ElevationHelper.cs rename to src/Runner/Helpers/ElevationHelper.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/HotkeyConflictsManager.cs b/src/Runner/Helpers/HotkeyConflictsManager.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/HotkeyConflictsManager.cs rename to src/Runner/Helpers/HotkeyConflictsManager.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/NotificationHelper.cs b/src/Runner/Helpers/NotificationHelper.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/NotificationHelper.cs rename to src/Runner/Helpers/NotificationHelper.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/PackageHelper.cs b/src/Runner/Helpers/PackageHelper.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/PackageHelper.cs rename to src/Runner/Helpers/PackageHelper.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/ProcessHelper.cs b/src/Runner/Helpers/ProcessHelper.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/ProcessHelper.cs rename to src/Runner/Helpers/ProcessHelper.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/QuickAccessHelper.cs b/src/Runner/Helpers/QuickAccessHelper.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/QuickAccessHelper.cs rename to src/Runner/Helpers/QuickAccessHelper.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/SettingsHelper.cs b/src/Runner/Helpers/SettingsHelper.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/SettingsHelper.cs rename to src/Runner/Helpers/SettingsHelper.cs diff --git a/src/RunnerV2/RunnerV2/Helpers/TrayIconManager.cs b/src/Runner/Helpers/TrayIconManager.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Helpers/TrayIconManager.cs rename to src/Runner/Helpers/TrayIconManager.cs diff --git a/src/RunnerV2/RunnerV2/Models/IPowerToysModule.cs b/src/Runner/Models/IPowerToysModule.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Models/IPowerToysModule.cs rename to src/Runner/Models/IPowerToysModule.cs diff --git a/src/RunnerV2/RunnerV2/Models/IPowerToysModuleCustomActionsProvider.cs b/src/Runner/Models/IPowerToysModuleCustomActionsProvider.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Models/IPowerToysModuleCustomActionsProvider.cs rename to src/Runner/Models/IPowerToysModuleCustomActionsProvider.cs diff --git a/src/RunnerV2/RunnerV2/Models/IPowerToysModuleSettingsChangedSubscriber.cs b/src/Runner/Models/IPowerToysModuleSettingsChangedSubscriber.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Models/IPowerToysModuleSettingsChangedSubscriber.cs rename to src/Runner/Models/IPowerToysModuleSettingsChangedSubscriber.cs diff --git a/src/RunnerV2/RunnerV2/Models/IPowerToysModuleShortcutsProvider.cs b/src/Runner/Models/IPowerToysModuleShortcutsProvider.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Models/IPowerToysModuleShortcutsProvider.cs rename to src/Runner/Models/IPowerToysModuleShortcutsProvider.cs diff --git a/src/RunnerV2/RunnerV2/Models/ProcessModuleAbstractClass.cs b/src/Runner/Models/ProcessModuleAbstractClass.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Models/ProcessModuleAbstractClass.cs rename to src/Runner/Models/ProcessModuleAbstractClass.cs diff --git a/src/RunnerV2/RunnerV2/Models/RegistryChangeSet.cs b/src/Runner/Models/RegistryChangeSet.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Models/RegistryChangeSet.cs rename to src/Runner/Models/RegistryChangeSet.cs diff --git a/src/RunnerV2/RunnerV2/Models/RegistryValueChange.cs b/src/Runner/Models/RegistryValueChange.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Models/RegistryValueChange.cs rename to src/Runner/Models/RegistryValueChange.cs diff --git a/src/RunnerV2/RunnerV2/Models/SpecialMode.cs b/src/Runner/Models/SpecialMode.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Models/SpecialMode.cs rename to src/Runner/Models/SpecialMode.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/AdvancedPasteModuleInterface.cs b/src/Runner/ModuleInterfaces/AdvancedPasteModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/AdvancedPasteModuleInterface.cs rename to src/Runner/ModuleInterfaces/AdvancedPasteModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/AlwaysOnTopModuleInterface.cs b/src/Runner/ModuleInterfaces/AlwaysOnTopModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/AlwaysOnTopModuleInterface.cs rename to src/Runner/ModuleInterfaces/AlwaysOnTopModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/AwakeModuleInterface.cs b/src/Runner/ModuleInterfaces/AwakeModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/AwakeModuleInterface.cs rename to src/Runner/ModuleInterfaces/AwakeModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/CmdNotFoundModuleInterface.cs b/src/Runner/ModuleInterfaces/CmdNotFoundModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/CmdNotFoundModuleInterface.cs rename to src/Runner/ModuleInterfaces/CmdNotFoundModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/ColorPickerModuleInterface.cs b/src/Runner/ModuleInterfaces/ColorPickerModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/ColorPickerModuleInterface.cs rename to src/Runner/ModuleInterfaces/ColorPickerModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/CommandPaletteModuleInterface.cs b/src/Runner/ModuleInterfaces/CommandPaletteModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/CommandPaletteModuleInterface.cs rename to src/Runner/ModuleInterfaces/CommandPaletteModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/CropAndLockModuleInterface.cs b/src/Runner/ModuleInterfaces/CropAndLockModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/CropAndLockModuleInterface.cs rename to src/Runner/ModuleInterfaces/CropAndLockModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/CursorWrapModuleInterface.cs b/src/Runner/ModuleInterfaces/CursorWrapModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/CursorWrapModuleInterface.cs rename to src/Runner/ModuleInterfaces/CursorWrapModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/EnvironmentVariablesModuleInterface.cs b/src/Runner/ModuleInterfaces/EnvironmentVariablesModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/EnvironmentVariablesModuleInterface.cs rename to src/Runner/ModuleInterfaces/EnvironmentVariablesModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/FancyZonesModuleInterface.cs b/src/Runner/ModuleInterfaces/FancyZonesModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/FancyZonesModuleInterface.cs rename to src/Runner/ModuleInterfaces/FancyZonesModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/FileExplorerModuleInterface.cs b/src/Runner/ModuleInterfaces/FileExplorerModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/FileExplorerModuleInterface.cs rename to src/Runner/ModuleInterfaces/FileExplorerModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/FileLocksmithModuleInterface.cs b/src/Runner/ModuleInterfaces/FileLocksmithModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/FileLocksmithModuleInterface.cs rename to src/Runner/ModuleInterfaces/FileLocksmithModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/FindMyMouseModuleInterface.cs b/src/Runner/ModuleInterfaces/FindMyMouseModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/FindMyMouseModuleInterface.cs rename to src/Runner/ModuleInterfaces/FindMyMouseModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/HostsModuleInterface.cs b/src/Runner/ModuleInterfaces/HostsModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/HostsModuleInterface.cs rename to src/Runner/ModuleInterfaces/HostsModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/ImageResizerModuleInterface.cs b/src/Runner/ModuleInterfaces/ImageResizerModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/ImageResizerModuleInterface.cs rename to src/Runner/ModuleInterfaces/ImageResizerModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/KeyboardManagerModuleInterface.cs b/src/Runner/ModuleInterfaces/KeyboardManagerModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/KeyboardManagerModuleInterface.cs rename to src/Runner/ModuleInterfaces/KeyboardManagerModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/LightSwitchModuleInterface.cs b/src/Runner/ModuleInterfaces/LightSwitchModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/LightSwitchModuleInterface.cs rename to src/Runner/ModuleInterfaces/LightSwitchModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/MeasureToolModuleInterface.cs b/src/Runner/ModuleInterfaces/MeasureToolModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/MeasureToolModuleInterface.cs rename to src/Runner/ModuleInterfaces/MeasureToolModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/MouseHighlighterModuleInterface.cs b/src/Runner/ModuleInterfaces/MouseHighlighterModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/MouseHighlighterModuleInterface.cs rename to src/Runner/ModuleInterfaces/MouseHighlighterModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/MouseJumpModuleInterface.cs b/src/Runner/ModuleInterfaces/MouseJumpModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/MouseJumpModuleInterface.cs rename to src/Runner/ModuleInterfaces/MouseJumpModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/MousePointerCrosshairsModuleInterface.cs b/src/Runner/ModuleInterfaces/MousePointerCrosshairsModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/MousePointerCrosshairsModuleInterface.cs rename to src/Runner/ModuleInterfaces/MousePointerCrosshairsModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/MouseWithoutBordersModuleInterface.cs b/src/Runner/ModuleInterfaces/MouseWithoutBordersModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/MouseWithoutBordersModuleInterface.cs rename to src/Runner/ModuleInterfaces/MouseWithoutBordersModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/NewPlusModuleInterface.cs b/src/Runner/ModuleInterfaces/NewPlusModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/NewPlusModuleInterface.cs rename to src/Runner/ModuleInterfaces/NewPlusModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/PeekModuleInterface.cs b/src/Runner/ModuleInterfaces/PeekModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/PeekModuleInterface.cs rename to src/Runner/ModuleInterfaces/PeekModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/PowerAccentModuleInterface.cs b/src/Runner/ModuleInterfaces/PowerAccentModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/PowerAccentModuleInterface.cs rename to src/Runner/ModuleInterfaces/PowerAccentModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/PowerDisplayModuleInterface.cs b/src/Runner/ModuleInterfaces/PowerDisplayModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/PowerDisplayModuleInterface.cs rename to src/Runner/ModuleInterfaces/PowerDisplayModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/PowerOCRModuleInterface.cs b/src/Runner/ModuleInterfaces/PowerOCRModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/PowerOCRModuleInterface.cs rename to src/Runner/ModuleInterfaces/PowerOCRModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/PowerRenameModuleInterface.cs b/src/Runner/ModuleInterfaces/PowerRenameModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/PowerRenameModuleInterface.cs rename to src/Runner/ModuleInterfaces/PowerRenameModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/PowerToysRunModuleInterface.cs b/src/Runner/ModuleInterfaces/PowerToysRunModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/PowerToysRunModuleInterface.cs rename to src/Runner/ModuleInterfaces/PowerToysRunModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/RegistryPreviewModuleInterface.cs b/src/Runner/ModuleInterfaces/RegistryPreviewModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/RegistryPreviewModuleInterface.cs rename to src/Runner/ModuleInterfaces/RegistryPreviewModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/ShortcutGuideModuleInterface.cs b/src/Runner/ModuleInterfaces/ShortcutGuideModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/ShortcutGuideModuleInterface.cs rename to src/Runner/ModuleInterfaces/ShortcutGuideModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/WorkspacesModuleInterface.cs b/src/Runner/ModuleInterfaces/WorkspacesModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/WorkspacesModuleInterface.cs rename to src/Runner/ModuleInterfaces/WorkspacesModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/ZoomItModuleInterface.cs b/src/Runner/ModuleInterfaces/ZoomItModuleInterface.cs similarity index 100% rename from src/RunnerV2/RunnerV2/ModuleInterfaces/ZoomItModuleInterface.cs rename to src/Runner/ModuleInterfaces/ZoomItModuleInterface.cs diff --git a/src/RunnerV2/RunnerV2/NativeMethods.cs b/src/Runner/NativeMethods.cs similarity index 100% rename from src/RunnerV2/RunnerV2/NativeMethods.cs rename to src/Runner/NativeMethods.cs diff --git a/src/RunnerV2/RunnerV2/Program.cs b/src/Runner/Program.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Program.cs rename to src/Runner/Program.cs diff --git a/src/RunnerV2/RunnerV2/Runner.cs b/src/Runner/Runner.cs similarity index 100% rename from src/RunnerV2/RunnerV2/Runner.cs rename to src/Runner/Runner.cs diff --git a/src/RunnerV2/RunnerV2/RunnerV2.csproj b/src/Runner/RunnerV2.csproj similarity index 54% rename from src/RunnerV2/RunnerV2/RunnerV2.csproj rename to src/Runner/RunnerV2.csproj index 47b57bf1de..3dea14f5a2 100644 --- a/src/RunnerV2/RunnerV2/RunnerV2.csproj +++ b/src/Runner/RunnerV2.csproj @@ -1,11 +1,11 @@  - - + + WinExe PowerToys Runner PowerToys - ..\..\..\$(Platform)\$(Configuration) + ..\..\$(Platform)\$(Configuration) enable false false @@ -14,12 +14,12 @@ - - - - - - + + + + + + diff --git a/src/RunnerV2/RunnerV2/app.manifest b/src/Runner/app.manifest similarity index 100% rename from src/RunnerV2/RunnerV2/app.manifest rename to src/Runner/app.manifest diff --git a/src/RunnerV2/RunnerV2/icon.ico b/src/Runner/icon.ico similarity index 100% rename from src/RunnerV2/RunnerV2/icon.ico rename to src/Runner/icon.ico diff --git a/src/runner/ActionRunnerUtils.h b/src/runner/ActionRunnerUtils.h deleted file mode 100644 index a0c59761c6..0000000000 --- a/src/runner/ActionRunnerUtils.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#define WIN32_LEAN_AND_MEAN -#include - -namespace cmdArg -{ - const inline wchar_t* RUN_NONELEVATED = L"-run-non-elevated"; -} diff --git a/src/runner/PowerToys.exe.manifest b/src/runner/PowerToys.exe.manifest deleted file mode 100644 index ce82aa752f..0000000000 --- a/src/runner/PowerToys.exe.manifest +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - true/PM - PerMonitorV2 - - - diff --git a/src/runner/Resources.resx b/src/runner/Resources.resx deleted file mode 100644 index b94f84714e..0000000000 --- a/src/runner/Resources.resx +++ /dev/null @@ -1,200 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - PowerToys Error - - - Could not start PowerToys as a user! - - - Could not start PowerToys as an administrator! - - - PowerToys is already running. - - - PowerToys was successfully updated! - - - An older version of PowerToys is already running. - - - Couldn't download PowerToys update! Please report the issue on GitHub. - - - An older MSIX version of PowerToys was uninstalled. - - - PowerToys was updated successfully! - - - This setting has been disabled by your administrator. - - - This setting has been disabled manually via <a href="https://ms_settings_startupapps" target="_blank">Startup Settings</a>. - - - An update to PowerToys is available. - - - Update now - - - An update to PowerToys is available. Visit our GitHub page to update. - - - More info... - - - PowerToys Update - - - Quick access\tLeft-click - Don't localize "\t" as that is what separates the click portion to be right aligned in the menu. - - - Settings\tDouble-click - Don't localize "\t" as that is what separates the click portion to be right aligned in the menu. - - - Settings\tLeft-click - Don't localize "\t" as that is what separates the click portion to be right aligned in the menu. This is shown when Quick Access is disabled. - - - Documentation - - - Report bug - - - Bug report .zip file has been created on your Desktop. - - - A new PowerToys version has been installed. Please restart the computer, when possible, to fully reload File Explorer extensions. - File Explorer refers to the Windows File Explorer application. - - - Administrator - - - Close - Close as a verb, as in Close the application - - \ No newline at end of file diff --git a/src/runner/RestartManagement.cpp b/src/runner/RestartManagement.cpp deleted file mode 100644 index 8fc11338fc..0000000000 --- a/src/runner/RestartManagement.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "pch.h" -#include "RestartManagement.h" - -#include -#include - -#include - -void RestartProcess(const std::wstring& processName) -{ - DWORD sessionHandle{}; - WCHAR sessionKey[CCH_RM_SESSION_KEY + 1]; - if (RmStartSession(&sessionHandle, 0, sessionKey) != ERROR_SUCCESS) - { - return; - } - auto processHandles = getProcessHandlesByName(processName, PROCESS_QUERY_INFORMATION); - std::vector pInfo; - for (const auto& hProcess : processHandles) - { - FILETIME creationTime{}; - FILETIME _{}; - if (GetProcessTimes(hProcess.get(), &creationTime, &_, &_, &_)) - { - pInfo.emplace_back(RM_UNIQUE_PROCESS{ GetProcessId(hProcess.get()), creationTime }); - } - } - - if (pInfo.empty() || - RmRegisterResources(sessionHandle, 0, nullptr, sizeof(pInfo), pInfo.data(), 0, nullptr) != ERROR_SUCCESS) - { - return; - } - RmShutdown(sessionHandle, RmForceShutdown, nullptr); - RmRestart(sessionHandle, 0, nullptr); - RmEndSession(sessionHandle); -} diff --git a/src/runner/RestartManagement.h b/src/runner/RestartManagement.h deleted file mode 100644 index 92c60004c8..0000000000 --- a/src/runner/RestartManagement.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include - -void RestartProcess(const std::wstring& processName); diff --git a/src/runner/UpdateUtils.cpp b/src/runner/UpdateUtils.cpp deleted file mode 100644 index 820b926984..0000000000 --- a/src/runner/UpdateUtils.cpp +++ /dev/null @@ -1,308 +0,0 @@ -#include "pch.h" - -#include "Generated Files/resource.h" - -#include "ActionRunnerUtils.h" -#include "general_settings.h" -#include "trace.h" -#include "UpdateUtils.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace -{ - constexpr int64_t UPDATE_CHECK_INTERVAL_MINUTES = 60 * 24; - constexpr int64_t UPDATE_CHECK_AFTER_FAILED_INTERVAL_MINUTES = 60 * 2; - - // How many minor versions to suspend the toast notification (example: installed=0.60.0, suspend=2, next notification=0.63.*) - // Attention: When changing this value please update the ADML file to. - const int UPDATE_NOTIFICATION_TOAST_SUSPEND_MINOR_VERSION_COUNT = 2; -} -using namespace notifications; -using namespace updating; - -std::wstring CurrentVersionToNextVersion(const new_version_download_info& info) -{ - auto result = VersionHelper{ VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION }.toWstring(); - result += L" \u2192 "; // Right arrow - result += info.version.toWstring(); - return result; -} - -void ShowNewVersionAvailable(const new_version_download_info& info) -{ - remove_toasts_by_tag(UPDATING_PROCESS_TOAST_TAG); - - toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false }; - std::wstring contents = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_AVAILABLE); - contents += L'\n'; - contents += CurrentVersionToNextVersion(info); - - show_toast_with_activations(std::move(contents), - GET_RESOURCE_STRING(IDS_TOAST_TITLE), - {}, - { link_button{ GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_UPDATE_NOW), - L"powertoys://update_now/" }, - link_button{ GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_MORE_INFO), - L"powertoys://open_overview/" } }, - std::move(toast_params), - L"powertoys://open_overview/"); -} - -void ShowOpenSettingsForUpdate() -{ - remove_toasts_by_tag(UPDATING_PROCESS_TOAST_TAG); - - toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false }; - - std::vector actions = { - link_button{ GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_MORE_INFO), - L"powertoys://open_overview/" }, - }; - show_toast_with_activations(GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_AVAILABLE), - GET_RESOURCE_STRING(IDS_TOAST_TITLE), - {}, - std::move(actions), - std::move(toast_params), - L"powertoys://open_overview/"); -} - -SHELLEXECUTEINFOW LaunchPowerToysUpdate(const wchar_t* cmdline) -{ - std::wstring powertoysUpdaterPath; - powertoysUpdaterPath = get_module_folderpath(); - - powertoysUpdaterPath += L"\\PowerToys.Update.exe"; - SHELLEXECUTEINFOW sei{ sizeof(sei) }; - sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS }; - sei.lpFile = powertoysUpdaterPath.c_str(); - sei.nShow = SW_SHOWNORMAL; - sei.lpParameters = cmdline; - ShellExecuteExW(&sei); - return sei; -} - -bool IsMeteredConnection() -{ - using namespace winrt::Windows::Networking::Connectivity; - ConnectionProfile internetConnectionProfile = NetworkInformation::GetInternetConnectionProfile(); - if (!internetConnectionProfile) - { - return false; - } - - if (internetConnectionProfile.IsWwanConnectionProfile()) - { - return true; - } - - ConnectionCost connectionCost = internetConnectionProfile.GetConnectionCost(); - if (connectionCost.Roaming() - || connectionCost.OverDataLimit() - || connectionCost.NetworkCostType() == NetworkCostType::Fixed - || connectionCost.NetworkCostType() == NetworkCostType::Variable) - { - return true; - } - - return false; -} - -void ProcessNewVersionInfo(const github_version_info& version_info, - UpdateState& state, - const bool download_update, - bool show_notifications) -{ - state.githubUpdateLastCheckedDate.emplace(timeutil::now()); - if (std::holds_alternative(version_info)) - { - state.state = UpdateState::upToDate; - state.releasePageUrl = {}; - state.downloadedInstallerFilename = {}; - Logger::trace(L"Version is up to date"); - return; - } - const auto new_version_info = std::get(version_info); - state.releasePageUrl = new_version_info.release_page_uri.ToString().c_str(); - Logger::trace(L"Discovered new version {}", new_version_info.version.toWstring()); - - const bool already_downloaded = state.state == UpdateState::readyToInstall && state.downloadedInstallerFilename == new_version_info.installer_filename; - if (already_downloaded) - { - Logger::trace(L"New version is already downloaded"); - return; - } - - // Check toast notification GPOs and settings. (We check only if notifications are allowed. This is the case if we are triggered by the periodic check.) - // Disable notification GPO or setting - bool disable_notification_setting = get_general_settings().showNewUpdatesToastNotification == false; - if (show_notifications && (disable_notification_setting || powertoys_gpo::getDisableNewUpdateToastValue() == powertoys_gpo::gpo_rule_configured_enabled)) - { - Logger::info(L"There is a new update available or ready to install. But the toast notification is disabled by setting or GPO."); - show_notifications = false; - } - // Suspend notification GPO - else if (show_notifications && powertoys_gpo::getSuspendNewUpdateToastValue() == powertoys_gpo::gpo_rule_configured_enabled) - { - Logger::info(L"GPO to suspend new update toast notification is enabled."); - if (new_version_info.version.major <= VERSION_MAJOR && new_version_info.version.minor - VERSION_MINOR <= UPDATE_NOTIFICATION_TOAST_SUSPEND_MINOR_VERSION_COUNT) - { - Logger::info(L"The difference between the installed version and the newer version is within the allowed period. The toast notification is not shown."); - show_notifications = false; - } - else - { - Logger::info(L"The installed version is older than allowed for suspending the toast notification. The toast notification is shown."); - } - } - - if (download_update) - { - Logger::trace(L"Downloading installer for a new version"); - - // Cleanup old updates before downloading the latest - updating::cleanup_updates(); - - if (download_new_version(new_version_info).get()) - { - state.state = UpdateState::readyToInstall; - state.downloadedInstallerFilename = new_version_info.installer_filename; - Trace::UpdateDownloadCompleted(true, new_version_info.version.toWstring()); - if (show_notifications) - { - ShowNewVersionAvailable(new_version_info); - } - } - else - { - state.state = UpdateState::errorDownloading; - state.downloadedInstallerFilename = {}; - Trace::UpdateDownloadCompleted(false, new_version_info.version.toWstring()); - Logger::error("Couldn't download new installer"); - } - } - else - { - Logger::trace(L"New version is ready to download, showing notification"); - state.state = UpdateState::readyToDownload; - state.downloadedInstallerFilename = {}; - if (show_notifications) - { - ShowOpenSettingsForUpdate(); - } - } -} - -void PeriodicUpdateWorker() -{ - for (;;) - { - auto state = UpdateState::read(); - int64_t sleep_minutes_till_next_update = UPDATE_CHECK_AFTER_FAILED_INTERVAL_MINUTES; - if (state.githubUpdateLastCheckedDate.has_value()) - { - int64_t last_checked_minutes_ago = timeutil::diff::in_minutes(timeutil::now(), *state.githubUpdateLastCheckedDate); - if (last_checked_minutes_ago < 0) - { - last_checked_minutes_ago = UPDATE_CHECK_INTERVAL_MINUTES; - } - sleep_minutes_till_next_update = max(0, UPDATE_CHECK_INTERVAL_MINUTES - last_checked_minutes_ago); - } - - std::this_thread::sleep_for(std::chrono::minutes{ sleep_minutes_till_next_update }); - - // Auto download setting. - bool download_update = !IsMeteredConnection() && get_general_settings().downloadUpdatesAutomatically; - if (powertoys_gpo::getDisableAutomaticUpdateDownloadValue() == powertoys_gpo::gpo_rule_configured_enabled) - { - Logger::info(L"Automatic download of updates is disabled by GPO."); - download_update = false; - } - - bool version_info_obtained = false; - try - { - const auto new_version_info = get_github_version_info_async().get(); - if (new_version_info.has_value()) - { - version_info_obtained = true; - bool updateAvailable = std::holds_alternative(*new_version_info); - std::wstring fromVersion = get_product_version(); - std::wstring toVersion = updateAvailable ? std::get(*new_version_info).version.toWstring() : L""; - Trace::UpdateCheckCompleted(true, updateAvailable, fromVersion, toVersion); - ProcessNewVersionInfo(*new_version_info, state, download_update, true); - } - else - { - Trace::UpdateCheckCompleted(false, false, get_product_version(), L""); - Logger::error(L"Couldn't obtain version info from github: {}", new_version_info.error()); - } - } - catch (...) - { - Logger::error("periodic_update_worker: error while processing version info"); - } - - if (version_info_obtained) - { - UpdateState::store([&](UpdateState& v) { - v = std::move(state); - }); - } - else - { - std::this_thread::sleep_for(std::chrono::minutes{ UPDATE_CHECK_AFTER_FAILED_INTERVAL_MINUTES }); - } - } -} - -void CheckForUpdatesCallback() -{ - Logger::trace(L"Check for updates callback invoked"); - auto state = UpdateState::read(); - try - { - auto new_version_info = get_github_version_info_async().get(); - if (!new_version_info) - { - // We couldn't get a new version from github for some reason, log error - state.state = UpdateState::networkError; - Trace::UpdateCheckCompleted(false, false, get_product_version(), L""); - Logger::error(L"Couldn't obtain version info from github: {}", new_version_info.error()); - } - else - { - // Auto download setting - bool download_update = !IsMeteredConnection() && get_general_settings().downloadUpdatesAutomatically; - if (powertoys_gpo::getDisableAutomaticUpdateDownloadValue() == powertoys_gpo::gpo_rule_configured_enabled) - { - Logger::info(L"Automatic download of updates is disabled by GPO."); - download_update = false; - } - - bool updateAvailable = std::holds_alternative(*new_version_info); - std::wstring fromVersion = get_product_version(); - std::wstring toVersion = updateAvailable ? std::get(*new_version_info).version.toWstring() : L""; - Trace::UpdateCheckCompleted(true, updateAvailable, fromVersion, toVersion); - ProcessNewVersionInfo(*new_version_info, state, download_update, false); - } - - UpdateState::store([&](UpdateState& v) { - v = std::move(state); - }); - } - catch (...) - { - Logger::error("CheckForUpdatesCallback: error while processing version info"); - } -} diff --git a/src/runner/UpdateUtils.h b/src/runner/UpdateUtils.h deleted file mode 100644 index 83437c8f80..0000000000 --- a/src/runner/UpdateUtils.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -void PeriodicUpdateWorker(); -void CheckForUpdatesCallback(); - -namespace cmdArg -{ - // Starts first stage of the PowerToys auto-update process, which involves copying action runner to a temp path and - // restarting it from there, so it doesn't interfere with the installation process. - const inline wchar_t* UPDATE_NOW_LAUNCH_STAGE1 = L"-update_now"; - // Stage 2 consists of starting the installer and optionally launching newly installed PowerToys binary. - // That's indicated by the following 2 flags. - const inline wchar_t* UPDATE_NOW_LAUNCH_STAGE2 = L"-update_now_stage_2"; - const inline wchar_t* UPDATE_STAGE2_RESTART_PT = L"restart"; - const inline wchar_t* UPDATE_STAGE2_DONT_START_PT = L"dont_start"; - - const inline wchar_t* UPDATE_REPORT_SUCCESS = L"-report_update_success"; -} - -SHELLEXECUTEINFOW LaunchPowerToysUpdate(const wchar_t* cmdline); \ No newline at end of file diff --git a/src/runner/ai_detection.h b/src/runner/ai_detection.h deleted file mode 100644 index 41aa1dc328..0000000000 --- a/src/runner/ai_detection.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -// Detect AI capabilities by calling ImageResizer in detection mode. -// This runs in a background thread to avoid blocking. -// ImageResizer writes the result to a cache file that it reads on normal startup. -// -// Parameters: -// skipSettingsCheck - If true, skip checking if ImageResizer is enabled in settings. -// Use this when called from apply_general_settings where we know -// ImageResizer is being enabled but settings file may not be saved yet. -void DetectAiCapabilitiesAsync(bool skipSettingsCheck = false); diff --git a/src/runner/auto_start_helper.cpp b/src/runner/auto_start_helper.cpp deleted file mode 100644 index ac1ae45afe..0000000000 --- a/src/runner/auto_start_helper.cpp +++ /dev/null @@ -1,397 +0,0 @@ -#include "pch.h" -#include "auto_start_helper.h" - -#include - -#include -#include -#include - -// Helper macros from wix. -#define ExitOnFailure(x, s, ...) \ - if (FAILED(x)) \ - { \ - Logger::error(s, ##__VA_ARGS__); \ - goto LExit; \ - } -#define ExitWithLastError(x, s, ...) \ - { \ - DWORD util_err = ::GetLastError(); \ - x = HRESULT_FROM_WIN32(util_err); \ - if (!FAILED(x)) \ - { \ - x = E_FAIL; \ - } \ - Logger::error(s, ##__VA_ARGS__); \ - goto LExit; \ - } -#define ExitFunction() \ - { \ - goto LExit; \ - } - -const DWORD USERNAME_DOMAIN_LEN = DNLEN + UNLEN + 2; // Domain Name + '\' + User Name + '\0' -const DWORD USERNAME_LEN = UNLEN + 1; // User Name + '\0' - -bool create_auto_start_task_for_this_user(bool runElevated) -{ - HRESULT hr = S_OK; - - WCHAR username_domain[USERNAME_DOMAIN_LEN]; - WCHAR username[USERNAME_LEN]; - - std::wstring wstrTaskName; - - ITaskService* pService = NULL; - ITaskFolder* pTaskFolder = NULL; - ITaskDefinition* pTask = NULL; - IRegistrationInfo* pRegInfo = NULL; - ITaskSettings* pSettings = NULL; - ITriggerCollection* pTriggerCollection = NULL; - IRegisteredTask* pRegisteredTask = NULL; - - // ------------------------------------------------------ - // Get the Domain/Username for the trigger. - if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) - { - ExitWithLastError(hr, "Getting username failed: {:x}", hr); - } - if (!GetEnvironmentVariable(L"USERDOMAIN", username_domain, USERNAME_DOMAIN_LEN)) - { - ExitWithLastError(hr, "Getting the user's domain failed: {:x}", hr); - } - wcscat_s(username_domain, L"\\"); - wcscat_s(username_domain, username); - - // Task Name. - wstrTaskName = L"Autorun for "; - wstrTaskName += username; - - // Get the executable path passed to the custom action. - WCHAR wszExecutablePath[MAX_PATH]; - GetModuleFileName(NULL, wszExecutablePath, MAX_PATH); - - // ------------------------------------------------------ - // Create an instance of the Task Service. - hr = CoCreateInstance(CLSID_TaskScheduler, - NULL, - CLSCTX_INPROC_SERVER, - IID_ITaskService, - reinterpret_cast(&pService)); - ExitOnFailure(hr, "Failed to create an instance of ITaskService: {:x}", hr); - - // Connect to the task service. - hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t()); - ExitOnFailure(hr, "ITaskService::Connect failed: {:x}", hr); - - // ------------------------------------------------------ - // Get the PowerToys task folder. Creates it if it doesn't exist. - hr = pService->GetFolder(_bstr_t(L"\\PowerToys"), &pTaskFolder); - if (FAILED(hr)) - { - // Folder doesn't exist. Get the Root folder and create the PowerToys subfolder. - ITaskFolder* pRootFolder = NULL; - hr = pService->GetFolder(_bstr_t(L"\\"), &pRootFolder); - ExitOnFailure(hr, "Cannot get Root Folder pointer: {:x}", hr); - hr = pRootFolder->CreateFolder(_bstr_t(L"\\PowerToys"), _variant_t(L""), &pTaskFolder); - if (FAILED(hr)) - { - pRootFolder->Release(); - ExitOnFailure(hr, "Cannot create PowerToys task folder: {:x}", hr); - } - } - - // If the task exists, just enable it. - { - IRegisteredTask* pExistingRegisteredTask = NULL; - hr = pTaskFolder->GetTask(_bstr_t(wstrTaskName.c_str()), &pExistingRegisteredTask); - if (SUCCEEDED(hr)) - { - // Task exists, try enabling it. - hr = pExistingRegisteredTask->put_Enabled(VARIANT_TRUE); - pExistingRegisteredTask->Release(); - if (SUCCEEDED(hr)) - { - // Function enable. Sounds like a success. - ExitFunction(); - } - } - } - - // Create the task builder object to create the task. - hr = pService->NewTask(0, &pTask); - ExitOnFailure(hr, "Failed to create a task definition: {:x}", hr); - - // ------------------------------------------------------ - // Get the registration info for setting the identification. - hr = pTask->get_RegistrationInfo(&pRegInfo); - ExitOnFailure(hr, "Cannot get identification pointer: {:x}", hr); - hr = pRegInfo->put_Author(_bstr_t(username_domain)); - ExitOnFailure(hr, "Cannot put identification info: {:x}", hr); - - // ------------------------------------------------------ - // Create the settings for the task - hr = pTask->get_Settings(&pSettings); - ExitOnFailure(hr, "Cannot get settings pointer: {:x}", hr); - - hr = pSettings->put_StartWhenAvailable(VARIANT_FALSE); - ExitOnFailure(hr, "Cannot put_StartWhenAvailable setting info: {:x}", hr); - hr = pSettings->put_StopIfGoingOnBatteries(VARIANT_FALSE); - ExitOnFailure(hr, "Cannot put_StopIfGoingOnBatteries setting info: {:x}", hr); - hr = pSettings->put_ExecutionTimeLimit(_bstr_t(L"PT0S")); //Unlimited - ExitOnFailure(hr, "Cannot put_ExecutionTimeLimit setting info: {:x}", hr); - hr = pSettings->put_DisallowStartIfOnBatteries(VARIANT_FALSE); - ExitOnFailure(hr, "Cannot put_DisallowStartIfOnBatteries setting info: {:x}", hr); - hr = pSettings->put_Priority(4); - ExitOnFailure(hr, "Cannot put_Priority setting info : {:x}", hr); - - // ------------------------------------------------------ - // Get the trigger collection to insert the logon trigger. - hr = pTask->get_Triggers(&pTriggerCollection); - ExitOnFailure(hr, "Cannot get trigger collection: {:x}", hr); - - // Add the logon trigger to the task. - { - ITrigger* pTrigger = NULL; - ILogonTrigger* pLogonTrigger = NULL; - hr = pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger); - ExitOnFailure(hr, "Cannot create the trigger: {:x}", hr); - - hr = pTrigger->QueryInterface( - IID_ILogonTrigger, reinterpret_cast(&pLogonTrigger)); - pTrigger->Release(); - ExitOnFailure(hr, "QueryInterface call failed for ILogonTrigger: {:x}", hr); - - hr = pLogonTrigger->put_Id(_bstr_t(L"Trigger1")); - - // Timing issues may make explorer not be started when the task runs. - // Add a little delay to mitigate this. - hr = pLogonTrigger->put_Delay(_bstr_t(L"PT03S")); - - // Define the user. The task will execute when the user logs on. - // The specified user must be a user on this computer. - hr = pLogonTrigger->put_UserId(_bstr_t(username_domain)); - pLogonTrigger->Release(); - ExitOnFailure(hr, "Cannot add user ID to logon trigger: {:x}", hr); - } - - // ------------------------------------------------------ - // Add an Action to the task. This task will execute the path passed to this custom action. - { - IActionCollection* pActionCollection = NULL; - IAction* pAction = NULL; - IExecAction* pExecAction = NULL; - - // Get the task action collection pointer. - hr = pTask->get_Actions(&pActionCollection); - ExitOnFailure(hr, "Cannot get Task collection pointer: {:x}", hr); - - // Create the action, specifying that it is an executable action. - hr = pActionCollection->Create(TASK_ACTION_EXEC, &pAction); - pActionCollection->Release(); - ExitOnFailure(hr, "Cannot create the action: {:x}", hr); - - // QI for the executable task pointer. - hr = pAction->QueryInterface( - IID_IExecAction, reinterpret_cast(&pExecAction)); - pAction->Release(); - ExitOnFailure(hr, "QueryInterface call failed for IExecAction: {:x}", hr); - - // Set the path of the executable to PowerToys (passed as CustomActionData). - hr = pExecAction->put_Path(_bstr_t(wszExecutablePath)); - pExecAction->Release(); - ExitOnFailure(hr, "Cannot set path of executable: {:x}", hr); - } - - // ------------------------------------------------------ - // Create the principal for the task - { - IPrincipal* pPrincipal = NULL; - hr = pTask->get_Principal(&pPrincipal); - ExitOnFailure(hr, "Cannot get principal pointer: {:x}", hr); - - // Set up principal information: - hr = pPrincipal->put_Id(_bstr_t(L"Principal1")); - - hr = pPrincipal->put_UserId(_bstr_t(username_domain)); - - hr = pPrincipal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN); - - if (runElevated) - { - hr = pPrincipal->put_RunLevel(_TASK_RUNLEVEL::TASK_RUNLEVEL_HIGHEST); - } - else - { - hr = pPrincipal->put_RunLevel(_TASK_RUNLEVEL::TASK_RUNLEVEL_LUA); - } - pPrincipal->Release(); - ExitOnFailure(hr, "Cannot put principal run level: {:x}", hr); - } - // ------------------------------------------------------ - // Save the task in the PowerToys folder. - { - _variant_t SDDL_FULL_ACCESS_FOR_EVERYONE = L"D:(A;;FA;;;WD)"; - hr = pTaskFolder->RegisterTaskDefinition( - _bstr_t(wstrTaskName.c_str()), - pTask, - TASK_CREATE_OR_UPDATE, - _variant_t(username_domain), - _variant_t(), - TASK_LOGON_INTERACTIVE_TOKEN, - SDDL_FULL_ACCESS_FOR_EVERYONE, - &pRegisteredTask); - ExitOnFailure(hr, "Error saving the Task : {:x}", hr); - } - -LExit: - if (pService) - pService->Release(); - if (pTaskFolder) - pTaskFolder->Release(); - if (pTask) - pTask->Release(); - if (pRegInfo) - pRegInfo->Release(); - if (pSettings) - pSettings->Release(); - if (pTriggerCollection) - pTriggerCollection->Release(); - if (pRegisteredTask) - pRegisteredTask->Release(); - - return (SUCCEEDED(hr)); -} - -bool delete_auto_start_task_for_this_user() -{ - HRESULT hr = S_OK; - - WCHAR username[USERNAME_LEN]; - std::wstring wstrTaskName; - - ITaskService* pService = NULL; - ITaskFolder* pTaskFolder = NULL; - - // ------------------------------------------------------ - // Get the Username for the task. - if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) - { - ExitWithLastError(hr, "Getting username failed: {:x}", hr); - } - - // Task Name. - wstrTaskName = L"Autorun for "; - wstrTaskName += username; - - // ------------------------------------------------------ - // Create an instance of the Task Service. - hr = CoCreateInstance(CLSID_TaskScheduler, - NULL, - CLSCTX_INPROC_SERVER, - IID_ITaskService, - reinterpret_cast(&pService)); - ExitOnFailure(hr, "Failed to create an instance of ITaskService: {:x}", hr); - - // Connect to the task service. - hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t()); - ExitOnFailure(hr, "ITaskService::Connect failed: {:x}", hr); - - // ------------------------------------------------------ - // Get the PowerToys task folder. - hr = pService->GetFolder(_bstr_t(L"\\PowerToys"), &pTaskFolder); - if (FAILED(hr)) - { - // Folder doesn't exist. No need to disable a non-existing task. - hr = S_OK; - ExitFunction(); - } - - // ------------------------------------------------------ - // If the task exists, disable. - { - IRegisteredTask* pExistingRegisteredTask = NULL; - hr = pTaskFolder->GetTask(_bstr_t(wstrTaskName.c_str()), &pExistingRegisteredTask); - if (SUCCEEDED(hr)) - { - // Task exists, try disabling it. - hr = pTaskFolder->DeleteTask(_bstr_t(wstrTaskName.c_str()), 0); - } - } - -LExit: - if (pService) - pService->Release(); - if (pTaskFolder) - pTaskFolder->Release(); - - return (SUCCEEDED(hr)); -} - -bool is_auto_start_task_active_for_this_user() -{ - HRESULT hr = S_OK; - - WCHAR username[USERNAME_LEN]; - std::wstring wstrTaskName; - - ITaskService* pService = NULL; - ITaskFolder* pTaskFolder = NULL; - - // ------------------------------------------------------ - // Get the Username for the task. - if (!GetEnvironmentVariable(L"USERNAME", username, USERNAME_LEN)) - { - ExitWithLastError(hr, "Getting username failed: {:x}", hr); - } - - // Task Name. - wstrTaskName = L"Autorun for "; - wstrTaskName += username; - - // ------------------------------------------------------ - // Create an instance of the Task Service. - hr = CoCreateInstance(CLSID_TaskScheduler, - NULL, - CLSCTX_INPROC_SERVER, - IID_ITaskService, - reinterpret_cast(&pService)); - ExitOnFailure(hr, "Failed to create an instance of ITaskService: {:x}", hr); - - // Connect to the task service. - hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t()); - ExitOnFailure(hr, "ITaskService::Connect failed: {:x}", hr); - - // ------------------------------------------------------ - // Get the PowerToys task folder. - hr = pService->GetFolder(_bstr_t(L"\\PowerToys"), &pTaskFolder); - ExitOnFailure(hr, "ITaskFolder doesn't exist: {:x}", hr); - - // ------------------------------------------------------ - // If the task exists, disable. - { - IRegisteredTask* pExistingRegisteredTask = NULL; - hr = pTaskFolder->GetTask(_bstr_t(wstrTaskName.c_str()), &pExistingRegisteredTask); - if (SUCCEEDED(hr)) - { - // Task exists, get its value. - VARIANT_BOOL is_enabled; - hr = pExistingRegisteredTask->get_Enabled(&is_enabled); - pExistingRegisteredTask->Release(); - if (SUCCEEDED(hr)) - { - // Got the value. Return it. - hr = (is_enabled == VARIANT_TRUE) ? S_OK : E_FAIL; // Fake success or fail to return the value. - ExitFunction(); - } - } - } - -LExit: - if (pService) - pService->Release(); - if (pTaskFolder) - pTaskFolder->Release(); - - return (SUCCEEDED(hr)); -} diff --git a/src/runner/auto_start_helper.h b/src/runner/auto_start_helper.h deleted file mode 100644 index fb2b68fadf..0000000000 --- a/src/runner/auto_start_helper.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -bool is_auto_start_task_active_for_this_user(); -bool create_auto_start_task_for_this_user(bool runElevated); -bool delete_auto_start_task_for_this_user(); diff --git a/src/runner/bug_report.cpp b/src/runner/bug_report.cpp deleted file mode 100644 index 697bf518f7..0000000000 --- a/src/runner/bug_report.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "pch.h" -#include "bug_report.h" -#include "Generated files/resource.h" -#include -#include - -BugReportManager& BugReportManager::instance() -{ - static BugReportManager instance; - return instance; -} - -void BugReportManager::register_callback(const BugReportCallback& callback) -{ - std::lock_guard lock(m_callbacksMutex); - m_callbacks.push_back(callback); -} - -void BugReportManager::clear_callbacks() -{ - std::lock_guard lock(m_callbacksMutex); - m_callbacks.clear(); -} - -void BugReportManager::notify_observers(bool isRunning) -{ - std::lock_guard lock(m_callbacksMutex); - for (const auto& callback : m_callbacks) - { - try - { - callback(isRunning); - } - catch (...) - { - // Ignore callback exceptions to prevent one bad callback from affecting others - } - } -} - -void BugReportManager::launch_bug_report() noexcept -{ - std::wstring bug_report_path = get_module_folderpath(); - bug_report_path += L"\\Tools\\PowerToys.BugReportTool.exe"; - - bool expected_isBugReportRunning = false; - if (m_isBugReportRunning.compare_exchange_strong(expected_isBugReportRunning, true)) - { - // Notify observers that bug report is starting - notify_observers(true); - - std::thread([this, bug_report_path]() { - SHELLEXECUTEINFOW sei{ sizeof(sei) }; - sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NO_CONSOLE }; - sei.lpFile = bug_report_path.c_str(); - sei.nShow = SW_HIDE; - if (ShellExecuteExW(&sei)) - { - WaitForSingleObject(sei.hProcess, INFINITE); - CloseHandle(sei.hProcess); - static const std::wstring bugreport_success = GET_RESOURCE_STRING(IDS_BUGREPORT_SUCCESS); - MessageBoxW(nullptr, bugreport_success.c_str(), L"PowerToys", MB_OK); - } - - m_isBugReportRunning.store(false); - // Notify observers that bug report has finished - notify_observers(false); - }).detach(); - } - else - { - notify_observers(false); - } -} - -bool BugReportManager::is_bug_report_running() const noexcept -{ - return m_isBugReportRunning.load(); -} - -// Legacy functions for backward compatibility -void launch_bug_report() noexcept -{ - BugReportManager::instance().launch_bug_report(); -} - -bool is_bug_report_running() noexcept -{ - return BugReportManager::instance().is_bug_report_running(); -} diff --git a/src/runner/bug_report.h b/src/runner/bug_report.h deleted file mode 100644 index 6edb1c6ba3..0000000000 --- a/src/runner/bug_report.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include -#include -#include - -// Observer pattern for bug report status changes -using BugReportCallback = std::function; - -class BugReportManager -{ -public: - static BugReportManager& instance(); - - // Register a callback to be notified when bug report status changes - void register_callback(const BugReportCallback& callback); - - // Remove all callbacks (useful for cleanup) - void clear_callbacks(); - - // Launch bug report and notify observers - void launch_bug_report() noexcept; - - // Check if bug report is currently running - bool is_bug_report_running() const noexcept; - -private: - BugReportManager() = default; - ~BugReportManager() = default; - BugReportManager(const BugReportManager&) = delete; - BugReportManager& operator=(const BugReportManager&) = delete; - - // Notify all registered callbacks - void notify_observers(bool isRunning); - - std::atomic_bool m_isBugReportRunning = false; - std::vector m_callbacks; - mutable std::mutex m_callbacksMutex; -}; - -// Legacy functions for backward compatibility -void launch_bug_report() noexcept; -bool is_bug_report_running() noexcept; \ No newline at end of file diff --git a/src/runner/centralized_hotkeys.cpp b/src/runner/centralized_hotkeys.cpp deleted file mode 100644 index d0ad870f52..0000000000 --- a/src/runner/centralized_hotkeys.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "pch.h" -#include "centralized_hotkeys.h" - -#include -#include -#include -#include - -namespace CentralizedHotkeys -{ - std::map> actions; - std::map ids; - HWND runnerWindow; - - std::wstring ToWstring(const Shortcut& shortcut) - { - std::wstring res = L""; - if (shortcut.modifiersMask & MOD_SHIFT) - { - res += L"shift+"; - } - - if (shortcut.modifiersMask & MOD_CONTROL) - { - res += L"ctrl+"; - } - - if (shortcut.modifiersMask & MOD_WIN) - { - res += L"win+"; - } - - if (shortcut.modifiersMask & MOD_ALT) - { - res += L"alt+"; - } - - res += PowerToysSettings::HotkeyObject::key_from_code(shortcut.vkCode); - - return res; - } - - bool AddHotkeyAction(Shortcut shortcut, Action action) - { - if (!actions[shortcut].empty()) - { - // It will only work if previous one is rewritten - Logger::warn(L"{} shortcut is already registered", ToWstring(shortcut)); - } - - actions[shortcut].push_back(action); - // Register hotkey if it is the first shortcut - if (actions[shortcut].size() == 1) - { - if (ids.find(shortcut) == ids.end()) - { - static int nextId = 0; - ids[shortcut] = nextId++; - } - - if (!RegisterHotKey(runnerWindow, ids[shortcut], shortcut.modifiersMask, shortcut.vkCode)) - { - Logger::warn(L"Failed to add {} shortcut. {}", ToWstring(shortcut), get_last_error_or_default(GetLastError())); - return false; - } - - Logger::trace(L"{} shortcut registered", ToWstring(shortcut)); - return true; - } - - return true; - } - - void UnregisterHotkeysForModule(std::wstring moduleName) - { - for (auto it = actions.begin(); it != actions.end(); it++) - { - auto val = std::find_if(it->second.begin(), it->second.end(), [moduleName](Action a) { return a.moduleName == moduleName; }); - if (val != it->second.end()) - { - it->second.erase(val); - - if (it->second.empty()) - { - if (!UnregisterHotKey(runnerWindow, ids[it->first])) - { - Logger::warn(L"Failed to unregister {} shortcut. {}", ToWstring(it->first), get_last_error_or_default(GetLastError())); - } - else - { - Logger::trace(L"{} shortcut unregistered", ToWstring(it->first)); - } - } - } - } - } - - void PopulateHotkey(Shortcut shortcut) - { - if (!actions.empty()) - { - try - { - actions[shortcut].begin()->action(shortcut.modifiersMask, shortcut.vkCode); - } - catch(std::exception& ex) - { - Logger::error("Failed to execute hotkey's action. {}", ex.what()); - } - catch(...) - { - Logger::error(L"Failed to execute hotkey's action"); - } - } - } - - void RegisterWindow(HWND hwnd) - { - runnerWindow = hwnd; - } -} diff --git a/src/runner/centralized_hotkeys.h b/src/runner/centralized_hotkeys.h deleted file mode 100644 index bb503d332d..0000000000 --- a/src/runner/centralized_hotkeys.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once -#include -#include - -namespace CentralizedHotkeys -{ - struct Action - { - std::wstring moduleName; - std::function action; - - Action(std::wstring moduleName = L"", std::function action = ([](WORD /*modifiersMask*/, WORD /*vkCode*/) {})) - { - this->moduleName = moduleName; - this->action = action; - } - }; - - struct Shortcut - { - WORD modifiersMask; - WORD vkCode; - int hotkeyID; - - Shortcut(WORD modifiersMask = 0, WORD vkCode = 0, const int hotkeyID = 0) - { - this->modifiersMask = modifiersMask; - this->vkCode = vkCode; - this->hotkeyID = hotkeyID; - } - - bool operator<(const Shortcut& key) const - { - return std::pair{ this->modifiersMask, this->vkCode } < std::pair{ key.modifiersMask, key.vkCode }; - } - }; - - std::wstring ToWstring(const Shortcut& shortcut); - - bool AddHotkeyAction(Shortcut shortcut, Action action); - - void UnregisterHotkeysForModule(std::wstring moduleName); - - void PopulateHotkey(Shortcut shortcut); - - void RegisterWindow(HWND hwnd); -} diff --git a/src/runner/centralized_kb_hook.cpp b/src/runner/centralized_kb_hook.cpp deleted file mode 100644 index 72b473bd08..0000000000 --- a/src/runner/centralized_kb_hook.cpp +++ /dev/null @@ -1,276 +0,0 @@ -#include "pch.h" -#include "centralized_kb_hook.h" -#include -#include -#include -#include - -namespace CentralizedKeyboardHook -{ - struct HotkeyDescriptor - { - Hotkey hotkey; - std::wstring moduleName; - std::function action; - - bool operator<(const HotkeyDescriptor& other) const - { - return hotkey < other.hotkey; - }; - }; - - std::multiset hotkeyDescriptors; - std::mutex mutex; - HHOOK hHook{}; - - // To store information about handling pressed keys. - struct PressedKeyDescriptor - { - DWORD virtualKey; // Virtual Key code of the key we're keeping track of. - std::wstring moduleName; - std::function action; - UINT_PTR idTimer; // Timer ID for calling SET_TIMER with. - UINT millisecondsToPress; // How much time the key must be pressed. - bool operator<(const PressedKeyDescriptor& other) const - { - // We'll use the virtual key as the real key, since looking for a hit with the key is done in the more time sensitive path (low level keyboard hook). - return virtualKey < other.virtualKey; - }; - }; - std::multiset pressedKeyDescriptors; - std::mutex pressedKeyMutex; - - // keep track of last pressed key, to detect repeated keys and if there are more keys pressed. - const DWORD VK_DISABLED = CommonSharedConstants::VK_DISABLED; - DWORD vkCodePressed = VK_DISABLED; - - // Save the runner window handle for registering timers. - HWND runnerWindow; - - struct DestroyOnExit - { - ~DestroyOnExit() - { - Stop(); - } - } destroyOnExitObj; - - // Handle the pressed key proc - void PressedKeyTimerProc( - HWND hwnd, - UINT /*message*/, - UINT_PTR idTimer, - DWORD /*dwTime*/) - { - std::multiset copy; - { - // Make a copy, to look for the action to call. - std::unique_lock lock{ pressedKeyMutex }; - copy = pressedKeyDescriptors; - } - for (const auto& it : copy) - { - if (it.idTimer == idTimer) - { - it.action(); - } - } - - KillTimer(hwnd, idTimer); - } - - LRESULT CALLBACK KeyboardHookProc(_In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam) - { - if (nCode < 0) - { - return CallNextHookEx(hHook, nCode, wParam, lParam); - } - - const auto& keyPressInfo = *reinterpret_cast(lParam); - - if (keyPressInfo.dwExtraInfo == PowertoyModuleIface::CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG) - { - // The new keystroke was generated from one of our actions. We should pass it along. - return CallNextHookEx(hHook, nCode, wParam, lParam); - } - - // Check if the keys are pressed. - if (!pressedKeyDescriptors.empty()) - { - bool wasKeyPressed = vkCodePressed != VK_DISABLED; - // Hold the lock for the shortest possible duration - if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)) - { - if (!wasKeyPressed) - { - // If no key was pressed before, let's start a timer to take into account this new key. - std::unique_lock lock{ pressedKeyMutex }; - PressedKeyDescriptor dummy{ .virtualKey = keyPressInfo.vkCode }; - auto [it, last] = pressedKeyDescriptors.equal_range(dummy); - for (; it != last; ++it) - { - SetTimer(runnerWindow, it->idTimer, it->millisecondsToPress, PressedKeyTimerProc); - } - } - else if (vkCodePressed != keyPressInfo.vkCode) - { - // If a different key was pressed, let's clear the timers we have started for the previous key. - std::unique_lock lock{ pressedKeyMutex }; - PressedKeyDescriptor dummy{ .virtualKey = vkCodePressed }; - auto [it, last] = pressedKeyDescriptors.equal_range(dummy); - for (; it != last; ++it) - { - KillTimer(runnerWindow, it->idTimer); - } - } - vkCodePressed = keyPressInfo.vkCode; - } - if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP) - { - std::unique_lock lock{ pressedKeyMutex }; - PressedKeyDescriptor dummy{ .virtualKey = keyPressInfo.vkCode }; - auto [it, last] = pressedKeyDescriptors.equal_range(dummy); - for (; it != last; ++it) - { - KillTimer(runnerWindow, it->idTimer); - } - vkCodePressed = 0x100; - } - } - - if ((wParam != WM_KEYDOWN) && (wParam != WM_SYSKEYDOWN)) - { - return CallNextHookEx(hHook, nCode, wParam, lParam); - } - - Hotkey hotkey{ - .win = (GetAsyncKeyState(VK_LWIN) & 0x8000) || (GetAsyncKeyState(VK_RWIN) & 0x8000), - .ctrl = static_cast(GetAsyncKeyState(VK_CONTROL) & 0x8000), - .shift = static_cast(GetAsyncKeyState(VK_SHIFT) & 0x8000), - .alt = static_cast(GetAsyncKeyState(VK_MENU) & 0x8000), - .key = static_cast(keyPressInfo.vkCode) - }; - - if (hotkey == Hotkey{}) - { - return CallNextHookEx(hHook, nCode, wParam, lParam); - } - - std::function action; - { - // Hold the lock for the shortest possible duration - std::unique_lock lock{ mutex }; - HotkeyDescriptor dummy{ .hotkey = hotkey }; - auto it = hotkeyDescriptors.find(dummy); - if (it != hotkeyDescriptors.end()) - { - action = it->action; - } - } - - if (action) - { - if (action()) - { - // After invoking the hotkey send a dummy key to prevent Start Menu from activating - INPUT dummyEvent[1] = {}; - dummyEvent[0].type = INPUT_KEYBOARD; - dummyEvent[0].ki.wVk = 0xFF; - dummyEvent[0].ki.dwFlags = KEYEVENTF_KEYUP; - SendInput(1, dummyEvent, sizeof(INPUT)); - - // Swallow the key press - return 1; - } - } - - return CallNextHookEx(hHook, nCode, wParam, lParam); - } - - void SetHotkeyAction(const std::wstring& moduleName, const Hotkey& hotkey, std::function&& action) noexcept - { - Logger::trace(L"Register hotkey action for {}", moduleName); - std::unique_lock lock{ mutex }; - hotkeyDescriptors.insert({ .hotkey = hotkey, .moduleName = moduleName, .action = std::move(action) }); - } - - void AddPressedKeyAction(const std::wstring& moduleName, const DWORD vk, const UINT milliseconds, std::function&& action) noexcept - { - // Calculate a unique TimerID. - auto hash = std::hash{}(moduleName); // Hash the module as the upper part of the timer ID. - const UINT upperId = hash & 0xFFFF; - const UINT lowerId = vk & 0xFFFF; // The key to press can be the lower ID. - const UINT timerId = upperId << 16 | lowerId; - std::unique_lock lock{ pressedKeyMutex }; - pressedKeyDescriptors.insert({ .virtualKey = vk, .moduleName = moduleName, .action = std::move(action), .idTimer = timerId, .millisecondsToPress = milliseconds }); - } - - void ClearModuleHotkeys(const std::wstring& moduleName) noexcept - { - Logger::trace(L"UnRegister hotkey action for {}", moduleName); - { - std::unique_lock lock{ mutex }; - auto it = hotkeyDescriptors.begin(); - while (it != hotkeyDescriptors.end()) - { - if (it->moduleName == moduleName) - { - it = hotkeyDescriptors.erase(it); - } - else - { - ++it; - } - } - } - { - std::unique_lock lock{ pressedKeyMutex }; - auto it = pressedKeyDescriptors.begin(); - while (it != pressedKeyDescriptors.end()) - { - if (it->moduleName == moduleName) - { - it = pressedKeyDescriptors.erase(it); - } - else - { - ++it; - } - } - } - } - - void Start() noexcept - { -#if defined(DISABLE_LOWLEVEL_HOOKS_WHEN_DEBUGGED) - const bool hook_disabled = IsDebuggerPresent(); -#else - const bool hook_disabled = false; -#endif - if (!hook_disabled) - { - if (!hHook) - { - hHook = SetWindowsHookExW(WH_KEYBOARD_LL, KeyboardHookProc, NULL, NULL); - if (!hHook) - { - DWORD errorCode = GetLastError(); - show_last_error_message(L"SetWindowsHookEx", errorCode, L"centralized_kb_hook"); - } - } - } - } - - void Stop() noexcept - { - if (hHook && UnhookWindowsHookEx(hHook)) - { - hHook = NULL; - } - } - - void RegisterWindow(HWND hwnd) noexcept - { - runnerWindow = hwnd; - } -} diff --git a/src/runner/centralized_kb_hook.h b/src/runner/centralized_kb_hook.h deleted file mode 100644 index 1ae36ebacb..0000000000 --- a/src/runner/centralized_kb_hook.h +++ /dev/null @@ -1,15 +0,0 @@ -#include "pch.h" - -#include "../modules/interface/powertoy_module_interface.h" - -namespace CentralizedKeyboardHook -{ - using Hotkey = PowertoyModuleIface::Hotkey; - - void Start() noexcept; - void Stop() noexcept; - void SetHotkeyAction(const std::wstring& moduleName, const Hotkey& hotkey, std::function&& action) noexcept; - void AddPressedKeyAction(const std::wstring& moduleName, const DWORD vk, const UINT milliseconds, std::function&& action) noexcept; - void ClearModuleHotkeys(const std::wstring& moduleName) noexcept; - void RegisterWindow(HWND hwnd) noexcept; -}; diff --git a/src/runner/general_settings.cpp b/src/runner/general_settings.cpp deleted file mode 100644 index 6225ed8f2a..0000000000 --- a/src/runner/general_settings.cpp +++ /dev/null @@ -1,588 +0,0 @@ -#include "pch.h" -#include "general_settings.h" -#include "auto_start_helper.h" -#include "tray_icon.h" -#include "quick_access_host.h" -#include "Generated files/resource.h" -#include "hotkey_conflict_detector.h" - -#include -#include "powertoy_module.h" -#include - -#include "trace.h" -#include "ai_detection.h" -#include -#include -#include - -namespace -{ - json::JsonValue create_empty_shortcut_array_value() - { - return json::JsonValue::Parse(L"[]"); - } - - void ensure_ignored_conflict_properties_shape(json::JsonObject& obj) - { - if (!json::has(obj, L"ignored_shortcuts", json::JsonValueType::Array)) - { - obj.SetNamedValue(L"ignored_shortcuts", create_empty_shortcut_array_value()); - } - } - - json::JsonObject create_default_ignored_conflict_properties() - { - json::JsonObject obj; - ensure_ignored_conflict_properties_shape(obj); - return obj; - } - - DashboardSortOrder parse_dashboard_sort_order(const json::JsonObject& obj, DashboardSortOrder fallback) - { - if (json::has(obj, L"dashboard_sort_order", json::JsonValueType::Number)) - { - const auto raw_value = static_cast(obj.GetNamedNumber(L"dashboard_sort_order", static_cast(static_cast(fallback)))); - return raw_value == static_cast(DashboardSortOrder::ByStatus) ? DashboardSortOrder::ByStatus : DashboardSortOrder::Alphabetical; - } - - if (json::has(obj, L"dashboard_sort_order", json::JsonValueType::String)) - { - const auto raw = obj.GetNamedString(L"dashboard_sort_order"); - if (raw == L"ByStatus") - { - return DashboardSortOrder::ByStatus; - } - - if (raw == L"Alphabetical") - { - return DashboardSortOrder::Alphabetical; - } - } - - return fallback; - } -} - -// TODO: would be nice to get rid of these globals, since they're basically cached json settings -static std::wstring settings_theme = L"system"; -static bool show_tray_icon = true; -static bool show_theme_adaptive_tray_icon = false; -static bool run_as_elevated = false; -static bool show_new_updates_toast_notification = true; -static bool download_updates_automatically = true; -static bool show_whats_new_after_updates = true; -static bool enable_experimentation = true; -static bool enable_warnings_elevated_apps = true; -static bool enable_quick_access = true; -static PowerToysSettings::HotkeyObject quick_access_shortcut; -static DashboardSortOrder dashboard_sort_order = DashboardSortOrder::Alphabetical; -static json::JsonObject ignored_conflict_properties = create_default_ignored_conflict_properties(); - -json::JsonObject GeneralSettings::to_json() -{ - json::JsonObject result; - - auto ignoredProps = ignoredConflictProperties; - ensure_ignored_conflict_properties_shape(ignoredProps); - - result.SetNamedValue(L"startup", json::value(isStartupEnabled)); - if (!startupDisabledReason.empty()) - { - result.SetNamedValue(L"startup_disabled_reason", json::value(startupDisabledReason)); - } - - json::JsonObject enabled; - for (const auto& [name, isEnabled] : isModulesEnabledMap) - { - enabled.SetNamedValue(name, json::value(isEnabled)); - } - result.SetNamedValue(L"enabled", std::move(enabled)); - - result.SetNamedValue(L"show_tray_icon", json::value(showSystemTrayIcon)); - result.SetNamedValue(L"show_theme_adaptive_tray_icon", json::value(showThemeAdaptiveTrayIcon)); - result.SetNamedValue(L"is_elevated", json::value(isElevated)); - result.SetNamedValue(L"run_elevated", json::value(isRunElevated)); - result.SetNamedValue(L"show_new_updates_toast_notification", json::value(showNewUpdatesToastNotification)); - result.SetNamedValue(L"download_updates_automatically", json::value(downloadUpdatesAutomatically)); - result.SetNamedValue(L"show_whats_new_after_updates", json::value(showWhatsNewAfterUpdates)); - result.SetNamedValue(L"enable_experimentation", json::value(enableExperimentation)); - result.SetNamedValue(L"dashboard_sort_order", json::value(static_cast(dashboardSortOrder))); - result.SetNamedValue(L"is_admin", json::value(isAdmin)); - result.SetNamedValue(L"enable_warnings_elevated_apps", json::value(enableWarningsElevatedApps)); - result.SetNamedValue(L"enable_quick_access", json::value(enableQuickAccess)); - result.SetNamedValue(L"quick_access_shortcut", quickAccessShortcut.get_json()); - result.SetNamedValue(L"theme", json::value(theme)); - result.SetNamedValue(L"system_theme", json::value(systemTheme)); - result.SetNamedValue(L"powertoys_version", json::value(powerToysVersion)); - result.SetNamedValue(L"ignored_conflict_properties", json::value(ignoredProps)); - - return result; -} - -json::JsonObject load_general_settings() -{ - auto loaded = PTSettingsHelper::load_general_settings(); - settings_theme = loaded.GetNamedString(L"theme", L"system"); - if (settings_theme != L"dark" && settings_theme != L"light") - { - settings_theme = L"system"; - } - show_tray_icon = loaded.GetNamedBoolean(L"show_tray_icon", true); - show_theme_adaptive_tray_icon = loaded.GetNamedBoolean(L"show_theme_adaptive_tray_icon", false); - run_as_elevated = loaded.GetNamedBoolean(L"run_elevated", false); - show_new_updates_toast_notification = loaded.GetNamedBoolean(L"show_new_updates_toast_notification", true); - download_updates_automatically = loaded.GetNamedBoolean(L"download_updates_automatically", true) && check_user_is_admin(); - show_whats_new_after_updates = loaded.GetNamedBoolean(L"show_whats_new_after_updates", true); - enable_experimentation = loaded.GetNamedBoolean(L"enable_experimentation", true); - enable_warnings_elevated_apps = loaded.GetNamedBoolean(L"enable_warnings_elevated_apps", true); - enable_quick_access = loaded.GetNamedBoolean(L"enable_quick_access", true); - if (json::has(loaded, L"quick_access_shortcut", json::JsonValueType::Object)) - { - quick_access_shortcut = PowerToysSettings::HotkeyObject::from_json(loaded.GetNamedObject(L"quick_access_shortcut")); - } - dashboard_sort_order = parse_dashboard_sort_order(loaded, dashboard_sort_order); - - if (json::has(loaded, L"ignored_conflict_properties", json::JsonValueType::Object)) - { - ignored_conflict_properties = loaded.GetNamedObject(L"ignored_conflict_properties"); - } - else - { - ignored_conflict_properties = create_default_ignored_conflict_properties(); - } - - ensure_ignored_conflict_properties_shape(ignored_conflict_properties); - - return loaded; -} - -GeneralSettings get_general_settings() -{ - const bool is_user_admin = check_user_is_admin(); - GeneralSettings settings - { - .showSystemTrayIcon = show_tray_icon, - .showThemeAdaptiveTrayIcon = show_theme_adaptive_tray_icon, - .isElevated = is_process_elevated(), - .isRunElevated = run_as_elevated, - .isAdmin = is_user_admin, - .enableWarningsElevatedApps = enable_warnings_elevated_apps, - .enableQuickAccess = enable_quick_access, - .quickAccessShortcut = quick_access_shortcut, - .showNewUpdatesToastNotification = show_new_updates_toast_notification, - .downloadUpdatesAutomatically = download_updates_automatically && is_user_admin, - .showWhatsNewAfterUpdates = show_whats_new_after_updates, - .enableExperimentation = enable_experimentation, - .dashboardSortOrder = dashboard_sort_order, - .theme = settings_theme, - .systemTheme = WindowsColors::is_dark_mode() ? L"dark" : L"light", - .powerToysVersion = get_product_version(), - .ignoredConflictProperties = ignored_conflict_properties - }; - - ensure_ignored_conflict_properties_shape(settings.ignoredConflictProperties); - - settings.isStartupEnabled = is_auto_start_task_active_for_this_user(); - - for (auto& [name, powertoy] : modules()) - { - settings.isModulesEnabledMap[name] = powertoy->is_enabled(); - } - - return settings; -} - -void apply_module_status_update(const json::JsonObject& module_config, bool save) -{ - Logger::info(L"apply_module_status_update: {}", std::wstring{ module_config.ToString() }); - - // Expected format: {"ModuleName": true/false} - only one module per update - auto iter = module_config.First(); - if (!iter.HasCurrent()) - { - Logger::warn(L"apply_module_status_update: Empty module config"); - return; - } - - const auto& element = iter.Current(); - const auto value = element.Value(); - if (value.ValueType() != json::JsonValueType::Boolean) - { - Logger::warn(L"apply_module_status_update: Invalid value type for module status"); - return; - } - - const std::wstring name{ element.Key().c_str() }; - if (modules().find(name) == modules().end()) - { - Logger::warn(L"apply_module_status_update: Module {} not found", name); - return; - } - - PowertoyModule& powertoy = modules().at(name); - const bool module_inst_enabled = powertoy->is_enabled(); - bool target_enabled = value.GetBoolean(); - - auto gpo_rule = powertoy->gpo_policy_enabled_configuration(); - if (gpo_rule == powertoys_gpo::gpo_rule_configured_enabled || gpo_rule == powertoys_gpo::gpo_rule_configured_disabled) - { - // Apply the GPO Rule. - target_enabled = gpo_rule == powertoys_gpo::gpo_rule_configured_enabled; - } - - if (module_inst_enabled == target_enabled) - { - Logger::info(L"apply_module_status_update: Module {} already in target state {}", name, target_enabled); - return; - } - - if (target_enabled) - { - Logger::info(L"apply_module_status_update: Enabling powertoy {}", name); - powertoy->enable(); - auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); - hkmng.EnableHotkeyByModule(name); - - // Trigger AI capability detection when ImageResizer is enabled - if (name == L"Image Resizer") - { - Logger::info(L"ImageResizer enabled, triggering AI capability detection"); - DetectAiCapabilitiesAsync(true); // Skip settings check since we know it's being enabled - } - } - else - { - Logger::info(L"apply_module_status_update: Disabling powertoy {}", name); - powertoy->disable(); - auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); - hkmng.DisableHotkeyByModule(name); - } - // Sync the hotkey state with the module state, so it can be removed for disabled modules. - powertoy.UpdateHotkeyEx(); - - if (save) - { - // Load existing settings and only update the specific module's enabled state - json::JsonObject current_settings = PTSettingsHelper::load_general_settings(); - - json::JsonObject enabled; - if (current_settings.HasKey(L"enabled")) - { - enabled = current_settings.GetNamedObject(L"enabled"); - } - - // Check if the saved state is different from the requested state - bool current_saved = enabled.HasKey(name) ? enabled.GetNamedBoolean(name, true) : true; - - if (current_saved != target_enabled) - { - // Update only this module's enabled state - enabled.SetNamedValue(name, json::value(target_enabled)); - current_settings.SetNamedValue(L"enabled", enabled); - - PTSettingsHelper::save_general_settings(current_settings); - - GeneralSettings settings_for_trace = get_general_settings(); - Trace::SettingsChanged(settings_for_trace); - } - } -} - -void apply_general_settings(const json::JsonObject& general_configs, bool save) -{ - std::wstring old_settings_json_string; - if (save) - { - old_settings_json_string = get_general_settings().to_json().Stringify().c_str(); - } - - Logger::info(L"apply_general_settings: {}", std::wstring{ general_configs.ToString() }); - run_as_elevated = general_configs.GetNamedBoolean(L"run_elevated", false); - - enable_warnings_elevated_apps = general_configs.GetNamedBoolean(L"enable_warnings_elevated_apps", true); - - bool new_enable_quick_access = general_configs.GetNamedBoolean(L"enable_quick_access", true); - Logger::info(L"apply_general_settings: enable_quick_access={}, new_enable_quick_access={}", enable_quick_access, new_enable_quick_access); - - PowerToysSettings::HotkeyObject new_quick_access_shortcut; - if (json::has(general_configs, L"quick_access_shortcut", json::JsonValueType::Object)) - { - new_quick_access_shortcut = PowerToysSettings::HotkeyObject::from_json(general_configs.GetNamedObject(L"quick_access_shortcut")); - } - - auto hotkey_equals = [](const PowerToysSettings::HotkeyObject& a, const PowerToysSettings::HotkeyObject& b) { - return a.get_code() == b.get_code() && - a.get_modifiers() == b.get_modifiers(); - }; - - if (enable_quick_access != new_enable_quick_access || !hotkey_equals(quick_access_shortcut, new_quick_access_shortcut)) - { - enable_quick_access = new_enable_quick_access; - quick_access_shortcut = new_quick_access_shortcut; - - if (enable_quick_access) - { - QuickAccessHost::start(); - } - else - { - QuickAccessHost::stop(); - } - update_quick_access_hotkey(enable_quick_access, quick_access_shortcut); - } - - show_new_updates_toast_notification = general_configs.GetNamedBoolean(L"show_new_updates_toast_notification", true); - - download_updates_automatically = general_configs.GetNamedBoolean(L"download_updates_automatically", true); - show_whats_new_after_updates = general_configs.GetNamedBoolean(L"show_whats_new_after_updates", true); - - enable_experimentation = general_configs.GetNamedBoolean(L"enable_experimentation", true); - dashboard_sort_order = parse_dashboard_sort_order(general_configs, dashboard_sort_order); - - // apply_general_settings is called by the runner's WinMain, so we can just force the run at startup gpo rule here. - auto gpo_run_as_startup = powertoys_gpo::getConfiguredRunAtStartupValue(); - - if (json::has(general_configs, L"startup", json::JsonValueType::Boolean)) - { - bool startup = general_configs.GetNamedBoolean(L"startup"); - - if (gpo_run_as_startup == powertoys_gpo::gpo_rule_configured_enabled) - { - startup = true; - } - else if (gpo_run_as_startup == powertoys_gpo::gpo_rule_configured_disabled) - { - startup = false; - } - - if (startup) - { - if (is_process_elevated()) - { - delete_auto_start_task_for_this_user(); - create_auto_start_task_for_this_user(run_as_elevated); - } - else - { - if (!is_auto_start_task_active_for_this_user()) - { - delete_auto_start_task_for_this_user(); - create_auto_start_task_for_this_user(false); - - run_as_elevated = false; - } - else if (!general_configs.GetNamedBoolean(L"run_elevated", false)) - { - delete_auto_start_task_for_this_user(); - create_auto_start_task_for_this_user(false); - } - } - } - else - { - delete_auto_start_task_for_this_user(); - } - } - else - { - delete_auto_start_task_for_this_user(); - if (gpo_run_as_startup == powertoys_gpo::gpo_rule_configured_enabled || gpo_run_as_startup == powertoys_gpo::gpo_rule_configured_not_configured) - { - create_auto_start_task_for_this_user(run_as_elevated); - } - } - - if (json::has(general_configs, L"enabled")) - { - for (const auto& enabled_element : general_configs.GetNamedObject(L"enabled")) - { - const auto value = enabled_element.Value(); - if (value.ValueType() != json::JsonValueType::Boolean) - { - continue; - } - const std::wstring name{ enabled_element.Key().c_str() }; - const bool found = modules().find(name) != modules().end(); - if (!found) - { - continue; - } - PowertoyModule& powertoy = modules().at(name); - const bool module_inst_enabled = powertoy->is_enabled(); - bool target_enabled = value.GetBoolean(); - - auto gpo_rule = powertoy->gpo_policy_enabled_configuration(); - if (gpo_rule == powertoys_gpo::gpo_rule_configured_enabled || gpo_rule == powertoys_gpo::gpo_rule_configured_disabled) - { - // Apply the GPO Rule. - target_enabled = gpo_rule == powertoys_gpo::gpo_rule_configured_enabled; - } - - if (module_inst_enabled == target_enabled) - { - continue; - } - if (target_enabled) - { - Logger::info(L"apply_general_settings: Enabling powertoy {}", name); - powertoy->enable(); - auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); - hkmng.EnableHotkeyByModule(name); - - // Trigger AI capability detection when ImageResizer is enabled - if (name == L"Image Resizer") - { - Logger::info(L"ImageResizer enabled, triggering AI capability detection"); - DetectAiCapabilitiesAsync(true); // Skip settings check since we know it's being enabled - } - } - else - { - Logger::info(L"apply_general_settings: Disabling powertoy {}", name); - powertoy->disable(); - auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); - hkmng.DisableHotkeyByModule(name); - } - // Sync the hotkey state with the module state, so it can be removed for disabled modules. - powertoy.UpdateHotkeyEx(); - } - } - - if (json::has(general_configs, L"theme", json::JsonValueType::String)) - { - settings_theme = general_configs.GetNamedString(L"theme"); - } - - if (json::has(general_configs, L"show_tray_icon", json::JsonValueType::Boolean)) - { - show_tray_icon = general_configs.GetNamedBoolean(L"show_tray_icon"); - set_tray_icon_visible(show_tray_icon); - } - - if (json::has(general_configs, L"show_theme_adaptive_tray_icon", json::JsonValueType::Boolean)) - { - bool new_theme_adaptive = general_configs.GetNamedBoolean(L"show_theme_adaptive_tray_icon"); - Logger::info(L"apply_general_settings: show_theme_adaptive_tray_icon current={}, new={}", - show_theme_adaptive_tray_icon, new_theme_adaptive); - if (show_theme_adaptive_tray_icon != new_theme_adaptive) - { - show_theme_adaptive_tray_icon = new_theme_adaptive; - set_tray_icon_theme_adaptive(show_theme_adaptive_tray_icon); - } - else - { - Logger::info(L"apply_general_settings: show_theme_adaptive_tray_icon unchanged, skipping update"); - } - } - else - { - Logger::warn(L"apply_general_settings: show_theme_adaptive_tray_icon not found in config"); - } - - if (json::has(general_configs, L"ignored_conflict_properties", json::JsonValueType::Object)) - { - ignored_conflict_properties = general_configs.GetNamedObject(L"ignored_conflict_properties"); - ensure_ignored_conflict_properties_shape(ignored_conflict_properties); - } - - if (save) - { - GeneralSettings save_settings = get_general_settings(); - std::wstring new_settings_json_string = save_settings.to_json().Stringify().c_str(); - if (old_settings_json_string != new_settings_json_string) - { - PTSettingsHelper::save_general_settings(save_settings.to_json()); - Trace::SettingsChanged(save_settings); - } - } -} - -void start_enabled_powertoys() -{ - std::unordered_set powertoys_to_disable; - std::unordered_map powertoys_gpo_configuration; - // Take into account default values supplied by modules themselves and gpo configurations - for (auto& [name, powertoy] : modules()) - { - auto gpo_rule = powertoy->gpo_policy_enabled_configuration(); - powertoys_gpo_configuration[name] = gpo_rule; - if (gpo_rule == powertoys_gpo::gpo_rule_configured_unavailable) - { - Logger::warn(L"start_enabled_powertoys: couldn't read the gpo rule for Powertoy {}", name); - } - if (gpo_rule == powertoys_gpo::gpo_rule_configured_wrong_value) - { - Logger::warn(L"start_enabled_powertoys: gpo rule for Powertoy {} is set to an unknown value", name); - } - - if (!powertoy->is_enabled_by_default()) - powertoys_to_disable.emplace(name); - } - - json::JsonObject general_settings; - try - { - general_settings = load_general_settings(); - if (general_settings.HasKey(L"enabled")) - { - json::JsonObject enabled = general_settings.GetNamedObject(L"enabled"); - for (const auto& disabled_element : enabled) - { - std::wstring disable_module_name{ static_cast(disabled_element.Key()) }; - - if (powertoys_gpo_configuration.find(disable_module_name) != powertoys_gpo_configuration.end() && (powertoys_gpo_configuration[disable_module_name] == powertoys_gpo::gpo_rule_configured_enabled || powertoys_gpo_configuration[disable_module_name] == powertoys_gpo::gpo_rule_configured_disabled)) - { - // If gpo forces the enabled setting, no need to check the setting for this PowerToy. It will be applied later on this function. - continue; - } - - // Disable explicitly disabled modules - if (!disabled_element.Value().GetBoolean()) - { - Logger::info(L"start_enabled_powertoys: Powertoy {} explicitly disabled", disable_module_name); - powertoys_to_disable.emplace(std::move(disable_module_name)); - } - // If module was scheduled for disable, but it's enabled in the settings - override default value - else if (auto it = powertoys_to_disable.find(disable_module_name); it != end(powertoys_to_disable)) - { - Logger::info(L"start_enabled_powertoys: Overriding default enabled value for {} powertoy", disable_module_name); - powertoys_to_disable.erase(it); - } - } - } - } - catch (...) - { - } - - for (auto& [name, powertoy] : modules()) - { - bool should_powertoy_be_enabled = true; - - auto gpo_rule = powertoys_gpo_configuration.find(name) != powertoys_gpo_configuration.end() ? powertoys_gpo_configuration[name] : powertoys_gpo::gpo_rule_configured_not_configured; - - if (gpo_rule == powertoys_gpo::gpo_rule_configured_enabled || gpo_rule == powertoys_gpo::gpo_rule_configured_disabled) - { - // Apply the GPO Rule. - should_powertoy_be_enabled = gpo_rule == powertoys_gpo::gpo_rule_configured_enabled; - Logger::info(L"start_enabled_powertoys: GPO sets the enabled state for {} powertoy as {}", name, should_powertoy_be_enabled); - } - else if (powertoys_to_disable.contains(name)) - { - // Apply the settings or default information provided by the PowerToy on first run. - should_powertoy_be_enabled = false; - } - - if (should_powertoy_be_enabled) - { - Logger::info(L"start_enabled_powertoys: Enabling powertoy {}", name); - powertoy->enable(); - auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); - hkmng.EnableHotkeyByModule(name); - powertoy.UpdateHotkeyEx(); - } - } -} - - diff --git a/src/runner/general_settings.h b/src/runner/general_settings.h deleted file mode 100644 index 487e3216da..0000000000 --- a/src/runner/general_settings.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include -#include - -enum class DashboardSortOrder -{ - Alphabetical = 0, - ByStatus = 1, -}; - -struct GeneralSettings -{ - bool isStartupEnabled; - bool showSystemTrayIcon; - bool showThemeAdaptiveTrayIcon; - std::wstring startupDisabledReason; - std::map isModulesEnabledMap; - bool isElevated; - bool isRunElevated; - bool isAdmin; - bool enableWarningsElevatedApps; - bool enableQuickAccess; - PowerToysSettings::HotkeyObject quickAccessShortcut; - bool showNewUpdatesToastNotification; - bool downloadUpdatesAutomatically; - bool showWhatsNewAfterUpdates; - bool enableExperimentation; - DashboardSortOrder dashboardSortOrder; - std::wstring theme; - std::wstring systemTheme; - std::wstring powerToysVersion; - json::JsonObject ignoredConflictProperties; - - json::JsonObject to_json(); -}; - -json::JsonObject load_general_settings(); -GeneralSettings get_general_settings(); -void apply_general_settings(const json::JsonObject& general_configs, bool save = true); -void apply_module_status_update(const json::JsonObject& module_config, bool save = true); -void start_enabled_powertoys(); \ No newline at end of file diff --git a/src/runner/hotkey_conflict_detector.cpp b/src/runner/hotkey_conflict_detector.cpp deleted file mode 100644 index 14c8a1ecd9..0000000000 --- a/src/runner/hotkey_conflict_detector.cpp +++ /dev/null @@ -1,471 +0,0 @@ -#include "pch.h" -#include "hotkey_conflict_detector.h" -#include -#include -#include -#include - -namespace HotkeyConflictDetector -{ - Hotkey ShortcutToHotkey(const CentralizedHotkeys::Shortcut& shortcut) - { - Hotkey hotkey; - - hotkey.win = (shortcut.modifiersMask & MOD_WIN) != 0; - hotkey.ctrl = (shortcut.modifiersMask & MOD_CONTROL) != 0; - hotkey.shift = (shortcut.modifiersMask & MOD_SHIFT) != 0; - hotkey.alt = (shortcut.modifiersMask & MOD_ALT) != 0; - - hotkey.key = shortcut.vkCode > 255 ? 0 : static_cast(shortcut.vkCode); - - return hotkey; - } - - HotkeyConflictManager* HotkeyConflictManager::instance = nullptr; - std::mutex HotkeyConflictManager::instanceMutex; - - HotkeyConflictManager& HotkeyConflictManager::GetInstance() - { - std::lock_guard lock(instanceMutex); - if (instance == nullptr) - { - instance = new HotkeyConflictManager(); - } - return *instance; - } - - HotkeyConflictType HotkeyConflictManager::HasConflict(Hotkey const& _hotkey, const wchar_t* _moduleName, const int _hotkeyID) - { - if (disabledHotkeys.find(_moduleName) != disabledHotkeys.end()) - { - return HotkeyConflictType::NoConflict; - } - - uint16_t handle = GetHotkeyHandle(_hotkey); - - if (handle == 0) - { - return HotkeyConflictType::NoConflict; - } - - // The order is important, first to check sys conflict and then inapp conflict - if (sysConflictHotkeyMap.find(handle) != sysConflictHotkeyMap.end()) - { - return HotkeyConflictType::SystemConflict; - } - - if (inAppConflictHotkeyMap.find(handle) != inAppConflictHotkeyMap.end()) - { - return HotkeyConflictType::InAppConflict; - } - - auto it = hotkeyMap.find(handle); - - if (it == hotkeyMap.end()) - { - return HasConflictWithSystemHotkey(_hotkey) ? - HotkeyConflictType::SystemConflict : - HotkeyConflictType::NoConflict; - } - - if (wcscmp(it->second.moduleName.c_str(), _moduleName) == 0 && it->second.hotkeyID == _hotkeyID) - { - // A shortcut matching its own assignment is not considered a conflict. - return HotkeyConflictType::NoConflict; - } - - return HotkeyConflictType::InAppConflict; - } - - HotkeyConflictType HotkeyConflictManager::HasConflict(Hotkey const& _hotkey) - { - uint16_t handle = GetHotkeyHandle(_hotkey); - - if (handle == 0) - { - return HotkeyConflictType::NoConflict; - } - - // The order is important, first to check sys conflict and then inapp conflict - if (sysConflictHotkeyMap.find(handle) != sysConflictHotkeyMap.end()) - { - return HotkeyConflictType::SystemConflict; - } - - if (inAppConflictHotkeyMap.find(handle) != inAppConflictHotkeyMap.end()) - { - return HotkeyConflictType::InAppConflict; - } - - auto it = hotkeyMap.find(handle); - - if (it == hotkeyMap.end()) - { - return HasConflictWithSystemHotkey(_hotkey) ? - HotkeyConflictType::SystemConflict : - HotkeyConflictType::NoConflict; - } - - return HotkeyConflictType::InAppConflict; - } - - // This function should only be called when a conflict has already been identified. - // It returns a list of all conflicting shortcuts. - std::vector HotkeyConflictManager::GetAllConflicts(Hotkey const& _hotkey) - { - std::vector conflicts; - uint16_t handle = GetHotkeyHandle(_hotkey); - - // Check in-app conflicts first - auto inAppIt = inAppConflictHotkeyMap.find(handle); - if (inAppIt != inAppConflictHotkeyMap.end()) - { - // Add all in-app conflicts - for (const auto& conflict : inAppIt->second) - { - conflicts.push_back(conflict); - } - - return conflicts; - } - - // Check system conflicts - auto sysIt = sysConflictHotkeyMap.find(handle); - if (sysIt != sysConflictHotkeyMap.end()) - { - HotkeyConflictInfo systemConflict; - systemConflict.hotkey = _hotkey; - systemConflict.moduleName = L"System"; - systemConflict.hotkeyID = 0; - - conflicts.push_back(systemConflict); - - return conflicts; - } - - // Check if there's a successfully registered hotkey that would conflict - auto registeredIt = hotkeyMap.find(handle); - if (registeredIt != hotkeyMap.end()) - { - conflicts.push_back(registeredIt->second); - - return conflicts; - } - - // If all the above conditions are ruled out, a system-level conflict is the only remaining explanation. - HotkeyConflictInfo systemConflict; - systemConflict.hotkey = _hotkey; - systemConflict.moduleName = L"System"; - systemConflict.hotkeyID = 0; - conflicts.push_back(systemConflict); - - return conflicts; - } - - bool HotkeyConflictManager::AddHotkey(Hotkey const& _hotkey, const wchar_t* _moduleName, const int _hotkeyID, bool isEnabled) - { - if (!isEnabled) - { - disabledHotkeys[_moduleName].push_back({ _hotkey, _moduleName, _hotkeyID }); - return true; - } - - uint16_t handle = GetHotkeyHandle(_hotkey); - - if (handle == 0) - { - return false; - } - - HotkeyConflictType conflictType = HasConflict(_hotkey, _moduleName, _hotkeyID); - if (conflictType != HotkeyConflictType::NoConflict) - { - if (conflictType == HotkeyConflictType::InAppConflict) - { - auto hotkeyFound = hotkeyMap.find(handle); - inAppConflictHotkeyMap[handle].insert({ _hotkey, _moduleName, _hotkeyID }); - - if (hotkeyFound != hotkeyMap.end()) - { - inAppConflictHotkeyMap[handle].insert(hotkeyFound->second); - hotkeyMap.erase(hotkeyFound); - } - } - else - { - sysConflictHotkeyMap[handle].insert({ _hotkey, _moduleName, _hotkeyID }); - } - return false; - } - - HotkeyConflictInfo hotkeyInfo; - hotkeyInfo.moduleName = _moduleName; - hotkeyInfo.hotkeyID = _hotkeyID; - hotkeyInfo.hotkey = _hotkey; - hotkeyMap[handle] = hotkeyInfo; - - return true; - } - - std::vector HotkeyConflictManager::RemoveHotkeyByModule(const std::wstring& moduleName) - { - std::vector removedHotkeys; - - if (disabledHotkeys.find(moduleName) != disabledHotkeys.end()) - { - disabledHotkeys.erase(moduleName); - } - - std::lock_guard lock(hotkeyMutex); - bool foundRecord = false; - - for (auto it = sysConflictHotkeyMap.begin(); it != sysConflictHotkeyMap.end();) - { - auto& conflictSet = it->second; - for (auto setIt = conflictSet.begin(); setIt != conflictSet.end();) - { - if (setIt->moduleName == moduleName) - { - removedHotkeys.push_back(*setIt); - setIt = conflictSet.erase(setIt); - foundRecord = true; - } - else - { - ++setIt; - } - } - if (conflictSet.empty()) - { - it = sysConflictHotkeyMap.erase(it); - } - else - { - ++it; - } - } - - for (auto it = inAppConflictHotkeyMap.begin(); it != inAppConflictHotkeyMap.end();) - { - auto& conflictSet = it->second; - uint16_t handle = it->first; - - for (auto setIt = conflictSet.begin(); setIt != conflictSet.end();) - { - if (setIt->moduleName == moduleName) - { - removedHotkeys.push_back(*setIt); - setIt = conflictSet.erase(setIt); - foundRecord = true; - } - else - { - ++setIt; - } - } - - if (conflictSet.empty()) - { - it = inAppConflictHotkeyMap.erase(it); - } - else if (conflictSet.size() == 1) - { - // Move the only remaining conflict to main map - const auto& onlyConflict = *conflictSet.begin(); - hotkeyMap[handle] = onlyConflict; - it = inAppConflictHotkeyMap.erase(it); - } - else - { - ++it; - } - } - - for (auto it = hotkeyMap.begin(); it != hotkeyMap.end();) - { - if (it->second.moduleName == moduleName) - { - uint16_t handle = it->first; - removedHotkeys.push_back(it->second); - it = hotkeyMap.erase(it); - foundRecord = true; - - auto inAppIt = inAppConflictHotkeyMap.find(handle); - if (inAppIt != inAppConflictHotkeyMap.end() && inAppIt->second.size() == 1) - { - // Move the only in-app conflict to main map - const auto& onlyConflict = *inAppIt->second.begin(); - hotkeyMap[handle] = onlyConflict; - inAppConflictHotkeyMap.erase(inAppIt); - } - } - else - { - ++it; - } - } - - return removedHotkeys; - } - - void HotkeyConflictManager::EnableHotkeyByModule(const std::wstring& moduleName) - { - if (disabledHotkeys.find(moduleName) == disabledHotkeys.end()) - { - return; // No disabled hotkeys for this module - } - - auto hotkeys = disabledHotkeys[moduleName]; - disabledHotkeys.erase(moduleName); - - for (const auto& hotkeyInfo : hotkeys) - { - // Re-add the hotkey as enabled - AddHotkey(hotkeyInfo.hotkey, moduleName.c_str(), hotkeyInfo.hotkeyID, true); - } - } - - void HotkeyConflictManager::DisableHotkeyByModule(const std::wstring& moduleName) - { - auto hotkeys = RemoveHotkeyByModule(moduleName); - disabledHotkeys[moduleName] = hotkeys; - } - - bool HotkeyConflictManager::HasConflictWithSystemHotkey(const Hotkey& hotkey) - { - // Convert PowerToys Hotkey format to Win32 RegisterHotKey format - UINT modifiers = 0; - if (hotkey.win) - { - modifiers |= MOD_WIN; - } - if (hotkey.ctrl) - { - modifiers |= MOD_CONTROL; - } - if (hotkey.alt) - { - modifiers |= MOD_ALT; - } - if (hotkey.shift) - { - modifiers |= MOD_SHIFT; - } - - // No modifiers or no key is not a valid hotkey - if (modifiers == 0 || hotkey.key == 0) - { - return false; - } - - // Use a unique ID for this test registration - const int hotkeyId = 0x0FFF; // Arbitrary ID for temporary registration - - // Try to register the hotkey with Windows, using nullptr instead of a window handle - if (!RegisterHotKey(nullptr, hotkeyId, modifiers, hotkey.key)) - { - // If registration fails with ERROR_HOTKEY_ALREADY_REGISTERED, it means the hotkey - // is already in use by the system or another application - if (GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED) - { - return true; - } - } - else - { - // If registration succeeds, unregister it immediately - UnregisterHotKey(nullptr, hotkeyId); - } - - return false; - } - - json::JsonObject HotkeyConflictManager::GetHotkeyConflictsAsJson() - { - std::lock_guard lock(hotkeyMutex); - - using namespace json; - JsonObject root; - - // Serialize hotkey to a unique string format for grouping - auto serializeHotkey = [](const Hotkey& hotkey) -> JsonObject { - JsonObject obj; - obj.Insert(L"win", value(hotkey.win)); - obj.Insert(L"ctrl", value(hotkey.ctrl)); - obj.Insert(L"shift", value(hotkey.shift)); - obj.Insert(L"alt", value(hotkey.alt)); - obj.Insert(L"key", value(static_cast(hotkey.key))); - return obj; - }; - - // New format: Group conflicts by hotkey - JsonArray inAppConflictsArray; - JsonArray sysConflictsArray; - - // Process in-app conflicts - only include hotkeys that are actually in conflict - for (const auto& [handle, conflicts] : inAppConflictHotkeyMap) - { - if (!conflicts.empty()) - { - JsonObject conflictGroup; - - // All entries have the same hotkey, so use the first one for the key - conflictGroup.Insert(L"hotkey", serializeHotkey(conflicts.begin()->hotkey)); - - // Create an array of module info without repeating the hotkey - JsonArray modules; - for (const auto& info : conflicts) - { - JsonObject moduleInfo; - moduleInfo.Insert(L"moduleName", value(info.moduleName)); - moduleInfo.Insert(L"hotkeyID", value(info.hotkeyID)); - modules.Append(moduleInfo); - } - - conflictGroup.Insert(L"modules", modules); - inAppConflictsArray.Append(conflictGroup); - } - } - - // Process system conflicts - only include hotkeys that are actually in conflict - for (const auto& [handle, conflicts] : sysConflictHotkeyMap) - { - if (!conflicts.empty()) - { - JsonObject conflictGroup; - - // All entries have the same hotkey, so use the first one for the key - conflictGroup.Insert(L"hotkey", serializeHotkey(conflicts.begin()->hotkey)); - - // Create an array of module info without repeating the hotkey - JsonArray modules; - for (const auto& info : conflicts) - { - JsonObject moduleInfo; - moduleInfo.Insert(L"moduleName", value(info.moduleName)); - moduleInfo.Insert(L"hotkeyID", value(info.hotkeyID)); - modules.Append(moduleInfo); - } - - conflictGroup.Insert(L"modules", modules); - sysConflictsArray.Append(conflictGroup); - } - } - - // Add the grouped conflicts to the root object - root.Insert(L"inAppConflicts", inAppConflictsArray); - root.Insert(L"sysConflicts", sysConflictsArray); - - return root; - } - - uint16_t HotkeyConflictManager::GetHotkeyHandle(const Hotkey& hotkey) - { - uint16_t handle = hotkey.key; - handle |= hotkey.win << 8; - handle |= hotkey.ctrl << 9; - handle |= hotkey.shift << 10; - handle |= hotkey.alt << 11; - return handle; - } -} \ No newline at end of file diff --git a/src/runner/hotkey_conflict_detector.h b/src/runner/hotkey_conflict_detector.h deleted file mode 100644 index c32954e3e4..0000000000 --- a/src/runner/hotkey_conflict_detector.h +++ /dev/null @@ -1,100 +0,0 @@ -#pragma once -#include "pch.h" -#include -#include -#include - -#include "../modules/interface/powertoy_module_interface.h" -#include "centralized_hotkeys.h" -#include "common/utils/json.h" - -namespace HotkeyConflictDetector -{ - using Hotkey = PowertoyModuleIface::Hotkey; - using HotkeyEx = PowertoyModuleIface::HotkeyEx; - using Shortcut = CentralizedHotkeys::Shortcut; - - struct HotkeyConflictInfo - { - Hotkey hotkey; - std::wstring moduleName; - int hotkeyID = 0; - - inline bool operator==(const HotkeyConflictInfo& other) const - { - return hotkey == other.hotkey && - moduleName == other.moduleName && - hotkeyID == other.hotkeyID; - } - }; - - Hotkey ShortcutToHotkey(const CentralizedHotkeys::Shortcut& shortcut); - - enum HotkeyConflictType - { - NoConflict = 0, - SystemConflict = 1, - InAppConflict = 2, - }; - - class HotkeyConflictManager - { - public: - static HotkeyConflictManager& GetInstance(); - - HotkeyConflictType HasConflict(const Hotkey& hotkey, const wchar_t* moduleName, const int hotkeyID); - HotkeyConflictType HotkeyConflictManager::HasConflict(Hotkey const& _hotkey); - std::vector HotkeyConflictManager::GetAllConflicts(Hotkey const& hotkey); - bool AddHotkey(const Hotkey& hotkey, const wchar_t* moduleName, const int hotkeyID, bool isEnabled); - std::vector RemoveHotkeyByModule(const std::wstring& moduleName); - - void EnableHotkeyByModule(const std::wstring& moduleName); - void DisableHotkeyByModule(const std::wstring& moduleName); - - json::JsonObject GetHotkeyConflictsAsJson(); - - private: - static std::mutex instanceMutex; - static HotkeyConflictManager* instance; - - std::mutex hotkeyMutex; - // Hotkey in hotkeyMap means the hotkey has been registered successfully - std::unordered_map hotkeyMap; - // Hotkey in sysConflictHotkeyMap means the hotkey has conflict with system defined hotkeys - std::unordered_map> sysConflictHotkeyMap; - // Hotkey in inAppConflictHotkeyMap means the hotkey has conflict with other modules - std::unordered_map> inAppConflictHotkeyMap; - - std::unordered_map> disabledHotkeys; - - uint16_t GetHotkeyHandle(const Hotkey&); - bool HasConflictWithSystemHotkey(const Hotkey&); - - HotkeyConflictManager() = default; - }; -}; - -namespace std -{ - template<> - struct hash - { - size_t operator()(const HotkeyConflictDetector::HotkeyConflictInfo& info) const - { - - size_t hotkeyHash = - (info.hotkey.win ? 1ULL : 0ULL) | - ((info.hotkey.ctrl ? 1ULL : 0ULL) << 1) | - ((info.hotkey.shift ? 1ULL : 0ULL) << 2) | - ((info.hotkey.alt ? 1ULL : 0ULL) << 3) | - (static_cast(info.hotkey.key) << 4); - - size_t moduleHash = std::hash{}(info.moduleName); - size_t idHash = std::hash{}(info.hotkeyID); - - return hotkeyHash ^ - ((moduleHash << 1) | (moduleHash >> (sizeof(size_t) * 8 - 1))) ^ // rotate left 1 bit - ((idHash << 2) | (idHash >> (sizeof(size_t) * 8 - 2))); // rotate left 2 bits - } - }; -} diff --git a/src/runner/main.cpp b/src/runner/main.cpp deleted file mode 100644 index 973cee4ba5..0000000000 --- a/src/runner/main.cpp +++ /dev/null @@ -1,643 +0,0 @@ -#include "pch.h" -#include -#include -#include -#include -#include "tray_icon.h" -#include "powertoy_module.h" -#include "trace.h" -#include "general_settings.h" -#include "restart_elevated.h" -#include "RestartManagement.h" -#include "Generated files/resource.h" -#include "settings_telemetry.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "UpdateUtils.h" -#include "ActionRunnerUtils.h" - -#include - -#include -#include -#include -#include "centralized_kb_hook.h" -#include "centralized_hotkeys.h" -#include "quick_access_host.h" -#include "ai_detection.h" -#include - -#if _DEBUG && _WIN64 -#include "unhandled_exception_handler.h" -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// disabling warning 4458 - declaration of 'identifier' hides class member -// to avoid warnings from GDI files - can't add winRT directory to external code -// in the Cpp.Build.props -#pragma warning(push) -#pragma warning(disable : 4458) -#include -#pragma warning(pop) - -namespace -{ - const wchar_t PT_URI_PROTOCOL_SCHEME[] = L"powertoys://"; - const wchar_t POWER_TOYS_MODULE_LOAD_FAIL[] = L"Failed to load "; // Module name will be appended on this message and it is not localized. -} - -void chdir_current_executable() -{ - // Change current directory to the path of the executable. - WCHAR executable_path[MAX_PATH]; - GetModuleFileName(NULL, executable_path, MAX_PATH); - PathRemoveFileSpec(executable_path); - if (!SetCurrentDirectory(executable_path)) - { - show_last_error_message(L"Change Directory to Executable Path", GetLastError(), L"PowerToys - runner"); - } -} - -// Detect AI capabilities by calling ImageResizer in detection mode. -// This runs in a background thread to avoid blocking the main startup. -// ImageResizer writes the result to a cache file that it reads on normal startup. -void DetectAiCapabilitiesAsync(bool skipSettingsCheck) -{ - std::thread([skipSettingsCheck]() { - try - { - // Check if ImageResizer module is enabled (skip if called from apply_general_settings) - if (!skipSettingsCheck) - { - auto settings = PTSettingsHelper::load_general_settings(); - if (json::has(settings, L"enabled", json::JsonValueType::Object)) - { - auto enabledModules = settings.GetNamedObject(L"enabled"); - if (json::has(enabledModules, L"Image Resizer", json::JsonValueType::Boolean)) - { - bool isEnabled = enabledModules.GetNamedBoolean(L"Image Resizer", false); - if (!isEnabled) - { - Logger::info(L"ImageResizer module is disabled, skipping AI detection"); - return; - } - } - } - } - - // Get ImageResizer.exe path (located in WinUI3Apps folder) - std::wstring imageResizerPath = get_module_folderpath(); - imageResizerPath += L"\\WinUI3Apps\\PowerToys.ImageResizer.exe"; - - if (!std::filesystem::exists(imageResizerPath)) - { - Logger::warn(L"ImageResizer.exe not found at {}, skipping AI detection", imageResizerPath); - return; - } - - Logger::info(L"Starting AI capability detection via ImageResizer"); - - // Call ImageResizer --detect-ai - SHELLEXECUTEINFO sei = { sizeof(sei) }; - sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI; - sei.lpFile = imageResizerPath.c_str(); - sei.lpParameters = L"--detect-ai"; - sei.nShow = SW_HIDE; - - if (ShellExecuteExW(&sei)) - { - // Wait for detection to complete (with timeout) - DWORD waitResult = WaitForSingleObject(sei.hProcess, 30000); // 30 second timeout - CloseHandle(sei.hProcess); - - if (waitResult == WAIT_OBJECT_0) - { - Logger::info(L"AI capability detection completed successfully"); - } - else if (waitResult == WAIT_TIMEOUT) - { - Logger::warn(L"AI capability detection timed out"); - } - else - { - Logger::warn(L"AI capability detection wait failed"); - } - } - else - { - Logger::warn(L"Failed to launch ImageResizer for AI detection, error: {}", GetLastError()); - } - } - catch (const std::exception& e) - { - Logger::error("Exception during AI capability detection: {}", e.what()); - } - catch (...) - { - Logger::error("Unknown exception during AI capability detection"); - } - }).detach(); -} - -inline wil::unique_mutex_nothrow create_msi_mutex() -{ - return createAppMutex(POWERTOYS_MSI_MUTEX_NAME); -} - -void open_menu_from_another_instance(std::optional settings_window) -{ - const HWND hwnd_main = FindWindowW(L"PToyTrayIconWindow", nullptr); - LPARAM msg = static_cast(ESettingsWindowNames::Dashboard); - if (settings_window.has_value() && settings_window.value() != "") - { - msg = static_cast(ESettingsWindowNames_from_string(settings_window.value())); - } - PostMessageW(hwnd_main, WM_COMMAND, ID_SETTINGS_MENU_COMMAND, msg); - SetForegroundWindow(hwnd_main); // Bring the settings window to the front -} - -int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow, bool openOobe, bool openScoobe, bool showRestartNotificationAfterUpdate) -{ - Logger::info("Runner is starting. Elevated={} openOobe={} openScoobe={} showRestartNotificationAfterUpdate={}", isProcessElevated, openOobe, openScoobe, showRestartNotificationAfterUpdate); - DPIAware::EnableDPIAwarenessForThisProcess(); - -#if _DEBUG && _WIN64 -//Global error handlers to diagnose errors. -//We prefer this not to show any longer until there's a bug to diagnose. -//init_global_error_handlers(); -#endif - Trace::RegisterProvider(); - - // Load settings from file before reading them - load_general_settings(); - auto const settings = get_general_settings(); - start_tray_icon(isProcessElevated, settings.showThemeAdaptiveTrayIcon); - - if (settings.enableQuickAccess) - { - QuickAccessHost::start(); - } - update_quick_access_hotkey(settings.enableQuickAccess, settings.quickAccessShortcut); - set_tray_icon_visible(settings.showSystemTrayIcon); - CentralizedKeyboardHook::Start(); - - int result = -1; - try - { - if (!openOobe && showRestartNotificationAfterUpdate) - { - std::thread{ - [] { - // Wait a bit, because Windows has a delay until it picks up toast notification registration in the registry - Sleep(10000); - Logger::info("Showing toast notification asking to restart PC"); - notifications::show_toast(GET_RESOURCE_STRING(IDS_PT_VERSION_CHANGE_ASK_FOR_COMPUTER_RESTART).c_str(), L"PowerToys"); - } - }.detach(); - } - - std::thread{ [] { - PeriodicUpdateWorker(); - } }.detach(); - - // Start AI capability detection in background (Windows 11+ only) - // AI Super Resolution is not supported on Windows 10 - // This calls ImageResizer --detect-ai which writes result to cache file - if (package::IsWin11OrGreater()) - { - DetectAiCapabilitiesAsync(); - } - else - { - Logger::info(L"AI capability detection skipped: Windows 10 does not support AI Super Resolution"); - } - - std::thread{ [] { - if (updating::uninstall_previous_msix_version_async().get()) - { - notifications::show_toast(GET_RESOURCE_STRING(IDS_OLDER_MSIX_UNINSTALLED).c_str(), L"PowerToys"); - } - } }.detach(); - - chdir_current_executable(); - - // We deprecated a utility called Video Conference Mute, which registered itself as a video input device. - // When running elevated, we try to clean up the device registration from previous installations. - // This is done here too because a user-scope installer won't be able to remove the driver registration due to lack of permissions. - if (isProcessElevated) - { - clean_video_conference(); - } - - // Load PowerToys DLLs - - std::vector knownModules = { - L"PowerToys.FancyZonesModuleInterface.dll", - L"PowerToys.powerpreview.dll", - L"WinUI3Apps/PowerToys.ImageResizerExt.dll", - L"PowerToys.KeyboardManager.dll", - L"PowerToys.Launcher.dll", - L"WinUI3Apps/PowerToys.PowerRenameExt.dll", - L"PowerToys.ShortcutGuideModuleInterface.dll", - L"PowerToys.ColorPicker.dll", - L"PowerToys.AwakeModuleInterface.dll", - L"PowerToys.FindMyMouse.dll", - L"PowerToys.MouseHighlighter.dll", - L"PowerToys.MouseJump.dll", - L"PowerToys.AlwaysOnTopModuleInterface.dll", - L"PowerToys.MousePointerCrosshairs.dll", - L"PowerToys.CursorWrap.dll", - L"PowerToys.PowerAccentModuleInterface.dll", - L"PowerToys.PowerOCRModuleInterface.dll", - L"PowerToys.AdvancedPasteModuleInterface.dll", - L"WinUI3Apps/PowerToys.FileLocksmithExt.dll", - L"WinUI3Apps/PowerToys.RegistryPreviewExt.dll", - L"WinUI3Apps/PowerToys.MeasureToolModuleInterface.dll", - L"WinUI3Apps/PowerToys.NewPlus.ShellExtension.dll", - L"WinUI3Apps/PowerToys.HostsModuleInterface.dll", - L"WinUI3Apps/PowerToys.Peek.dll", - L"WinUI3Apps/PowerToys.EnvironmentVariablesModuleInterface.dll", - L"PowerToys.MouseWithoutBordersModuleInterface.dll", - L"PowerToys.CropAndLockModuleInterface.dll", - L"PowerToys.CmdNotFoundModuleInterface.dll", - L"PowerToys.WorkspacesModuleInterface.dll", - L"PowerToys.CmdPalModuleInterface.dll", - L"PowerToys.ZoomItModuleInterface.dll", - L"PowerToys.LightSwitchModuleInterface.dll", - L"PowerToys.PowerDisplayModuleInterface.dll", - }; - - for (auto moduleSubdir : knownModules) - { - try - { - auto pt_module = load_powertoy(moduleSubdir); - modules().emplace(pt_module->get_key(), std::move(pt_module)); - } - catch (...) - { - std::wstring errorMessage = POWER_TOYS_MODULE_LOAD_FAIL; - errorMessage += moduleSubdir; - -#ifdef _DEBUG - // In debug mode, simply log the warning and continue execution. - // This contrasts with the past approach where developers had to build all modules - // without errors before debugging—slowing down quick clone-and-fix iterations. - Logger::warn(L"Debug mode: {}", errorMessage); -#else - // In release mode, show error dialog as before - MessageBoxW(NULL, - errorMessage.c_str(), - L"PowerToys", - MB_OK | MB_ICONERROR); -#endif - } - } - // Start initial powertoys - start_enabled_powertoys(); - std::wstring product_version = get_product_version(); - Trace::EventLaunch(product_version, isProcessElevated); - PTSettingsHelper::save_last_version_run(product_version); - - if (openSettings) - { - std::optional window; - if (!settingsWindow.empty()) - { - window = winrt::to_hstring(settingsWindow); - } - open_settings_window(window); - } - - if (openOobe) - { - PTSettingsHelper::save_oobe_opened_state(); - open_oobe_window(); - } - else if (openScoobe) - { - open_scoobe_window(); - } - - settings_telemetry::init(); - result = run_message_loop(); - } - catch (std::runtime_error& err) - { - std::string err_what = err.what(); - MessageBoxW(nullptr, std::wstring(err_what.begin(), err_what.end()).c_str(), GET_RESOURCE_STRING(IDS_ERROR).c_str(), MB_OK | MB_ICONERROR | MB_SETFOREGROUND); - result = -1; - } - Trace::UnregisterProvider(); - QuickAccessHost::stop(); - return result; -} - -// If the PT runner is launched as part of some action and manually by a user, e.g. being activated as a COM server -// for background toast notification handling, we should execute corresponding code flow instead of the main code flow. -enum class SpecialMode -{ - None, - Win32ToastNotificationCOMServer, - ToastNotificationHandler, - ReportSuccessfulUpdate -}; - -SpecialMode should_run_in_special_mode(const int n_cmd_args, LPWSTR* cmd_arg_list) -{ - for (size_t i = 1; i < n_cmd_args; ++i) - { - if (!wcscmp(notifications::TOAST_ACTIVATED_LAUNCH_ARG, cmd_arg_list[i])) - { - return SpecialMode::Win32ToastNotificationCOMServer; - } - else if (n_cmd_args == 2 && !wcsncmp(PT_URI_PROTOCOL_SCHEME, cmd_arg_list[i], wcslen(PT_URI_PROTOCOL_SCHEME))) - { - return SpecialMode::ToastNotificationHandler; - } - else if (n_cmd_args == 2 && !wcscmp(cmdArg::UPDATE_REPORT_SUCCESS, cmd_arg_list[i])) - { - return SpecialMode::ReportSuccessfulUpdate; - } - } - - return SpecialMode::None; -} - -int win32_toast_notification_COM_server_mode() -{ - notifications::run_desktop_app_activator_loop(); - return 0; -} - -enum class toast_notification_handler_result -{ - exit_success, - exit_error -}; - -toast_notification_handler_result toast_notification_handler(const std::wstring_view param) -{ - const std::wstring_view cant_drag_elevated_disable = L"cant_drag_elevated_disable/"; - const std::wstring_view couldnt_toggle_powerpreview_modules_disable = L"couldnt_toggle_powerpreview_modules_disable/"; - const std::wstring_view open_settings = L"open_settings/"; - const std::wstring_view open_overview = L"open_overview/"; - const std::wstring_view update_now = L"update_now/"; - - if (param == cant_drag_elevated_disable) - { - return notifications::disable_toast(notifications::ElevatedDontShowAgainRegistryPath) ? toast_notification_handler_result::exit_success : toast_notification_handler_result::exit_error; - } - else if (param.starts_with(update_now)) - { - std::wstring args{ cmdArg::UPDATE_NOW_LAUNCH_STAGE1 }; - LaunchPowerToysUpdate(args.c_str()); - return toast_notification_handler_result::exit_success; - } - else if (param == couldnt_toggle_powerpreview_modules_disable) - { - return notifications::disable_toast(notifications::PreviewModulesDontShowAgainRegistryPath) ? toast_notification_handler_result::exit_success : toast_notification_handler_result::exit_error; - } - else if (param == open_settings) - { - open_menu_from_another_instance(std::nullopt); - return toast_notification_handler_result::exit_success; - } - else if (param == open_overview) - { - open_menu_from_another_instance("Overview"); - return toast_notification_handler_result::exit_success; - } - else - { - return toast_notification_handler_result::exit_error; - } -} - -int WINAPI WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR lpCmdLine, int /*nCmdShow*/) -{ - Shared::Trace::ETWTrace trace{}; - trace.UpdateState(true); - - Gdiplus::GdiplusStartupInput gpStartupInput; - ULONG_PTR gpToken; - GdiplusStartup(&gpToken, &gpStartupInput, NULL); - - winrt::init_apartment(); - - const wchar_t* securityDescriptor = - L"O:BA" // Owner: Builtin (local) administrator - L"G:BA" // Group: Builtin (local) administrator - L"D:" - L"(A;;0x7;;;PS)" // Access allowed on COM_RIGHTS_EXECUTE, _LOCAL, & _REMOTE for Personal self - L"(A;;0x7;;;IU)" // Access allowed on COM_RIGHTS_EXECUTE for Interactive Users - L"(A;;0x3;;;SY)" // Access allowed on COM_RIGHTS_EXECUTE, & _LOCAL for Local system - L"(A;;0x7;;;BA)" // Access allowed on COM_RIGHTS_EXECUTE, _LOCAL, & _REMOTE for Builtin (local) administrator - L"(A;;0x3;;;S-1-15-3-1310292540-1029022339-4008023048-2190398717-53961996-4257829345-603366646)" // Access allowed on COM_RIGHTS_EXECUTE, & _LOCAL for Win32WebViewHost package capability - L"S:" - L"(ML;;NX;;;LW)"; // Integrity label on No execute up for Low mandatory level - initializeCOMSecurity(securityDescriptor); - - int n_cmd_args = 0; - LPWSTR* cmd_arg_list = CommandLineToArgvW(GetCommandLineW(), &n_cmd_args); - switch (should_run_in_special_mode(n_cmd_args, cmd_arg_list)) - { - case SpecialMode::Win32ToastNotificationCOMServer: - return win32_toast_notification_COM_server_mode(); - case SpecialMode::ToastNotificationHandler: - switch (toast_notification_handler(cmd_arg_list[1] + wcslen(PT_URI_PROTOCOL_SCHEME))) - { - case toast_notification_handler_result::exit_error: - return 1; - case toast_notification_handler_result::exit_success: - return 0; - } - [[fallthrough]]; - case SpecialMode::ReportSuccessfulUpdate: - { - notifications::remove_toasts_by_tag(notifications::UPDATING_PROCESS_TOAST_TAG); - notifications::remove_all_scheduled_toasts(); - notifications::show_toast(GET_RESOURCE_STRING(IDS_PT_UPDATE_MESSAGE_BOX_TEXT), - L"PowerToys", - notifications::toast_params{ notifications::UPDATING_PROCESS_TOAST_TAG }); - break; - } - - case SpecialMode::None: - // continue as usual - break; - } - - std::filesystem::path logFilePath(PTSettingsHelper::get_root_save_folder_location()); - logFilePath.append(LogSettings::runnerLogPath); - Logger::init(LogSettings::runnerLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location()); - - const std::string cmdLine{ lpCmdLine }; - Logger::info("Running powertoys with cmd args: {}", cmdLine); - - auto open_settings_it = cmdLine.find("--open-settings"); - const bool open_settings = open_settings_it != std::string::npos; - // Check if opening specific settings window - open_settings_it = cmdLine.find("--open-settings="); - std::string settings_window; - if (open_settings_it != std::string::npos) - { - std::string rest_of_cmd_line{ cmdLine, open_settings_it + std::string{ "--open-settings=" }.size() }; - std::istringstream iss(rest_of_cmd_line); - iss >> settings_window; - } - - // Check if another instance is already running. - wil::unique_mutex_nothrow msi_mutex = create_msi_mutex(); - if (!msi_mutex) - { - open_menu_from_another_instance(settings_window); - return 0; - } - - bool openOobe = false; - try - { - openOobe = !PTSettingsHelper::get_oobe_opened_state(); - } - catch (const std::exception& e) - { - Logger::error("Failed to get or save OOBE state with an exception: {}", e.what()); - } - - bool openScoobe = false; - bool showRestartNotificationAfterUpdate = false; - try - { - std::wstring last_version_run = PTSettingsHelper::get_last_version_run(); - const auto product_version = get_product_version(); - openScoobe = product_version != last_version_run; - showRestartNotificationAfterUpdate = openScoobe; - Logger::info(L"Scoobe: product_version={} last_version_run={}", product_version, last_version_run); - } - catch (const std::exception& e) - { - Logger::error("Failed to get last version with an exception: {}", e.what()); - } - - int result = 0; - try - { - // Singletons initialization order needs to be preserved, first events and - // then modules to guarantee the reverse destruction order. - modules(); - - std::thread{ [] { - auto state = UpdateState::read(); - if (state.state == UpdateState::upToDate) - { - updating::cleanup_updates(); - } - } }.detach(); - - auto general_settings = load_general_settings(); - - // Apply the general settings but don't save it as the modules() variable has not been loaded yet - apply_general_settings(general_settings, false); - const bool elevated = is_process_elevated(); - const bool with_dont_elevate_arg = cmdLine.find("--dont-elevate") != std::string::npos; - const bool run_elevated_setting = general_settings.GetNamedBoolean(L"run_elevated", false); - const bool with_restartedElevated_arg = cmdLine.find("--restartedElevated") != std::string::npos; - - // Update scoobe behavior based on setting and gpo - bool scoobeSettingDisabled = general_settings.GetNamedBoolean(L"show_whats_new_after_updates", true) == false; - bool scoobeDisabledByGpo = powertoys_gpo::getDisableShowWhatsNewAfterUpdatesValue() == powertoys_gpo::gpo_rule_configured_enabled; - if (openScoobe && (scoobeSettingDisabled || scoobeDisabledByGpo)) - { - // Scoobe should show after an update, but is disabled by policy or setting - Logger::info(L"Scoobe: Showing scoobe after updates is disabled by setting or by GPO."); - openScoobe = false; - } - - bool dataDiagnosticsDisabledByGpo = powertoys_gpo::getAllowDataDiagnosticsValue() == powertoys_gpo::gpo_rule_configured_disabled; - if (dataDiagnosticsDisabledByGpo) - { - Logger::info(L"Data diagnostics: Data diagnostics is disabled by GPO."); - PTSettingsHelper::save_data_diagnostics(false); - } - - if (elevated && with_dont_elevate_arg && !run_elevated_setting) - { - Logger::info("Scheduling restart as non elevated"); - schedule_restart_as_non_elevated(); - result = 0; - } - else if (elevated || !run_elevated_setting || with_dont_elevate_arg || (!elevated && with_restartedElevated_arg)) - { - // The condition (!elevated && with_restartedElevated_arg) solves issue #19307. Restart elevated loop detected, running non-elevated - if (!elevated && with_restartedElevated_arg) - { - Logger::info("Restart as elevated failed. Running non-elevated."); - } - - result = runner(elevated, open_settings, settings_window, openOobe, openScoobe, showRestartNotificationAfterUpdate); - - if (result == 0) - { - // Save settings on closing, if closed 'normal' - PTSettingsHelper::save_general_settings(get_general_settings().to_json()); - } - } - else - { - Logger::info("Scheduling restart as elevated"); - schedule_restart_as_elevated(open_settings); - result = 0; - } - } - catch (std::runtime_error& err) - { - std::string err_what = err.what(); - MessageBoxW(nullptr, std::wstring(err_what.begin(), err_what.end()).c_str(), GET_RESOURCE_STRING(IDS_ERROR).c_str(), MB_OK | MB_ICONERROR); - result = -1; - } - - trace.Flush(); - trace.UpdateState(false); - - // We need to release the mutexes to be able to restart the application - if (msi_mutex) - { - msi_mutex.reset(nullptr); - } - - if (is_restart_scheduled()) - { - modules().clear(); - if (!restart_if_scheduled()) - { - // If it's not possible to restart non-elevated due to some condition in the user's configuration, user should start PowerToys manually. - Logger::warn("Scheduled restart failed. Couldn't restart non-elevated. PowerToys exits here because retrying it would just mean failing in a loop."); - } - } - stop_tray_icon(); - - return result; -} diff --git a/src/runner/pch.cpp b/src/runner/pch.cpp deleted file mode 100644 index 1d9f38c57d..0000000000 --- a/src/runner/pch.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "pch.h" diff --git a/src/runner/pch.h b/src/runner/pch.h deleted file mode 100644 index 537bef12d6..0000000000 --- a/src/runner/pch.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include diff --git a/src/runner/powertoy_module.cpp b/src/runner/powertoy_module.cpp deleted file mode 100644 index eb1f7c4fd7..0000000000 --- a/src/runner/powertoy_module.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "pch.h" -#include "powertoy_module.h" -#include "centralized_kb_hook.h" -#include "centralized_hotkeys.h" -#include -#include - -std::map& modules() -{ - static std::map modules; - return modules; -} - -PowertoyModule load_powertoy(const std::wstring_view filename) -{ - auto handle = winrt::check_pointer(LoadLibraryW(filename.data())); - auto create = reinterpret_cast(GetProcAddress(handle, "powertoy_create")); - if (!create) - { - FreeLibrary(handle); - winrt::throw_last_error(); - } - auto pt_module = create(); - if (!pt_module) - { - FreeLibrary(handle); - winrt::throw_hresult(winrt::hresult(E_POINTER)); - } - return PowertoyModule(pt_module, handle); -} - -json::JsonObject PowertoyModule::json_config() const -{ - int size = 0; - pt_module->get_config(nullptr, &size); - std::wstring result; - result.resize(static_cast(size) - 1); - pt_module->get_config(result.data(), &size); - return json::JsonObject::Parse(result); -} - -PowertoyModule::PowertoyModule(PowertoyModuleIface* pt_module, HMODULE handle) : - handle(handle), pt_module(pt_module), hkmng(HotkeyConflictDetector::HotkeyConflictManager::GetInstance()) -{ - if (!pt_module) - { - throw std::runtime_error("Module not initialized"); - } - - remove_hotkey_records(); - update_hotkeys(); - UpdateHotkeyEx(); -} - -void PowertoyModule::update_hotkeys() -{ - CentralizedKeyboardHook::ClearModuleHotkeys(pt_module->get_key()); - - size_t hotkeyCount = pt_module->get_hotkeys(nullptr, 0); - std::vector hotkeys(hotkeyCount); - pt_module->get_hotkeys(hotkeys.data(), hotkeyCount); - - auto modulePtr = pt_module.get(); - - for (size_t i = 0; i < hotkeyCount; i++) - { - if (hotkeys[i].isShown) - { - hkmng.AddHotkey(hotkeys[i], pt_module->get_key(), static_cast(i), pt_module->is_enabled()); - - CentralizedKeyboardHook::SetHotkeyAction(pt_module->get_key(), hotkeys[i], [modulePtr, i] { - Logger::trace(L"{} hotkey is invoked from Centralized keyboard hook", modulePtr->get_key()); - return modulePtr->on_hotkey(i); - }); - } - } -} - -void PowertoyModule::UpdateHotkeyEx() -{ - CentralizedHotkeys::UnregisterHotkeysForModule(pt_module->get_key()); - - auto container = pt_module->GetHotkeyEx(); - if (container.has_value() && pt_module->is_enabled()) - { - hkmng.RemoveHotkeyByModule(pt_module->get_key()); - - auto hotkey = container.value(); - auto modulePtr = pt_module.get(); - auto action = [modulePtr](WORD /*modifiersMask*/, WORD /*vkCode*/) { - Logger::trace(L"{} hotkey Ex is invoked from Centralized keyboard hook", modulePtr->get_key()); - modulePtr->OnHotkeyEx(); - }; - - HotkeyConflictDetector::Hotkey _hotkey = HotkeyConflictDetector::ShortcutToHotkey({ hotkey.modifiersMask, hotkey.vkCode }); - hkmng.AddHotkey(_hotkey, pt_module->get_key(), 0, pt_module->is_enabled()); // This is the only one activation hotkey, so we use "0" as the name. - - CentralizedHotkeys::AddHotkeyAction({ hotkey.modifiersMask, hotkey.vkCode }, { pt_module->get_key(), action }); - } - - // HACK: - // Just for enabling the shortcut guide legacy behavior of pressing the Windows Key. - // This is not the sort of behavior we'd like to have generalized on other modules. - // But this was a way to bring back the long windows key behavior that the community wanted back while maintaining the separate process. - if (pt_module->keep_track_of_pressed_win_key()) - { - auto modulePtr = pt_module.get(); - auto action = [modulePtr] { - modulePtr->OnHotkeyEx(); - return false; - }; - CentralizedKeyboardHook::AddPressedKeyAction(pt_module->get_key(), VK_LWIN, pt_module->milliseconds_win_key_must_be_pressed(), action); - CentralizedKeyboardHook::AddPressedKeyAction(pt_module->get_key(), VK_RWIN, pt_module->milliseconds_win_key_must_be_pressed(), action); - } -} diff --git a/src/runner/powertoy_module.h b/src/runner/powertoy_module.h deleted file mode 100644 index 81e020820c..0000000000 --- a/src/runner/powertoy_module.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include "hotkey_conflict_detector.h" - -#include - -struct PowertoyModuleDeleter -{ - void operator()(PowertoyModuleIface* pt_module) const - { - if (pt_module) - { - pt_module->destroy(); - } - } -}; - -struct PowertoyModuleDLLDeleter -{ - using pointer = HMODULE; - void operator()(HMODULE handle) const - { - FreeLibrary(handle); - } -}; - -class PowertoyModule -{ -public: - PowertoyModule(PowertoyModuleIface* pt_module, HMODULE handle); - - inline PowertoyModuleIface* operator->() - { - return pt_module.get(); - } - - json::JsonObject json_config() const; - - void update_hotkeys(); - - void UpdateHotkeyEx(); - - inline void remove_hotkey_records() - { - hkmng.RemoveHotkeyByModule(pt_module->get_key()); - } - -private: - HotkeyConflictDetector::HotkeyConflictManager& hkmng; - std::unique_ptr handle; - std::unique_ptr pt_module; - - -}; - -PowertoyModule load_powertoy(const std::wstring_view filename); -std::map& modules(); diff --git a/src/runner/quick_access_host.cpp b/src/runner/quick_access_host.cpp deleted file mode 100644 index b546ee244e..0000000000 --- a/src/runner/quick_access_host.cpp +++ /dev/null @@ -1,296 +0,0 @@ -#include "pch.h" -#include "quick_access_host.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -extern void receive_json_send_to_main_thread(const std::wstring& msg); - -namespace -{ - wil::unique_handle quick_access_process; - wil::unique_handle quick_access_job; - wil::unique_handle show_event; - wil::unique_handle exit_event; - std::wstring show_event_name; - std::wstring exit_event_name; - std::wstring runner_pipe_name; - std::wstring app_pipe_name; - std::unique_ptr quick_access_ipc; - std::mutex quick_access_mutex; - - bool is_process_active_locked() - { - if (!quick_access_process) - { - return false; - } - - DWORD exit_code = 0; - if (!GetExitCodeProcess(quick_access_process.get(), &exit_code)) - { - Logger::warn(L"QuickAccessHost: failed to read Quick Access process exit code. error={}.", GetLastError()); - return false; - } - - return exit_code == STILL_ACTIVE; - } - - void reset_state_locked() - { - if (quick_access_ipc) - { - quick_access_ipc->end(); - quick_access_ipc.reset(); - } - - quick_access_process.reset(); - quick_access_job.reset(); - show_event.reset(); - exit_event.reset(); - show_event_name.clear(); - exit_event_name.clear(); - runner_pipe_name.clear(); - app_pipe_name.clear(); - } - - std::wstring build_event_name(const wchar_t* suffix) - { - std::wstring name = L"Local\\PowerToysQuickAccess_"; - name += std::to_wstring(GetCurrentProcessId()); - if (suffix) - { - name += suffix; - } - return name; - } - - std::wstring build_command_line(const std::wstring& exe_path) - { - std::wstring command_line = L"\""; - command_line += exe_path; - command_line += L"\" --show-event=\""; - command_line += show_event_name; - command_line += L"\" --exit-event=\""; - command_line += exit_event_name; - command_line += L"\""; - if (!runner_pipe_name.empty()) - { - command_line.append(L" --runner-pipe=\""); - command_line += runner_pipe_name; - command_line += L"\""; - } - if (!app_pipe_name.empty()) - { - command_line.append(L" --app-pipe=\""); - command_line += app_pipe_name; - command_line += L"\""; - } - return command_line; - } -} - -namespace QuickAccessHost -{ - bool is_running() - { - std::scoped_lock lock(quick_access_mutex); - return is_process_active_locked(); - } - - void start() - { - Logger::info(L"QuickAccessHost::start() called"); - std::scoped_lock lock(quick_access_mutex); - if (is_process_active_locked()) - { - Logger::info(L"QuickAccessHost::start: process already active"); - return; - } - - reset_state_locked(); - - show_event_name = build_event_name(L"_Show"); - exit_event_name = build_event_name(L"_Exit"); - - show_event.reset(CreateEventW(nullptr, FALSE, FALSE, show_event_name.c_str())); - if (!show_event) - { - Logger::error(L"QuickAccessHost: failed to create show event. error={}.", GetLastError()); - reset_state_locked(); - return; - } - - exit_event.reset(CreateEventW(nullptr, FALSE, FALSE, exit_event_name.c_str())); - if (!exit_event) - { - Logger::error(L"QuickAccessHost: failed to create exit event. error={}.", GetLastError()); - reset_state_locked(); - return; - } - - runner_pipe_name = L"\\\\.\\pipe\\powertoys_quick_access_runner_"; - app_pipe_name = L"\\\\.\\pipe\\powertoys_quick_access_ui_"; - UUID temp_uuid; - wchar_t* uuid_chars = nullptr; - if (UuidCreate(&temp_uuid) == RPC_S_UUID_NO_ADDRESS) - { - Logger::warn(L"QuickAccessHost: failed to create UUID for pipe names. error={}.", GetLastError()); - } - else if (UuidToString(&temp_uuid, reinterpret_cast(&uuid_chars)) != RPC_S_OK) - { - Logger::warn(L"QuickAccessHost: failed to convert UUID to string. error={}.", GetLastError()); - } - - if (uuid_chars != nullptr) - { - runner_pipe_name += std::wstring(uuid_chars); - app_pipe_name += std::wstring(uuid_chars); - RpcStringFree(reinterpret_cast(&uuid_chars)); - uuid_chars = nullptr; - } - else - { - const std::wstring fallback_suffix = std::to_wstring(GetTickCount64()); - runner_pipe_name += fallback_suffix; - app_pipe_name += fallback_suffix; - } - - HANDLE token_handle = nullptr; - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token_handle)) - { - Logger::error(L"QuickAccessHost: failed to open process token. error={}.", GetLastError()); - reset_state_locked(); - return; - } - - wil::unique_handle token(token_handle); - quick_access_ipc.reset(new (std::nothrow) TwoWayPipeMessageIPC(runner_pipe_name, app_pipe_name, receive_json_send_to_main_thread)); - if (!quick_access_ipc) - { - Logger::error(L"QuickAccessHost: failed to allocate IPC instance."); - reset_state_locked(); - return; - } - - try - { - quick_access_ipc->start(token.get()); - } - catch (...) - { - Logger::error(L"QuickAccessHost: failed to start IPC server for Quick Access."); - reset_state_locked(); - return; - } - - const std::wstring exe_path = get_module_folderpath() + L"\\WinUI3Apps\\PowerToys.QuickAccess.exe"; - if (GetFileAttributesW(exe_path.c_str()) == INVALID_FILE_ATTRIBUTES) - { - Logger::warn(L"QuickAccessHost: missing Quick Access executable at {}", exe_path); - reset_state_locked(); - return; - } - - const std::wstring command_line = build_command_line(exe_path); - std::vector command_line_buffer(command_line.begin(), command_line.end()); - command_line_buffer.push_back(L'\0'); - STARTUPINFOW startup_info{}; - startup_info.cb = sizeof(startup_info); - PROCESS_INFORMATION process_info{}; - - BOOL created = CreateProcessW(exe_path.c_str(), command_line_buffer.data(), nullptr, nullptr, FALSE, CREATE_SUSPENDED, nullptr, nullptr, &startup_info, &process_info); - if (!created) - { - Logger::error(L"QuickAccessHost: failed to launch Quick Access host. error={}.", GetLastError()); - reset_state_locked(); - return; - } - - quick_access_process.reset(process_info.hProcess); - - // Assign to job object to ensure the process is killed if the runner exits unexpectedly (e.g. debugging stop) - quick_access_job.reset(CreateJobObjectW(nullptr, nullptr)); - if (quick_access_job) - { - JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; - jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; - if (!SetInformationJobObject(quick_access_job.get(), JobObjectExtendedLimitInformation, &jeli, sizeof(jeli))) - { - Logger::warn(L"QuickAccessHost: failed to set job object information. error={}", GetLastError()); - } - else - { - if (!AssignProcessToJobObject(quick_access_job.get(), quick_access_process.get())) - { - Logger::warn(L"QuickAccessHost: failed to assign process to job object. error={}", GetLastError()); - } - } - } - else - { - Logger::warn(L"QuickAccessHost: failed to create job object. error={}", GetLastError()); - } - - ResumeThread(process_info.hThread); - CloseHandle(process_info.hThread); - } - - void show() - { - start(); - std::scoped_lock lock(quick_access_mutex); - - if (show_event) - { - if (!SetEvent(show_event.get())) - { - Logger::warn(L"QuickAccessHost: failed to signal show event. error={}.", GetLastError()); - } - } - } - - void stop() - { - Logger::info(L"QuickAccessHost::stop() called"); - std::unique_lock lock(quick_access_mutex); - if (exit_event) - { - SetEvent(exit_event.get()); - } - - if (quick_access_process) - { - const DWORD wait_result = WaitForSingleObject(quick_access_process.get(), 2000); - Logger::info(L"QuickAccessHost::stop: WaitForSingleObject result={}", wait_result); - if (wait_result == WAIT_TIMEOUT) - { - Logger::warn(L"QuickAccessHost: Quick Access process did not exit in time, terminating."); - if (!TerminateProcess(quick_access_process.get(), 0)) - { - Logger::error(L"QuickAccessHost: failed to terminate Quick Access process. error={}.", GetLastError()); - } - else - { - Logger::info(L"QuickAccessHost: TerminateProcess succeeded."); - WaitForSingleObject(quick_access_process.get(), 5000); - } - } - else if (wait_result == WAIT_FAILED) - { - Logger::error(L"QuickAccessHost: failed while waiting for Quick Access process. error={}.", GetLastError()); - } - } - - reset_state_locked(); - } -} diff --git a/src/runner/quick_access_host.h b/src/runner/quick_access_host.h deleted file mode 100644 index 22a65a9c26..0000000000 --- a/src/runner/quick_access_host.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include -#include - -namespace QuickAccessHost -{ - void start(); - void show(); - void stop(); - bool is_running(); -} diff --git a/src/runner/resource.base.h b/src/runner/resource.base.h deleted file mode 100644 index 7037f4342d..0000000000 --- a/src/runner/resource.base.h +++ /dev/null @@ -1,23 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by runner.rc - -////////////////////////////// -// Non-localizable - -#define FILE_DESCRIPTION "PowerToys.Runner" -#define INTERNAL_NAME "PowerToys" -#define ORIGINAL_FILENAME "PowerToys.exe" - -// Non-localizable -////////////////////////////// - -#define APPICON 101 -#define ID_TRAY_MENU 102 - -#define ID_CLOSE_MENU_COMMAND 40001 -#define ID_SETTINGS_MENU_COMMAND 40002 -#define ID_ABOUT_MENU_COMMAND 40003 -#define ID_REPORT_BUG_COMMAND 40004 -#define ID_DOCUMENTATION_MENU_COMMAND 40005 -#define ID_QUICK_ACCESS_MENU_COMMAND 40006 diff --git a/src/runner/restart_elevated.cpp b/src/runner/restart_elevated.cpp deleted file mode 100644 index c14b63d479..0000000000 --- a/src/runner/restart_elevated.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "pch.h" -#include "restart_elevated.h" - -#include - -enum State -{ - None, - RestartAsElevated, - RestartAsElevatedOpenSettings, - RestartAsNonElevated, - RestartAsNonElevatedOpenSettings -}; -static State state = None; - -void schedule_restart_as_elevated(bool openSettings) -{ - state = openSettings ? RestartAsElevatedOpenSettings : RestartAsElevated; -} - -void schedule_restart_as_non_elevated() -{ - state = RestartAsNonElevated; -} - -void schedule_restart_as_non_elevated(bool openSettings) -{ - state = openSettings ? RestartAsNonElevatedOpenSettings : RestartAsNonElevated; -} - -bool is_restart_scheduled() -{ - return state != None; -} - -bool restart_if_scheduled() -{ - // Make sure we have enough room, even for the long (\\?\) paths - constexpr DWORD exe_path_size = 0xFFFF; - auto exe_path = std::make_unique(exe_path_size); - GetModuleFileNameW(nullptr, exe_path.get(), exe_path_size); - switch (state) - { - case RestartAsElevated: - return run_elevated(exe_path.get(), L"--restartedElevated"); - case RestartAsElevatedOpenSettings: - return run_elevated(exe_path.get(), L"--restartedElevated --open-settings"); - case RestartAsNonElevatedOpenSettings: - return run_non_elevated(exe_path.get(), L"--open-settings", NULL); - case RestartAsNonElevated: - return run_non_elevated(exe_path.get(), L"", NULL); - default: - return false; - } -} - -bool restart_same_elevation() -{ - constexpr DWORD exe_path_size = 0xFFFF; - auto exe_path = std::make_unique(exe_path_size); - GetModuleFileNameW(nullptr, exe_path.get(), exe_path_size); - return run_same_elevation(exe_path.get(), L"", nullptr); -} diff --git a/src/runner/restart_elevated.h b/src/runner/restart_elevated.h deleted file mode 100644 index 9ffb545c91..0000000000 --- a/src/runner/restart_elevated.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once -void schedule_restart_as_elevated(bool openSettings); -void schedule_restart_as_non_elevated(); -void schedule_restart_as_non_elevated(bool openSettings); -bool is_restart_scheduled(); -bool restart_if_scheduled(); -bool restart_same_elevation(); diff --git a/src/runner/runner.base.rc b/src/runner/runner.base.rc deleted file mode 100644 index 9c6560cc97..0000000000 Binary files a/src/runner/runner.base.rc and /dev/null differ diff --git a/src/runner/runner.vcxproj b/src/runner/runner.vcxproj deleted file mode 100644 index 88b74e3faa..0000000000 --- a/src/runner/runner.vcxproj +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - - 81010002 - - - - PackageReference - - native,Version=v0.0 - - Windows - $(WindowsTargetPlatformVersion) - - - 15.0 - {9412D5C6-2CF2-4FC2-A601-B55508EA9B27} - powertoys - runner - - - - - - - - - - - - Application - - None - true - true - - - - - - - - PowerToys - - - - ..\common\inc;..\common\os-detection;..\common\Telemetry;..;..\modules;%(AdditionalIncludeDirectories) - - - AsInvoker - $(OutDir)$(TargetName)$(TargetExt) - Shcore.lib;gdiplus.lib;Msi.lib;WindowsApp.lib;taskschd.lib;Rstrtmgr.lib;Shlwapi.lib;dwmapi.lib;%(AdditionalDependencies) - - - false - - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - Document - $(OutDir)\svgs - - - - - {7319089e-46d6-4400-bc65-e39bdf1416ee} - - - {caba8dfb-823b-4bf2-93ac-3f31984150d9} - - - {d9b8fc84-322a-4f9f-bbb9-20915c47ddfd} - - - {1d5be09d-78c0-4fd7-af00-ae7c1af7c525} - - - {8f021b46-362b-485c-bfba-ccf83e820cbd} - - - {98537082-0fdb-40de-abd8-0dc5a4269bab} - - - {17da04df-e393-4397-9cf0-84dabe11032e} - - - - - - - - - - - true - true - true - true - $(OutDir)\svgs - $(OutDir)\svgs - $(OutDir)\svgs - $(OutDir)\svgs - - - true - true - true - true - $(OutDir)\svgs - $(OutDir)\svgs - $(OutDir)\svgs - $(OutDir)\svgs - - - - - - - - - - - - NotUsing - - - - \ No newline at end of file diff --git a/src/runner/runner.vcxproj.filters b/src/runner/runner.vcxproj.filters deleted file mode 100644 index 4d1e82ff0d..0000000000 --- a/src/runner/runner.vcxproj.filters +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - Utils - - - - - {bc27e9c1-8afa-4d62-8179-789f4651c0b6} - - - {74d0b535-16ee-46cc-9adf-dc4668bbcfda} - - - {18a4e642-9246-4494-b916-8505aed19914} - - - - - - - - - - - - - - - - - - - Resource Files - - - - - - \ No newline at end of file diff --git a/src/runner/settings_telemetry.cpp b/src/runner/settings_telemetry.cpp deleted file mode 100644 index 7bab24d448..0000000000 --- a/src/runner/settings_telemetry.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#pragma once -#include "pch.h" -#include "settings_telemetry.h" -#include -#include -#include -#include -#include -#include -#include "powertoy_module.h" - -using JsonObject = winrt::Windows::Data::Json::JsonObject; -using JsonValue = winrt::Windows::Data::Json::JsonValue; - -std::wstring get_info_file_path() -{ - std::filesystem::path settingsFilePath(PTSettingsHelper::get_root_save_folder_location()); - settingsFilePath = settingsFilePath.append(settings_telemetry::send_info_file); - return settingsFilePath.wstring(); -} - -std::optional get_last_send_time() -{ - auto settings = json::from_file(get_info_file_path()); - if (!settings.has_value() || !settings.value().HasKey(settings_telemetry::last_send_option)) - { - return std::nullopt; - } - - auto stringTime = (std::wstring)settings.value().GetNamedString(settings_telemetry::last_send_option); - return timeutil::from_string(stringTime); -} - -void update_last_send_time(time_t time) -{ - auto settings = JsonObject(); - settings.SetNamedValue(settings_telemetry::last_send_option, JsonValue::CreateStringValue(timeutil::to_string(time))); - json::to_file(get_info_file_path(), settings); -} - -void send() -{ - for (auto& [name, powertoy] : modules()) - { - if (powertoy->is_enabled()) - { - try - { - powertoy->send_settings_telemetry(); - } - catch (...) - { - Logger::error(L"Failed to send telemetry for {} module", name); - } - } - } -} - -void run_interval() -{ - auto time = get_last_send_time(); - long long wait_time = 24 * 3600; - long long left_to_wait = 0; - if (time.has_value()) - { - left_to_wait = max(0, wait_time - timeutil::diff::in_seconds(timeutil::now(), time.value())); - } - - Sleep(static_cast(left_to_wait * 1000)); - send(); - update_last_send_time(timeutil::now()); - - while (true) - { - Sleep(static_cast(wait_time * 1000)); - send(); - update_last_send_time(timeutil::now()); - } -} - -void settings_telemetry::init() -{ - std::thread([]() { - try - { - run_interval(); - } - catch (...) - { - Logger::error("Failed to send settings telemetry"); - } - }).detach(); -} diff --git a/src/runner/settings_telemetry.h b/src/runner/settings_telemetry.h deleted file mode 100644 index c72972914a..0000000000 --- a/src/runner/settings_telemetry.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once -namespace settings_telemetry -{ - static std::wstring send_info_file = L"settings-telemetry.json"; - static std::wstring last_send_option = L"last_send_time"; - void init(); -} \ No newline at end of file diff --git a/src/runner/settings_window.cpp b/src/runner/settings_window.cpp deleted file mode 100644 index 022ad9d76c..0000000000 --- a/src/runner/settings_window.cpp +++ /dev/null @@ -1,960 +0,0 @@ -#include "pch.h" -#include -#include -#include -#include - -#include "powertoy_module.h" -#include -#include -#include "tray_icon.h" -#include "general_settings.h" -#include "restart_elevated.h" -#include "UpdateUtils.h" -#include "centralized_kb_hook.h" -#include "Generated files/resource.h" -#include "hotkey_conflict_detector.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "settings_window.h" -#include "bug_report.h" - -#define BUFSIZE 1024 - -TwoWayPipeMessageIPC* current_settings_ipc = NULL; -std::mutex ipc_mutex; -std::atomic_bool g_isLaunchInProgress = false; -std::atomic_bool isUpdateCheckThreadRunning = false; -HANDLE g_terminateSettingsEvent = CreateEventW(nullptr, false, false, CommonSharedConstants::TERMINATE_SETTINGS_SHARED_EVENT); - -json::JsonObject get_power_toys_settings() -{ - json::JsonObject result; - for (const auto& [name, powertoy] : modules()) - { - try - { - result.SetNamedValue(name, powertoy.json_config()); - } - catch (...) - { - Logger::error(L"get_power_toys_settings(): got malformed json for {} module", name); - } - } - return result; -} - -json::JsonObject get_all_settings() -{ - json::JsonObject result; - - result.SetNamedValue(L"general", get_general_settings().to_json()); - result.SetNamedValue(L"powertoys", get_power_toys_settings()); - return result; -} - -std::optional dispatch_json_action_to_module(const json::JsonObject& powertoys_configs) -{ - std::optional result; - for (const auto& powertoy_element : powertoys_configs) - { - const std::wstring name{ powertoy_element.Key().c_str() }; - // Currently, there is only one custom action in the general settings screen, - // so it has to be the "restart as (non-)elevated" button. - if (name == L"general") - { - try - { - const auto value = powertoy_element.Value().GetObjectW(); - const auto action = value.GetNamedString(L"action_name"); - if (action == L"restart_elevation") - { - if (is_process_elevated()) - { - schedule_restart_as_non_elevated(); - PostQuitMessage(0); - } - else - { - schedule_restart_as_elevated(true); - PostQuitMessage(0); - } - } - else if (action == L"restart_maintain_elevation") - { - // this was added to restart and maintain elevation, which is needed after settings are change from outside the normal process. - // since a normal PostQuitMessage(0) would usually cause this process to save its in memory settings to disk, we need to - // send a PostQuitMessage(1) and check for that on exit, and skip the settings-flush. - auto loaded = PTSettingsHelper::load_general_settings(); - - if (is_process_elevated()) - { - schedule_restart_as_elevated(true); - PostQuitMessage(1); - } - else - { - schedule_restart_as_non_elevated(true); - PostQuitMessage(1); - } - } - else if (action == L"check_for_updates") - { - bool expected_isUpdateCheckThreadRunning = false; - if (isUpdateCheckThreadRunning.compare_exchange_strong(expected_isUpdateCheckThreadRunning, true)) - { - std::thread([]() { - CheckForUpdatesCallback(); - isUpdateCheckThreadRunning.store(false); - }).detach(); - } - } - else if (action == L"request_update_state_date") - { - json::JsonObject json; - - auto update_state = UpdateState::read(); - if (update_state.githubUpdateLastCheckedDate) - { - const time_t date = *update_state.githubUpdateLastCheckedDate; - json.SetNamedValue(L"updateStateDate", json::value(std::to_wstring(date))); - } - - result.emplace(json.Stringify()); - } - } - catch (...) - { - } - } - else if (modules().find(name) != modules().end()) - { - const auto element = powertoy_element.Value().Stringify(); - modules().at(name)->call_custom_action(element.c_str()); - } - } - - return result; -} - -void send_json_config_to_module(const std::wstring& module_key, const std::wstring& settings, bool hotkeyUpdated) -{ - auto moduleIt = modules().find(module_key); - if (moduleIt != modules().end()) - { - moduleIt->second->set_config(settings.c_str()); - - if (hotkeyUpdated) - { - moduleIt->second.remove_hotkey_records(); - moduleIt->second.update_hotkeys(); - moduleIt->second.UpdateHotkeyEx(); - } - } -} - -void dispatch_json_config_to_modules(const json::JsonObject& powertoys_configs) -{ - for (const auto& powertoy_element : powertoys_configs) - { - const auto element = powertoy_element.Value().Stringify(); - - /* As PowerToys Run hotkeys are not registered by the runner, hotkey updates are - * triggered only when hotkey properties change to avoid incorrect conflict detection; - * otherwise, the existing logic remains. - */ - auto settings = powertoy_element.Value().GetObjectW(); - bool hotkeyUpdated = true; - if (settings.HasKey(L"properties")) - { - const auto properties = settings.GetNamedObject(L"properties"); - - // Currently, only PowerToys Run settings use the 'hotkey_changed' property. - if (properties.HasKey(L"hotkey_changed")) - { - json::get(properties, L"hotkey_changed", hotkeyUpdated, true); - } - } - - send_json_config_to_module(powertoy_element.Key().c_str(), element.c_str(), hotkeyUpdated); - } -}; - -void dispatch_received_json(const std::wstring& json_to_parse) -{ - json::JsonObject j; - const bool ok = json::JsonObject::TryParse(json_to_parse, j); - if (!ok) - { - Logger::error(L"dispatch_received_json: got malformed json: {}", json_to_parse); - return; - } - - Logger::info(L"dispatch_received_json: {}", json_to_parse); - - for (const auto& base_element : j) - { - const auto name = base_element.Key(); - const auto value = base_element.Value(); - - if (name == L"general") - { - apply_general_settings(value.GetObjectW()); - // const std::wstring settings_string{ get_all_settings().Stringify().c_str() }; - // { - // std::unique_lock lock{ ipc_mutex }; - // if (current_settings_ipc) - // current_settings_ipc->send(settings_string); - // } - } - else if (name == L"module_status") - { - // Handle single module enable/disable update - // Expected format: {"module_status": {"ModuleName": true/false}} - apply_module_status_update(value.GetObjectW()); - } - else if (name == L"powertoys") - { - dispatch_json_config_to_modules(value.GetObjectW()); - const std::wstring settings_string{ get_all_settings().Stringify().c_str() }; - { - std::unique_lock lock{ ipc_mutex }; - if (current_settings_ipc) - current_settings_ipc->send(settings_string); - } - } - else if (name == L"refresh") - { - const std::wstring settings_string{ get_all_settings().Stringify().c_str() }; - { - std::unique_lock lock{ ipc_mutex }; - if (current_settings_ipc) - current_settings_ipc->send(settings_string); - } - } - else if (name == L"action") - { - auto result = dispatch_json_action_to_module(value.GetObjectW()); - if (result.has_value()) - { - { - std::unique_lock lock{ ipc_mutex }; - if (current_settings_ipc) - current_settings_ipc->send(result.value()); - } - } - } - else if (name == L"bugreport") - { - launch_bug_report(); - } - else if (name == L"bug_report_status") - { - json::JsonObject result; - result.SetNamedValue(L"bug_report_running", winrt::Windows::Data::Json::JsonValue::CreateBooleanValue(is_bug_report_running())); - std::unique_lock lock{ ipc_mutex }; - if (current_settings_ipc) - current_settings_ipc->send(result.Stringify().c_str()); - } - else if (name == L"killrunner") - { - const auto pt_main_window = FindWindowW(pt_tray_icon_window_class, nullptr); - if (pt_main_window != nullptr) - { - SendMessageW(pt_main_window, WM_CLOSE, 0, 0); - } - } - else if (name == L"language") - { - constexpr const wchar_t* language_filename = L"\\language.json"; - const std::wstring save_file_location = PTSettingsHelper::get_root_save_folder_location() + language_filename; - json::to_file(save_file_location, j); - } - else if (name == L"check_hotkey_conflict") - { - try - { - PowertoyModuleIface::Hotkey hotkey; - hotkey.win = value.GetObjectW().GetNamedBoolean(L"win", false); - hotkey.ctrl = value.GetObjectW().GetNamedBoolean(L"ctrl", false); - hotkey.shift = value.GetObjectW().GetNamedBoolean(L"shift", false); - hotkey.alt = value.GetObjectW().GetNamedBoolean(L"alt", false); - hotkey.key = static_cast(value.GetObjectW().GetNamedNumber(L"key", 0)); - - std::wstring requestId = value.GetObjectW().GetNamedString(L"request_id", L"").c_str(); - - auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); - bool hasConflict = hkmng.HasConflict(hotkey); - - json::JsonObject response; - response.SetNamedValue(L"response_type", json::JsonValue::CreateStringValue(L"hotkey_conflict_result")); - response.SetNamedValue(L"request_id", json::JsonValue::CreateStringValue(requestId)); - response.SetNamedValue(L"has_conflict", json::JsonValue::CreateBooleanValue(hasConflict)); - - if (hasConflict) - { - auto conflicts = hkmng.GetAllConflicts(hotkey); - if (!conflicts.empty()) - { - // Include all conflicts in the response - json::JsonArray allConflicts; - for (const auto& conflict : conflicts) - { - json::JsonObject conflictObj; - conflictObj.SetNamedValue(L"module", json::JsonValue::CreateStringValue(conflict.moduleName)); - conflictObj.SetNamedValue(L"hotkeyID", json::JsonValue::CreateNumberValue(conflict.hotkeyID)); - allConflicts.Append(conflictObj); - } - response.SetNamedValue(L"all_conflicts", allConflicts); - } - } - - std::unique_lock lock{ ipc_mutex }; - if (current_settings_ipc) - { - current_settings_ipc->send(response.Stringify().c_str()); - } - } - catch (...) - { - Logger::error(L"Failed to process hotkey conflict check request"); - } - } - else if (name == L"get_all_hotkey_conflicts") - { - try - { - auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); - auto conflictsJson = hkmng.GetHotkeyConflictsAsJson(); - - // Add response type identifier - conflictsJson.SetNamedValue(L"response_type", json::JsonValue::CreateStringValue(L"all_hotkey_conflicts")); - - std::unique_lock lock{ ipc_mutex }; - if (current_settings_ipc) - { - current_settings_ipc->send(conflictsJson.Stringify().c_str()); - } - } - catch (...) - { - Logger::error(L"Failed to process get all hotkey conflicts request"); - } - } - } - return; -} - -void dispatch_received_json_callback(PVOID data) -{ - std::wstring* msg = static_cast(data); - dispatch_received_json(*msg); - delete msg; -} - -void receive_json_send_to_main_thread(const std::wstring& msg) -{ - std::wstring* copy = new std::wstring(msg); - dispatch_run_on_main_ui_thread(dispatch_received_json_callback, copy); -} - -// Try to run the Settings process with non-elevated privileges. -BOOL run_settings_non_elevated(LPCWSTR executable_path, LPWSTR executable_args, PROCESS_INFORMATION* process_info) -{ - HWND hwnd = GetShellWindow(); - if (!hwnd) - { - return false; - } - - DWORD pid; - GetWindowThreadProcessId(hwnd, &pid); - - winrt::handle process{ OpenProcess(PROCESS_CREATE_PROCESS, FALSE, pid) }; - if (!process) - { - return false; - } - - SIZE_T size = 0; - InitializeProcThreadAttributeList(nullptr, 1, 0, &size); - auto pproc_buffer = std::unique_ptr{ new (std::nothrow) char[size] }; - auto pptal = reinterpret_cast(pproc_buffer.get()); - if (!pptal) - { - return false; - } - - if (!InitializeProcThreadAttributeList(pptal, 1, 0, &size)) - { - return false; - } - - if (!UpdateProcThreadAttribute(pptal, - 0, - PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, - &process, - sizeof(process), - nullptr, - nullptr)) - { - return false; - } - - STARTUPINFOEX siex = { 0 }; - siex.lpAttributeList = pptal; - siex.StartupInfo.cb = sizeof(siex); - - BOOL process_created = CreateProcessW(executable_path, - executable_args, - nullptr, - nullptr, - FALSE, - EXTENDED_STARTUPINFO_PRESENT, - nullptr, - nullptr, - &siex.StartupInfo, - process_info); - g_isLaunchInProgress = false; - return process_created; -} - -DWORD g_settings_process_id = 0; - -void run_settings_window(bool show_oobe_window, bool show_scoobe_window, std::optional settings_window) -{ - g_isLaunchInProgress = true; - - PROCESS_INFORMATION process_info = { 0 }; - HANDLE hToken = nullptr; - - // Arguments for calling the settings executable: - // "C:\powertoys_path\PowerToysSettings.exe" powertoys_pipe settings_pipe powertoys_pid settings_theme - // powertoys_pipe: PowerToys pipe server. - // settings_pipe : Settings pipe server. - // powertoys_pid : PowerToys process pid. - // settings_theme: pass "dark" to start the settings window in dark mode - - // Arg 1: executable path. - std::wstring executable_path = get_module_folderpath(); - - executable_path.append(L"\\WinUI3Apps\\PowerToys.Settings.exe"); - - // Args 2,3: pipe server. Generate unique names for the pipes, if getting a UUID is possible. - std::wstring powertoys_pipe_name(L"\\\\.\\pipe\\powertoys_runner_"); - std::wstring settings_pipe_name(L"\\\\.\\pipe\\powertoys_settings_"); - UUID temp_uuid; - wchar_t* uuid_chars = nullptr; - if (UuidCreate(&temp_uuid) == RPC_S_UUID_NO_ADDRESS) - { - auto val = get_last_error_message(GetLastError()); - Logger::warn(L"UuidCreate cannot create guid. {}", val.has_value() ? val.value() : L""); - } - else if (UuidToString(&temp_uuid, reinterpret_cast(&uuid_chars)) != RPC_S_OK) - { - auto val = get_last_error_message(GetLastError()); - Logger::warn(L"UuidToString cannot convert to string. {}", val.has_value() ? val.value() : L""); - } - - if (uuid_chars != nullptr) - { - powertoys_pipe_name += std::wstring(uuid_chars); - settings_pipe_name += std::wstring(uuid_chars); - RpcStringFree(reinterpret_cast(&uuid_chars)); - uuid_chars = nullptr; - } - - // Arg 4: process pid. - DWORD powertoys_pid = GetCurrentProcessId(); - - GeneralSettings save_settings = get_general_settings(); - - // Arg 5: settings theme. - const std::wstring settings_theme_setting{ save_settings.theme }; - std::wstring settings_theme = L"system"; - if (settings_theme_setting == L"dark" || (settings_theme_setting == L"system" && WindowsColors::is_dark_mode())) - { - settings_theme = L"dark"; - } - - // Arg 6: elevated status - bool isElevated{ save_settings.isElevated }; - std::wstring settings_elevatedStatus = isElevated ? L"true" : L"false"; - - // Arg 7: is user an admin - bool isAdmin{ save_settings.isAdmin }; - std::wstring settings_isUserAnAdmin = isAdmin ? L"true" : L"false"; - - // Arg 8: should oobe window be shown - std::wstring settings_showOobe = show_oobe_window ? L"true" : L"false"; - - // Arg 9: should scoobe window be shown - std::wstring settings_showScoobe = show_scoobe_window ? L"true" : L"false"; - - // Arg 10: contains if there's a settings window argument. If true, will add one extra argument with the value to the call. - std::wstring settings_containsSettingsWindow = settings_window.has_value() ? L"true" : L"false"; - - // Args 11, .... : Optional arguments depending on the options presented before. All by the same value. - - // create general settings file to initialize the settings file with installation configurations like : - // 1. Run on start up. - PTSettingsHelper::save_general_settings(save_settings.to_json()); - - std::wstring executable_args = fmt::format(L"\"{}\" {} {} {} {} {} {} {} {} {}", - executable_path, - powertoys_pipe_name, - settings_pipe_name, - std::to_wstring(powertoys_pid), - settings_theme, - settings_elevatedStatus, - settings_isUserAnAdmin, - settings_showOobe, - settings_showScoobe, - settings_containsSettingsWindow); - - if (settings_window.has_value()) - { - executable_args.append(L" "); - executable_args.append(settings_window.value()); - } - - BOOL process_created = false; - - // Commented out to fix #22659 - // Running settings non-elevated and modules elevated when PowerToys is running elevated results - // in settings making changes in one file (non-elevated user dir) and modules are reading settings - // from different (elevated user) dir - //if (is_process_elevated()) - //{ - - // auto res = RunNonElevatedFailsafe(executable_path, executable_args, get_module_folderpath()); - // process_created = res.has_value(); - // if (process_created) - // { - // process_info.dwProcessId = res->processID; - // process_info.hProcess = res->processHandle.release(); - // g_isLaunchInProgress = false; - // } - //} - - if (FALSE == process_created) - { - // The runner is not elevated or we failed to create the process using the - // attribute list from Windows Explorer (this happens when PowerToys is executed - // as Administrator from a non-Administrator user or an error occur trying). - // In the second case the Settings process will run elevated. - STARTUPINFO startup_info = { sizeof(startup_info) }; - if (!CreateProcessW(executable_path.c_str(), - executable_args.data(), - nullptr, - nullptr, - FALSE, - 0, - nullptr, - nullptr, - &startup_info, - &process_info)) - { - goto LExit; - } - else - { - g_isLaunchInProgress = false; - } - } - - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) - { - goto LExit; - } - - { - std::unique_lock lock{ ipc_mutex }; - current_settings_ipc = new TwoWayPipeMessageIPC(powertoys_pipe_name, settings_pipe_name, receive_json_send_to_main_thread); - current_settings_ipc->start(hToken); - - // Register callback for bug report status changes - BugReportManager::instance().register_callback([](bool isRunning) { - json::JsonObject result; - result.SetNamedValue(L"bug_report_running", winrt::Windows::Data::Json::JsonValue::CreateBooleanValue(isRunning)); - - std::unique_lock lock{ ipc_mutex }; - if (current_settings_ipc) - current_settings_ipc->send(result.Stringify().c_str()); - }); - } - - g_settings_process_id = process_info.dwProcessId; - - if (process_info.hProcess) - { - WaitForSingleObject(process_info.hProcess, INFINITE); - if (WaitForSingleObject(process_info.hProcess, INFINITE) != WAIT_OBJECT_0) - { - show_last_error_message(L"Couldn't wait on the Settings Window to close.", GetLastError(), L"PowerToys - runner"); - } - } - else - { - auto val = get_last_error_message(GetLastError()); - Logger::error(L"Process handle is empty. {}", val.has_value() ? val.value() : L""); - } - -LExit: - - if (process_info.hProcess) - { - CloseHandle(process_info.hProcess); - } - - if (process_info.hThread) - { - CloseHandle(process_info.hThread); - } - { - std::unique_lock lock{ ipc_mutex }; - if (current_settings_ipc) - { - current_settings_ipc->end(); - delete current_settings_ipc; - current_settings_ipc = nullptr; - } - } - - if (hToken) - { - CloseHandle(hToken); - } - - g_settings_process_id = 0; -} - -#define MAX_TITLE_LENGTH 100 -void bring_settings_to_front() -{ - auto callback = [](HWND hwnd, LPARAM /*data*/) -> BOOL { - DWORD processId; - if (GetWindowThreadProcessId(hwnd, &processId) && processId == g_settings_process_id) - { - std::wstring windowTitle = L"PowerToys Settings"; - - WCHAR title[MAX_TITLE_LENGTH]; - int len = GetWindowTextW(hwnd, title, MAX_TITLE_LENGTH); - if (len <= 0) - { - return TRUE; - } - if (wcsncmp(title, windowTitle.c_str(), len) == 0) - { - auto lStyles = GetWindowLong(hwnd, GWL_STYLE); - - if (lStyles & WS_MAXIMIZE) - { - ShowWindow(hwnd, SW_MAXIMIZE); - } - else - { - ShowWindow(hwnd, SW_RESTORE); - } - - SetForegroundWindow(hwnd); - return FALSE; - } - } - - return TRUE; - }; - - EnumWindows(callback, 0); -} - -void open_settings_window(std::optional settings_window) -{ - if (g_settings_process_id != 0) - { - // nl instead of showing the window, send message to it (flyout might need to be hidden, main setting window activated) - // bring_settings_to_front(); - if (current_settings_ipc) - { - if (settings_window.has_value()) - { - std::wstring msg = L"{\"ShowYourself\":\"" + settings_window.value() + L"\"}"; - current_settings_ipc->send(msg); - } - else - { - current_settings_ipc->send(L"{\"ShowYourself\":\"Dashboard\"}"); - } - } - } - else - { - if (!g_isLaunchInProgress) - { - std::thread([settings_window]() { - run_settings_window(false, false, settings_window); - }).detach(); - } - } -} - -void close_settings_window() -{ - if (g_settings_process_id != 0) - { - SetEvent(g_terminateSettingsEvent); - wil::unique_handle proc{ OpenProcess(PROCESS_ALL_ACCESS, false, g_settings_process_id) }; - if (proc) - { - WaitForSingleObject(proc.get(), 1500); - TerminateProcess(proc.get(), 0); - } - } -} - -void open_oobe_window() -{ - std::thread([]() { - run_settings_window(true, false, std::nullopt); - }).detach(); -} - -void open_scoobe_window() -{ - std::thread([]() { - run_settings_window(false, true, std::nullopt); - }).detach(); -} - -std::string ESettingsWindowNames_to_string(ESettingsWindowNames value) -{ - switch (value) - { - case ESettingsWindowNames::Dashboard: - return "Dashboard"; - case ESettingsWindowNames::Overview: - return "Overview"; - case ESettingsWindowNames::AlwaysOnTop: - return "AlwaysOnTop"; - case ESettingsWindowNames::Awake: - return "Awake"; - case ESettingsWindowNames::ColorPicker: - return "ColorPicker"; - case ESettingsWindowNames::CmdNotFound: - return "CmdNotFound"; - case ESettingsWindowNames::LightSwitch: - return "LightSwitch"; - case ESettingsWindowNames::FancyZones: - return "FancyZones"; - case ESettingsWindowNames::FileLocksmith: - return "FileLocksmith"; - case ESettingsWindowNames::Run: - return "Run"; - case ESettingsWindowNames::ImageResizer: - return "ImageResizer"; - case ESettingsWindowNames::KBM: - return "KBM"; - case ESettingsWindowNames::MouseUtils: - return "MouseUtils"; - case ESettingsWindowNames::MouseWithoutBorders: - return "MouseWithoutBorders"; - case ESettingsWindowNames::Peek: - return "Peek"; - case ESettingsWindowNames::PowerAccent: - return "PowerAccent"; - case ESettingsWindowNames::PowerLauncher: - return "PowerLauncher"; - case ESettingsWindowNames::PowerPreview: - return "PowerPreview"; - case ESettingsWindowNames::PowerRename: - return "PowerRename"; - case ESettingsWindowNames::FileExplorer: - return "FileExplorer"; - case ESettingsWindowNames::ShortcutGuide: - return "ShortcutGuide"; - case ESettingsWindowNames::Hosts: - return "Hosts"; - case ESettingsWindowNames::MeasureTool: - return "MeasureTool"; - case ESettingsWindowNames::PowerOCR: - return "PowerOcr"; - case ESettingsWindowNames::Workspaces: - return "Workspaces"; - case ESettingsWindowNames::RegistryPreview: - return "RegistryPreview"; - case ESettingsWindowNames::CropAndLock: - return "CropAndLock"; - case ESettingsWindowNames::EnvironmentVariables: - return "EnvironmentVariables"; - case ESettingsWindowNames::AdvancedPaste: - return "AdvancedPaste"; - case ESettingsWindowNames::NewPlus: - return "NewPlus"; - case ESettingsWindowNames::CmdPal: - return "CmdPal"; - case ESettingsWindowNames::ZoomIt: - return "ZoomIt"; - case ESettingsWindowNames::PowerDisplay: - return "PowerDisplay"; - default: - { - Logger::error(L"Can't convert ESettingsWindowNames value={} to string", static_cast(value)); - assert(false); - } - } - return ""; -} - -ESettingsWindowNames ESettingsWindowNames_from_string(std::string value) -{ - if (value == "Dashboard") - { - return ESettingsWindowNames::Dashboard; - } - else if (value == "Overview") - { - return ESettingsWindowNames::Overview; - } - else if (value == "AlwaysOnTop") - { - return ESettingsWindowNames::AlwaysOnTop; - } - else if (value == "Awake") - { - return ESettingsWindowNames::Awake; - } - else if (value == "ColorPicker") - { - return ESettingsWindowNames::ColorPicker; - } - else if (value == "CmdNotFound") - { - return ESettingsWindowNames::CmdNotFound; - } - else if (value == "LightSwitch") - { - return ESettingsWindowNames::LightSwitch; - } - else if (value == "FancyZones") - { - return ESettingsWindowNames::FancyZones; - } - else if (value == "FileLocksmith") - { - return ESettingsWindowNames::FileLocksmith; - } - else if (value == "Run") - { - return ESettingsWindowNames::Run; - } - else if (value == "ImageResizer") - { - return ESettingsWindowNames::ImageResizer; - } - else if (value == "KBM") - { - return ESettingsWindowNames::KBM; - } - else if (value == "MouseUtils") - { - return ESettingsWindowNames::MouseUtils; - } - else if (value == "MouseWithoutBorders") - { - return ESettingsWindowNames::MouseWithoutBorders; - } - else if (value == "Peek") - { - return ESettingsWindowNames::Peek; - } - else if (value == "PowerAccent") - { - return ESettingsWindowNames::PowerAccent; - } - else if (value == "PowerLauncher") - { - return ESettingsWindowNames::PowerLauncher; - } - else if (value == "PowerPreview") - { - return ESettingsWindowNames::PowerPreview; - } - else if (value == "PowerRename") - { - return ESettingsWindowNames::PowerRename; - } - else if (value == "FileExplorer") - { - return ESettingsWindowNames::FileExplorer; - } - else if (value == "ShortcutGuide") - { - return ESettingsWindowNames::ShortcutGuide; - } - else if (value == "Hosts") - { - return ESettingsWindowNames::Hosts; - } - else if (value == "MeasureTool") - { - return ESettingsWindowNames::MeasureTool; - } - else if (value == "PowerOcr") - { - return ESettingsWindowNames::PowerOCR; - } - else if (value == "Workspaces") - { - return ESettingsWindowNames::Workspaces; - } - else if (value == "RegistryPreview") - { - return ESettingsWindowNames::RegistryPreview; - } - else if (value == "CropAndLock") - { - return ESettingsWindowNames::CropAndLock; - } - else if (value == "EnvironmentVariables") - { - return ESettingsWindowNames::EnvironmentVariables; - } - else if (value == "AdvancedPaste") - { - return ESettingsWindowNames::AdvancedPaste; - } - else if (value == "NewPlus") - { - return ESettingsWindowNames::NewPlus; - } - else if (value == "CmdPal") - { - return ESettingsWindowNames::CmdPal; - } - else if (value == "ZoomIt") - { - return ESettingsWindowNames::ZoomIt; - } - else if (value == "PowerDisplay") - { - return ESettingsWindowNames::PowerDisplay; - } - else - { - Logger::error(L"Can't convert string value={} to ESettingsWindowNames", winrt::to_hstring(value)); - assert(false); - } - - return ESettingsWindowNames::Dashboard; -} diff --git a/src/runner/settings_window.h b/src/runner/settings_window.h deleted file mode 100644 index 4da4d70a7a..0000000000 --- a/src/runner/settings_window.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once -#include -#include - -enum class ESettingsWindowNames -{ - Dashboard = 0, - Overview, - AlwaysOnTop, - Awake, - ColorPicker, - CmdNotFound, - LightSwitch, - FancyZones, - FileLocksmith, - Run, - ImageResizer, - KBM, - MouseUtils, - MouseWithoutBorders, - Peek, - PowerAccent, - PowerLauncher, - PowerPreview, - PowerRename, - FileExplorer, - ShortcutGuide, - Hosts, - MeasureTool, - PowerOCR, - Workspaces, - RegistryPreview, - CropAndLock, - EnvironmentVariables, - AdvancedPaste, - NewPlus, - CmdPal, - ZoomIt, - PowerDisplay, -}; - -std::string ESettingsWindowNames_to_string(ESettingsWindowNames value); -ESettingsWindowNames ESettingsWindowNames_from_string(std::string value); - -void open_settings_window(std::optional settings_window); -void close_settings_window(); - -void open_oobe_window(); -void open_scoobe_window(); diff --git a/src/runner/svgs/PowerToysDark.ico b/src/runner/svgs/PowerToysDark.ico deleted file mode 100644 index 313a3d01ec..0000000000 Binary files a/src/runner/svgs/PowerToysDark.ico and /dev/null differ diff --git a/src/runner/svgs/PowerToysWhite.ico b/src/runner/svgs/PowerToysWhite.ico deleted file mode 100644 index 9e55ac8794..0000000000 Binary files a/src/runner/svgs/PowerToysWhite.ico and /dev/null differ diff --git a/src/runner/svgs/icon.ico b/src/runner/svgs/icon.ico deleted file mode 100644 index 6cbba351a1..0000000000 Binary files a/src/runner/svgs/icon.ico and /dev/null differ diff --git a/src/runner/trace.cpp b/src/runner/trace.cpp deleted file mode 100644 index 6fb2f89ba8..0000000000 --- a/src/runner/trace.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "pch.h" -#include "trace.h" - -#include "general_settings.h" - -#include - -TRACELOGGING_DEFINE_PROVIDER( - g_hProvider, - "Microsoft.PowerToys", - // {38e8889b-9731-53f5-e901-e8a7c1753074} - (0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74), - TraceLoggingOptionProjectTelemetry()); - -void Trace::EventLaunch(const std::wstring& versionNumber, bool isProcessElevated) -{ - TraceLoggingWriteWrapper( - g_hProvider, - "Runner_Launch", - TraceLoggingWideString(versionNumber.c_str(), "Version"), - TraceLoggingBoolean(isProcessElevated, "Elevated"), - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); -} - -void Trace::SettingsChanged(const GeneralSettings& settings) -{ - std::wstring enabledModules; - for (const auto& [name, isEnabled] : settings.isModulesEnabledMap) - { - if (isEnabled) - { - if (!enabledModules.empty()) - { - enabledModules += L", "; - } - - enabledModules += name; - } - } - - TraceLoggingWriteWrapper( - g_hProvider, - "GeneralSettingsChanged", - TraceLoggingBoolean(settings.isStartupEnabled, "RunAtStartup"), - TraceLoggingBoolean(settings.enableWarningsElevatedApps, "EnableWarningsElevatedApps"), - TraceLoggingWideString(settings.startupDisabledReason.c_str(), "StartupDisabledReason"), - TraceLoggingWideString(enabledModules.c_str(), "ModulesEnabled"), - TraceLoggingBoolean(settings.isRunElevated, "AlwaysRunElevated"), - TraceLoggingBoolean(settings.downloadUpdatesAutomatically, "DownloadUpdatesAutomatically"), - TraceLoggingBoolean(settings.enableExperimentation, "EnableExperimentation"), - TraceLoggingWideString(settings.theme.c_str(), "Theme"), - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); -} - -void Trace::UpdateCheckCompleted(bool success, bool updateAvailable, const std::wstring& fromVersion, const std::wstring& toVersion) -{ - TraceLoggingWriteWrapper( - g_hProvider, - "UpdateCheck_Completed", - TraceLoggingBoolean(success, "Success"), - TraceLoggingBoolean(updateAvailable, "UpdateAvailable"), - TraceLoggingWideString(fromVersion.c_str(), "FromVersion"), - TraceLoggingWideString(toVersion.c_str(), "ToVersion"), - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); -} - -void Trace::UpdateDownloadCompleted(bool success, const std::wstring& version) -{ - TraceLoggingWriteWrapper( - g_hProvider, - "UpdateDownload_Completed", - TraceLoggingBoolean(success, "Success"), - TraceLoggingWideString(version.c_str(), "Version"), - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); -} - -void Trace::TrayIconLeftClick(bool quickAccessEnabled) -{ - TraceLoggingWriteWrapper( - g_hProvider, - "TrayIcon_LeftClick", - TraceLoggingBoolean(quickAccessEnabled, "QuickAccessEnabled"), - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); -} - -void Trace::TrayIconDoubleClick(bool quickAccessEnabled) -{ - TraceLoggingWriteWrapper( - g_hProvider, - "TrayIcon_DoubleClick", - TraceLoggingBoolean(quickAccessEnabled, "QuickAccessEnabled"), - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); -} - -void Trace::TrayIconRightClick(bool quickAccessEnabled) -{ - TraceLoggingWriteWrapper( - g_hProvider, - "TrayIcon_RightClick", - TraceLoggingBoolean(quickAccessEnabled, "QuickAccessEnabled"), - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); -} diff --git a/src/runner/trace.h b/src/runner/trace.h deleted file mode 100644 index fb22ce3301..0000000000 --- a/src/runner/trace.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include - -struct GeneralSettings; - -class Trace : public telemetry::TraceBase -{ -public: - static void EventLaunch(const std::wstring& versionNumber, bool isProcessElevated); - static void SettingsChanged(const GeneralSettings& settings); - - // Auto-update telemetry - static void UpdateCheckCompleted(bool success, bool updateAvailable, const std::wstring& fromVersion, const std::wstring& toVersion); - static void UpdateDownloadCompleted(bool success, const std::wstring& version); - - // Tray icon interaction telemetry - static void TrayIconLeftClick(bool quickAccessEnabled); - static void TrayIconDoubleClick(bool quickAccessEnabled); - static void TrayIconRightClick(bool quickAccessEnabled); -}; diff --git a/src/runner/tray_icon.cpp b/src/runner/tray_icon.cpp deleted file mode 100644 index 307129d63b..0000000000 --- a/src/runner/tray_icon.cpp +++ /dev/null @@ -1,513 +0,0 @@ -#include "pch.h" -#include "Generated files/resource.h" -#include "settings_window.h" -#include "tray_icon.h" -#include "general_settings.h" -#include "centralized_hotkeys.h" -#include "centralized_kb_hook.h" -#include "quick_access_host.h" -#include "hotkey_conflict_detector.h" -#include "trace.h" -#include - -#include -#include -#include -#include -#include -#include -#include "bug_report.h" - -namespace -{ - HWND tray_icon_hwnd = NULL; - - enum - { - wm_icon_notify = WM_APP, - wm_run_on_main_ui_thread, - }; - - // Contains the Windows Message for taskbar creation. - UINT wm_taskbar_restart = 0; - - NOTIFYICONDATAW tray_icon_data; - bool tray_icon_created = false; - - bool about_box_shown = false; - - HMENU h_menu = nullptr; - HMENU h_sub_menu = nullptr; - bool double_click_timer_running = false; - bool double_clicked = false; - POINT tray_icon_click_point; - std::optional last_quick_access_state; // Track the last known Quick Access state - - static ThemeListener theme_listener; - static bool theme_adaptive_enabled = false; -} - -// Struct to fill with callback and the data. The window_proc is responsible for cleaning it. -struct run_on_main_ui_thread_msg -{ - main_loop_callback_function _callback; - PVOID data; -}; - -bool dispatch_run_on_main_ui_thread(main_loop_callback_function _callback, PVOID data) -{ - if (tray_icon_hwnd == NULL) - { - return false; - } - struct run_on_main_ui_thread_msg* wnd_msg = new struct run_on_main_ui_thread_msg(); - wnd_msg->_callback = _callback; - wnd_msg->data = data; - - PostMessage(tray_icon_hwnd, wm_run_on_main_ui_thread, 0, reinterpret_cast(wnd_msg)); - - return true; -} - -void change_menu_item_text(const UINT item_id, wchar_t* new_text) -{ - MENUITEMINFOW menuitem = { .cbSize = sizeof(MENUITEMINFOW), .fMask = MIIM_TYPE | MIIM_DATA }; - GetMenuItemInfoW(h_menu, item_id, false, &menuitem); - menuitem.dwTypeData = new_text; - SetMenuItemInfoW(h_menu, item_id, false, &menuitem); -} - -void open_quick_access_flyout_window() -{ - QuickAccessHost::show(); -} - -void handle_tray_command(HWND window, const WPARAM command_id, LPARAM lparam) -{ - switch (command_id) - { - case ID_SETTINGS_MENU_COMMAND: - { - std::wstring settings_window{ winrt::to_hstring(ESettingsWindowNames_to_string(static_cast(lparam))) }; - open_settings_window(settings_window); - } - break; - case ID_CLOSE_MENU_COMMAND: - if (h_menu) - { - DestroyMenu(h_menu); - } - DestroyWindow(window); - break; - case ID_ABOUT_MENU_COMMAND: - if (!about_box_shown) - { - about_box_shown = true; - std::wstring about_msg = L"PowerToys\nVersion " + get_product_version() + L"\n\xa9 2019 Microsoft Corporation"; - MessageBoxW(nullptr, about_msg.c_str(), L"About PowerToys", MB_OK); - about_box_shown = false; - } - break; - case ID_REPORT_BUG_COMMAND: - { - launch_bug_report(); - break; - } - - case ID_DOCUMENTATION_MENU_COMMAND: - { - RunNonElevatedEx(L"https://aka.ms/PowerToysOverview", L"", L""); - break; - } - case ID_QUICK_ACCESS_MENU_COMMAND: - { - open_quick_access_flyout_window(); - break; - } - } -} - -void click_timer_elapsed() -{ - double_click_timer_running = false; - if (!double_clicked) - { - // Log telemetry for single click (confirmed it's not a double click) - Trace::TrayIconLeftClick(get_general_settings().enableQuickAccess); - - if (get_general_settings().enableQuickAccess) - { - open_quick_access_flyout_window(); - } - else - { - open_settings_window(std::nullopt); - } - } -} - -LRESULT __stdcall tray_icon_window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) -{ - switch (message) - { - case WM_HOTKEY: - { - // We use the tray icon WndProc to avoid creating a dedicated window just for this message. - const auto modifiersMask = LOWORD(lparam); - const auto vkCode = HIWORD(lparam); - Logger::trace(L"On {} hotkey", CentralizedHotkeys::ToWstring({ modifiersMask, vkCode })); - CentralizedHotkeys::PopulateHotkey({ modifiersMask, vkCode }); - break; - } - case WM_CREATE: - if (wm_taskbar_restart == 0) - { - tray_icon_hwnd = window; - wm_taskbar_restart = RegisterWindowMessageW(L"TaskbarCreated"); - } - break; - case WM_DESTROY: - if (tray_icon_created) - { - Shell_NotifyIcon(NIM_DELETE, &tray_icon_data); - tray_icon_created = false; - } - close_settings_window(); - PostQuitMessage(0); - break; - case WM_CLOSE: - DestroyWindow(window); - break; - case WM_COMMAND: - handle_tray_command(window, wparam, lparam); - break; - // Shell_NotifyIcon can fail when we invoke it during the time explorer.exe isn't present/ready to handle it. - // We'll also never receive wm_taskbar_restart message if the first call to Shell_NotifyIcon failed, so we use - // WM_WINDOWPOSCHANGING which is always received on explorer startup sequence. - case WM_WINDOWPOSCHANGING: - { - if (!tray_icon_created) - { - tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE; - } - break; - } - default: - if (message == wm_icon_notify) - { - switch (lparam) - { - case WM_RBUTTONUP: - case WM_CONTEXTMENU: - { - bool quick_access_enabled = get_general_settings().enableQuickAccess; - - // Log telemetry - Trace::TrayIconRightClick(quick_access_enabled); - - // Reload menu if Quick Access state has changed or is first time - if (h_menu && (!last_quick_access_state.has_value() || quick_access_enabled != last_quick_access_state.value())) - { - DestroyMenu(h_menu); - h_menu = nullptr; - h_sub_menu = nullptr; - } - - last_quick_access_state = quick_access_enabled; - - if (!h_menu) - { - h_menu = LoadMenu(reinterpret_cast(&__ImageBase), MAKEINTRESOURCE(ID_TRAY_MENU)); - } - if (h_menu) - { - static std::wstring settings_menuitem_label = GET_RESOURCE_STRING(IDS_SETTINGS_MENU_TEXT); - static std::wstring settings_menuitem_label_leftclick = GET_RESOURCE_STRING(IDS_SETTINGS_MENU_TEXT_LEFTCLICK); - static std::wstring close_menuitem_label = GET_RESOURCE_STRING(IDS_CLOSE_MENU_TEXT); - static std::wstring submit_bug_menuitem_label = GET_RESOURCE_STRING(IDS_SUBMIT_BUG_TEXT); - static std::wstring documentation_menuitem_label = GET_RESOURCE_STRING(IDS_DOCUMENTATION_MENU_TEXT); - static std::wstring quick_access_menuitem_label = GET_RESOURCE_STRING(IDS_QUICK_ACCESS_MENU_TEXT); - - // Update Settings menu text based on Quick Access state - if (quick_access_enabled) - { - change_menu_item_text(ID_SETTINGS_MENU_COMMAND, settings_menuitem_label.data()); - } - else - { - change_menu_item_text(ID_SETTINGS_MENU_COMMAND, settings_menuitem_label_leftclick.data()); - } - - change_menu_item_text(ID_CLOSE_MENU_COMMAND, close_menuitem_label.data()); - change_menu_item_text(ID_REPORT_BUG_COMMAND, submit_bug_menuitem_label.data()); - bool bug_report_disabled = is_bug_report_running(); - EnableMenuItem(h_sub_menu, ID_REPORT_BUG_COMMAND, MF_BYCOMMAND | (bug_report_disabled ? MF_GRAYED : MF_ENABLED)); - change_menu_item_text(ID_DOCUMENTATION_MENU_COMMAND, documentation_menuitem_label.data()); - change_menu_item_text(ID_QUICK_ACCESS_MENU_COMMAND, quick_access_menuitem_label.data()); - - // Hide or show Quick Access menu item based on setting - if (!h_sub_menu) - { - h_sub_menu = GetSubMenu(h_menu, 0); - } - if (!quick_access_enabled) - { - // Remove Quick Access menu item when disabled - DeleteMenu(h_sub_menu, ID_QUICK_ACCESS_MENU_COMMAND, MF_BYCOMMAND); - } - } - if (!h_sub_menu) - { - h_sub_menu = GetSubMenu(h_menu, 0); - } - POINT mouse_pointer; - GetCursorPos(&mouse_pointer); - SetForegroundWindow(window); // Needed for the context menu to disappear. - TrackPopupMenu(h_sub_menu, TPM_CENTERALIGN | TPM_BOTTOMALIGN, mouse_pointer.x, mouse_pointer.y, 0, window, nullptr); - break; - } - case WM_LBUTTONUP: - { - // ignore event if this is the second click of a double click - if (!double_click_timer_running) - { - // start timer for detecting single or double click - double_click_timer_running = true; - double_clicked = false; - - UINT doubleClickTime = GetDoubleClickTime(); - std::thread([doubleClickTime]() { - std::this_thread::sleep_for(std::chrono::milliseconds(doubleClickTime)); - click_timer_elapsed(); - }).detach(); - } - break; - } - case WM_LBUTTONDBLCLK: - { - // Log telemetry - Trace::TrayIconDoubleClick(get_general_settings().enableQuickAccess); - - double_clicked = true; - open_settings_window(std::nullopt); - break; - } - break; - } - } - else if (message == wm_run_on_main_ui_thread) - { - if (lparam != NULL) - { - struct run_on_main_ui_thread_msg* msg = reinterpret_cast(lparam); - msg->_callback(msg->data); - delete msg; - lparam = NULL; - } - break; - } - else if (message == wm_taskbar_restart) - { - tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE; - break; - } - } - return DefWindowProc(window, message, wparam, lparam); -} - -static HICON get_icon(Theme theme) -{ - std::wstring icon_path = get_module_folderpath(); - icon_path += theme == Theme::Dark ? L"\\svgs\\PowerToysWhite.ico" : L"\\svgs\\PowerToysDark.ico"; - Logger::trace(L"get_icon: Loading icon from path: {}", icon_path); - - HICON icon = static_cast(LoadImage(NULL, - icon_path.c_str(), - IMAGE_ICON, - 0, - 0, - LR_LOADFROMFILE | LR_DEFAULTSIZE | LR_SHARED)); - if (!icon) - { - Logger::warn(L"get_icon: Failed to load icon from {}, error: {}", icon_path, GetLastError()); - } - return icon; -} - - -static void handle_theme_change() -{ - if (theme_adaptive_enabled) - { - tray_icon_data.hIcon = get_icon(ThemeHelpers::GetSystemTheme()); - Shell_NotifyIcon(NIM_MODIFY, &tray_icon_data); - } -} - -void update_bug_report_menu_status(bool isRunning) -{ - if (h_sub_menu != nullptr) - { - EnableMenuItem(h_sub_menu, ID_REPORT_BUG_COMMAND, MF_BYCOMMAND | (isRunning ? MF_GRAYED : MF_ENABLED)); - } -} - -void start_tray_icon(bool isProcessElevated, bool theme_adaptive) -{ - theme_adaptive_enabled = theme_adaptive; - auto h_instance = reinterpret_cast(&__ImageBase); - HICON const icon = theme_adaptive ? get_icon(ThemeHelpers::GetSystemTheme()) : LoadIcon(h_instance, MAKEINTRESOURCE(APPICON)); - if (icon) - { - UINT id_tray_icon = 1; - - WNDCLASS wc = {}; - wc.hCursor = LoadCursor(nullptr, IDC_ARROW); - wc.hInstance = h_instance; - wc.lpszClassName = pt_tray_icon_window_class; - wc.style = CS_HREDRAW | CS_VREDRAW; - wc.lpfnWndProc = tray_icon_window_proc; - wc.hIcon = icon; - RegisterClass(&wc); - auto hwnd = CreateWindowW(wc.lpszClassName, - pt_tray_icon_window_class, - WS_OVERLAPPEDWINDOW | WS_POPUP, - CW_USEDEFAULT, - CW_USEDEFAULT, - CW_USEDEFAULT, - CW_USEDEFAULT, - nullptr, - nullptr, - wc.hInstance, - nullptr); - WINRT_VERIFY(hwnd); - CentralizedHotkeys::RegisterWindow(hwnd); - CentralizedKeyboardHook::RegisterWindow(hwnd); - memset(&tray_icon_data, 0, sizeof(tray_icon_data)); - tray_icon_data.cbSize = sizeof(tray_icon_data); - tray_icon_data.hIcon = icon; - tray_icon_data.hWnd = hwnd; - tray_icon_data.uID = id_tray_icon; - tray_icon_data.uCallbackMessage = wm_icon_notify; - - std::wstringstream pt_version_tooltip_stream; - if (isProcessElevated) - { - pt_version_tooltip_stream << GET_RESOURCE_STRING(IDS_TRAY_ICON_ADMIN_TOOLTIP) << L": "; - } - - pt_version_tooltip_stream << L"PowerToys " << get_product_version() << '\0'; - std::wstring pt_version_tooltip = pt_version_tooltip_stream.str(); - wcscpy_s(tray_icon_data.szTip, sizeof(tray_icon_data.szTip) / sizeof(WCHAR), pt_version_tooltip.c_str()); - tray_icon_data.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE; - ChangeWindowMessageFilterEx(hwnd, WM_COMMAND, MSGFLT_ALLOW, nullptr); - - tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE; - theme_listener.AddSystemThemeChangedHandler(&handle_theme_change); - - // Register callback to update bug report menu item status - BugReportManager::instance().register_callback([](bool isRunning) { - dispatch_run_on_main_ui_thread([](PVOID data) { - bool* running = static_cast(data); - update_bug_report_menu_status(*running); - delete running; - }, - new bool(isRunning)); - }); - } -} - -void set_tray_icon_visible(bool shouldIconBeVisible) -{ - tray_icon_data.uFlags |= NIF_STATE; - tray_icon_data.dwStateMask = NIS_HIDDEN; - tray_icon_data.dwState = shouldIconBeVisible ? 0 : NIS_HIDDEN; - Shell_NotifyIcon(NIM_MODIFY, &tray_icon_data); -} - -void set_tray_icon_theme_adaptive(bool theme_adaptive) -{ - Logger::info(L"set_tray_icon_theme_adaptive: Called with theme_adaptive={}, current theme_adaptive_enabled={}", - theme_adaptive, theme_adaptive_enabled); - - auto h_instance = reinterpret_cast(&__ImageBase); - HICON icon = nullptr; - - if (theme_adaptive) - { - icon = get_icon(ThemeHelpers::GetSystemTheme()); - if (!icon) - { - Logger::warn(L"set_tray_icon_theme_adaptive: Failed to load theme adaptive icon, falling back to default"); - } - } - - // If not requesting adaptive icon, or if adaptive icon failed to load, use default icon - if (!icon) - { - icon = LoadIcon(h_instance, MAKEINTRESOURCE(APPICON)); - if (theme_adaptive && icon) - { - // We requested adaptive but had to fall back, so update the flag - theme_adaptive = false; - Logger::info(L"set_tray_icon_theme_adaptive: Using default icon as fallback"); - } - } - - theme_adaptive_enabled = theme_adaptive; - - if (icon) - { - tray_icon_data.hIcon = icon; - BOOL result = Shell_NotifyIcon(NIM_MODIFY, &tray_icon_data); - Logger::info(L"set_tray_icon_theme_adaptive: Icon updated, theme_adaptive_enabled={}, Shell_NotifyIcon result={}", - theme_adaptive_enabled, result); - } - else - { - Logger::error(L"set_tray_icon_theme_adaptive: Failed to load any icon"); - } -} - -void stop_tray_icon() -{ - if (tray_icon_created) - { - // Clear bug report callbacks - BugReportManager::instance().clear_callbacks(); - SendMessage(tray_icon_hwnd, WM_CLOSE, 0, 0); - } -} -void update_quick_access_hotkey(bool enabled, PowerToysSettings::HotkeyObject hotkey) -{ - static PowerToysSettings::HotkeyObject current_hotkey; - static bool is_registered = false; - auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); - - if (is_registered) - { - CentralizedKeyboardHook::ClearModuleHotkeys(L"QuickAccess"); - hkmng.RemoveHotkeyByModule(L"GeneralSettings"); - is_registered = false; - } - - if (enabled && hotkey.get_code() != 0) - { - HotkeyConflictDetector::Hotkey hk = { - hotkey.win_pressed(), - hotkey.ctrl_pressed(), - hotkey.shift_pressed(), - hotkey.alt_pressed(), - static_cast(hotkey.get_code()) - }; - - hkmng.AddHotkey(hk, L"GeneralSettings", 0, true); - CentralizedKeyboardHook::SetHotkeyAction(L"QuickAccess", hk, []() { - open_quick_access_flyout_window(); - return true; - }); - - current_hotkey = hotkey; - is_registered = true; - } -} diff --git a/src/runner/tray_icon.h b/src/runner/tray_icon.h deleted file mode 100644 index 5ef4c3a75b..0000000000 --- a/src/runner/tray_icon.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include -#include -#include - -// Start the Tray Icon -void start_tray_icon(bool isProcessElevated, bool theme_adaptive); -// Change the Tray Icon visibility -void set_tray_icon_visible(bool shouldIconBeVisible); -// Enable or disable theme adaptive tray icon at runtime -void set_tray_icon_theme_adaptive(bool theme_adaptive); -// Stop the Tray Icon -void stop_tray_icon(); -// Open the Settings Window -void open_settings_window(std::optional settings_window); -// Update Quick Access Hotkey -void update_quick_access_hotkey(bool enabled, PowerToysSettings::HotkeyObject hotkey); -// Callback type to be called by the tray icon loop -typedef void (*main_loop_callback_function)(PVOID); -// Calls a callback in _callback -bool dispatch_run_on_main_ui_thread(main_loop_callback_function _callback, PVOID data); - -// Must be the same as: settings-ui/Settings.UI/Views/ShellPage.xaml.cs -> ExitPTItem_Tapped() -> const string ptTrayIconWindowClass -const inline wchar_t* pt_tray_icon_window_class = L"PToyTrayIconWindow"; \ No newline at end of file diff --git a/src/runner/unhandled_exception_handler.cpp b/src/runner/unhandled_exception_handler.cpp deleted file mode 100644 index 1d01349dd3..0000000000 --- a/src/runner/unhandled_exception_handler.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include "pch.h" -#if _DEBUG && _WIN64 -#include "unhandled_exception_handler.h" -#include -#pragma comment(lib, "DbgHelp.lib") -#include -#include -#include - -static IMAGEHLP_SYMBOL64* p_symbol = static_cast(malloc(sizeof(IMAGEHLP_SYMBOL64) + MAX_PATH * sizeof(WCHAR))); -static IMAGEHLP_LINE64 line; -static bool processing_exception = false; -static WCHAR module_path[MAX_PATH]; -static LPTOP_LEVEL_EXCEPTION_FILTER default_top_level_exception_handler = NULL; - -static const WCHAR* exception_description(const DWORD& code) -{ - switch (code) - { - case EXCEPTION_ACCESS_VIOLATION: - return L"EXCEPTION_ACCESS_VIOLATION"; - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - return L"EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; - case EXCEPTION_BREAKPOINT: - return L"EXCEPTION_BREAKPOINT"; - case EXCEPTION_DATATYPE_MISALIGNMENT: - return L"EXCEPTION_DATATYPE_MISALIGNMENT"; - case EXCEPTION_FLT_DENORMAL_OPERAND: - return L"EXCEPTION_FLT_DENORMAL_OPERAND"; - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - return L"EXCEPTION_FLT_DIVIDE_BY_ZERO"; - case EXCEPTION_FLT_INEXACT_RESULT: - return L"EXCEPTION_FLT_INEXACT_RESULT"; - case EXCEPTION_FLT_INVALID_OPERATION: - return L"EXCEPTION_FLT_INVALID_OPERATION"; - case EXCEPTION_FLT_OVERFLOW: - return L"EXCEPTION_FLT_OVERFLOW"; - case EXCEPTION_FLT_STACK_CHECK: - return L"EXCEPTION_FLT_STACK_CHECK"; - case EXCEPTION_FLT_UNDERFLOW: - return L"EXCEPTION_FLT_UNDERFLOW"; - case EXCEPTION_ILLEGAL_INSTRUCTION: - return L"EXCEPTION_ILLEGAL_INSTRUCTION"; - case EXCEPTION_IN_PAGE_ERROR: - return L"EXCEPTION_IN_PAGE_ERROR"; - case EXCEPTION_INT_DIVIDE_BY_ZERO: - return L"EXCEPTION_INT_DIVIDE_BY_ZERO"; - case EXCEPTION_INT_OVERFLOW: - return L"EXCEPTION_INT_OVERFLOW"; - case EXCEPTION_INVALID_DISPOSITION: - return L"EXCEPTION_INVALID_DISPOSITION"; - case EXCEPTION_NONCONTINUABLE_EXCEPTION: - return L"EXCEPTION_NONCONTINUABLE_EXCEPTION"; - case EXCEPTION_PRIV_INSTRUCTION: - return L"EXCEPTION_PRIV_INSTRUCTION"; - case EXCEPTION_SINGLE_STEP: - return L"EXCEPTION_SINGLE_STEP"; - case EXCEPTION_STACK_OVERFLOW: - return L"EXCEPTION_STACK_OVERFLOW"; - default: - return L"UNKNOWN EXCEPTION"; - } -} - -void init_symbols() -{ - SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); - line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - auto process = GetCurrentProcess(); - SymInitialize(process, NULL, TRUE); -} - -void log_stack_trace(std::wstring& generalErrorDescription) -{ - memset(p_symbol, '\0', sizeof(*p_symbol) + MAX_PATH); - memset(&module_path[0], '\0', sizeof(module_path)); - line.LineNumber = 0; - - CONTEXT context; - RtlCaptureContext(&context); - auto process = GetCurrentProcess(); - auto thread = GetCurrentThread(); - STACKFRAME64 stack; - memset(&stack, 0, sizeof(STACKFRAME64)); - -#ifdef _M_ARM64 - stack.AddrPC.Offset = context.Pc; - stack.AddrStack.Offset = context.Sp; - stack.AddrFrame.Offset = context.Fp; -#else - stack.AddrPC.Offset = context.Rip; - stack.AddrStack.Offset = context.Rsp; - stack.AddrFrame.Offset = context.Rbp; -#endif - stack.AddrPC.Mode = AddrModeFlat; - stack.AddrStack.Mode = AddrModeFlat; - stack.AddrFrame.Mode = AddrModeFlat; - - std::wstringstream ss; - ss << generalErrorDescription << std::endl; - for (ULONG frame = 0;; frame++) - { - auto result = StackWalk64( -#ifdef _M_ARM64 - IMAGE_FILE_MACHINE_ARM64, -#else - IMAGE_FILE_MACHINE_AMD64, -#endif - process, - thread, - &stack, - &context, - NULL, - SymFunctionTableAccess64, - SymGetModuleBase64, - NULL); - - p_symbol->MaxNameLength = MAX_PATH; - p_symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); - - DWORD64 dw64Displacement; - SymGetSymFromAddr64(process, stack.AddrPC.Offset, &dw64Displacement, p_symbol); - DWORD dwDisplacement; - SymGetLineFromAddr64(process, stack.AddrPC.Offset, &dwDisplacement, &line); - - auto module_base = SymGetModuleBase64(process, stack.AddrPC.Offset); - if (module_base) - { - GetModuleFileName(reinterpret_cast(module_base), module_path, MAX_PATH); - } - ss << module_path << "!" - << p_symbol->Name - << "(" << line.FileName << ":" << line.LineNumber << ")\n"; - if (!result) - { - break; - } - } - auto errorString = ss.str(); - MessageBoxW(NULL, errorString.c_str(), L"Unhandled Error", MB_OK | MB_ICONERROR); -} - -LONG WINAPI unhandled_exception_handler(PEXCEPTION_POINTERS info) -{ - if (!processing_exception) - { - processing_exception = true; - try - { - init_symbols(); - std::wstring ex_description = L"Exception code not available"; - if (info != NULL && info->ExceptionRecord != NULL && info->ExceptionRecord->ExceptionCode != NULL) - { - ex_description = exception_description(info->ExceptionRecord->ExceptionCode); - } - log_stack_trace(ex_description); - } - catch (...) - { - } - if (default_top_level_exception_handler != NULL && info != NULL) - { - default_top_level_exception_handler(info); - } - processing_exception = false; - } - return EXCEPTION_CONTINUE_SEARCH; -} - -extern "C" void AbortHandler(int /*signal_number*/) -{ - init_symbols(); - std::wstring ex_description = L"SIGABRT was raised."; - log_stack_trace(ex_description); -} - -void init_global_error_handlers() -{ - default_top_level_exception_handler = SetUnhandledExceptionFilter(unhandled_exception_handler); - signal(SIGABRT, &AbortHandler); -} -#endif diff --git a/src/runner/unhandled_exception_handler.h b/src/runner/unhandled_exception_handler.h deleted file mode 100644 index 2aaf07b099..0000000000 --- a/src/runner/unhandled_exception_handler.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -#if _DEBUG && _WIN64 -void init_global_error_handlers(); -#endif