This page describes the top-level design of PowerToys: the processes involved, how they are structured, and how control and data flow between them at runtime. Details for each subsystem are in the child pages: the Runner (2.1), Module Loading (2.2), Settings Management (2.3), IPC (2.4), and Shared Services (2.5). For the Settings UI application's internal structure, see 4.1. For installation and distribution, see 5.
PowerToys runs as a set of cooperating processes with one long-running host.
| Role | Executable | Lifetime |
|---|---|---|
| Runner | PowerToys.exe | Always running while PowerToys is active |
| Settings UI | WinUI3Apps/PowerToys.Settings.exe | Launched on demand; one instance at a time |
| Module sub-processes | Various (editors, launchers) | Spawned and managed by individual modules |
Module DLLs are loaded directly into the Runner's address space. The Settings UI is a separate WinUI3 process that communicates with the Runner over a pair of named Win32 pipes.
Top-Level Process Architecture
Sources: src/runner/main.cpp181-356 src/runner/settings_window.cpp435-550 src/runner/tray_icon.cpp355-400
The entry point is WinMain in src/runner/main.cpp. Before the normal startup path it checks for three special execution modes triggered by command-line arguments:
| Mode | Trigger argument | Action |
|---|---|---|
Win32ToastNotificationCOMServer | TOAST_ACTIVATED_LAUNCH_ARG | Runs notifications::run_desktop_app_activator_loop() and exits |
ToastNotificationHandler | powertoys:// URI prefix | Handles URI actions (e.g., open settings, trigger update) and exits |
ReportSuccessfulUpdate | UPDATE_REPORT_SUCCESS | Shows update-success toast and falls through |
For normal startup, WinMain acquires an MSI mutex (POWERTOYS_MSI_MUTEX_NAME) to prevent multiple instances, determines elevation state, and calls into runner().
WinMain and runner() Startup Flow
Sources: src/runner/main.cpp439-640 src/runner/main.cpp181-356
After loading general settings, WinMain selects one of three execution paths:
| Condition | Outcome |
|---|---|
Already elevated, or elevation not required (run_elevated == false) | Call runner() directly |
Not elevated and run_elevated == true | schedule_restart_as_elevated(open_settings) then exit |
Elevated with --dont-elevate and elevation not required | schedule_restart_as_non_elevated() then exit |
The special case (!elevated && with_restartedElevated_arg) prevents an infinite restart loop if elevation fails.
Sources: src/runner/main.cpp562-614
After the tray icon is up, runner() iterates a hard-coded list of relative DLL paths, calling load_powertoy() for each and inserting the result into the modules() map. The map is keyed by the string returned from each module's get_key() method.
Selected entries from knownModules[]:
PowerToys.FancyZonesModuleInterface.dll
PowerToys.KeyboardManager.dll
PowerToys.Launcher.dll
PowerToys.ColorPicker.dll
WinUI3Apps/PowerToys.ImageResizerExt.dll
WinUI3Apps/PowerToys.PowerRenameExt.dll
PowerToys.CmdPalModuleInterface.dll
PowerToys.ZoomItModuleInterface.dll
start_enabled_powertoys() then calls enable() on each module whose name appears with value true in general_settings.enabled. Modules that fail to load in Release builds show an error dialog; in Debug builds only a warning is logged so a partial build still runs.
Module Load and Enable Flow
Runtime enable/disable (from Settings UI) goes through apply_module_status_update() in src/runner/general_settings.cpp, which performs the same GPO check before acting.
Sources: src/runner/main.cpp254-320 src/runner/general_settings.cpp196-289
For the PowertoyModuleIface contract and how DLLs implement it, see Module Loading System.
Global settings are loaded from a JSON file by load_general_settings() (implemented in src/runner/general_settings.cpp) and held in the GeneralSettings struct (src/runner/general_settings.h).
Key fields of GeneralSettings:
| Field | C++ Type | Purpose |
|---|---|---|
isStartupEnabled | bool | Windows startup task active |
showSystemTrayIcon | bool | Tray icon visibility |
showThemeAdaptiveTrayIcon | bool | Theme-adaptive icon mode |
isRunElevated | bool | Run-as-elevated preference |
enableQuickAccess | bool | Quick Access feature active |
quickAccessShortcut | HotkeyObject | Global hotkey for Quick Access |
isModulesEnabledMap | map<wstring, bool> | Per-module enable state |
theme | wstring | "light", "dark", or "system" |
ignoredConflictProperties | JsonObject | Hotkeys excluded from conflict detection |
dashboardSortOrder | DashboardSortOrder | Dashboard ordering enum |
The three main settings functions and their responsibilities:
| Function | Role |
|---|---|
load_general_settings() | Reads JSON from disk, populates module-level statics, returns raw JsonObject |
get_general_settings() | Constructs a GeneralSettings from current in-memory state (including live module enabled states) |
apply_general_settings() | Applies a JsonObject (from IPC or startup) to in-memory state; optionally saves to disk |
Sources: src/runner/general_settings.h1-42 src/runner/general_settings.cpp123-194 src/runner/general_settings.cpp292-450
For persistence detail see Settings Management and Configuration Persistence.
run_settings_window() launches PowerToys.Settings.exe with command-line arguments that include two unique pipe names and the Runner's PID. Both processes open their ends of the pipes and construct a TwoWayPipeMessageIPC object.
Pipe names are generated per-session using a UUID:
\\.\pipe\powertoys_runner_<uuid>\\.\pipe\powertoys_settings_<uuid>All messages are JSON text. The Settings UI sends requests; the Runner responds or pushes updates.
IPC Message Dispatch in dispatch_received_json()
The "action" key supports sub-actions dispatched by dispatch_json_action_to_module(): restart_elevation, restart_maintain_elevation, check_for_updates, request_update_state_date, and arbitrary per-module custom actions via call_custom_action().
The receive_json_send_to_main_thread() โ dispatch_run_on_main_ui_thread() path ensures all state mutations happen on the main thread that owns the modules() map, avoiding locking.
Sources: src/runner/settings_window.cpp194-357 src/runner/settings_window.cpp359-370 src/runner/settings_window.cpp435-560
For the full IPC protocol and hotkey conflict resolution, see Inter-Process Communication.
start_tray_icon() registers a window class and creates a hidden Win32 window of class PToyTrayIconWindow. This window's procedure, tray_icon_window_proc, is the main thread's central event dispatcher.
tray_icon_window_proc Message Routing
The wm_run_on_main_ui_thread message is posted by dispatch_run_on_main_ui_thread() from any background thread (IPC receive thread, update worker, etc.) to safely marshal a function call onto the main thread. This is the thread-safety boundary for all in-process state access.
The tray icon adapts to the system theme (light/dark) when showThemeAdaptiveTrayIcon is enabled, using ThemeListener from the common Themes library.
Sources: src/runner/tray_icon.cpp57-70 src/runner/tray_icon.cpp149-316 src/runner/tray_icon.cpp355-415 src/runner/tray_icon.h1-23
The Runner links these shared libraries from src/common/:
| Library project | Key classes / functions | Role |
|---|---|---|
common/logger/logger.vcxproj | Logger::info/warn/error | Structured file logging |
common/notifications/notifications.vcxproj | notifications::show_toast | Windows toast notifications |
common/Telemetry/EtwTrace/EtwTrace.vcxproj | Shared::Trace::ETWTrace | ETW telemetry session |
common/Themes/Themes.vcxproj | ThemeListener, ThemeHelpers | System theme detection |
common/updating/updating.vcxproj | updating::cleanup_updates, PeriodicUpdateWorker | GitHub-based update management |
common/COMUtils/COMUtils.vcxproj | initializeCOMSecurity | COM security initialization |
common/Display/Display.vcxproj | DPIAware::EnableDPIAwarenessForThisProcess | Per-monitor DPI awareness |
common/interop/two_way_pipe_message_ipc.cpp | TwoWayPipeMessageIPC | Bidirectional named-pipe transport |
Shared::Trace::ETWTrace is initialized at the very top of WinMain and Flush()/UpdateState(false) called at exit, wrapping all telemetry for the Runner session.
Sources: src/runner/runner.vcxproj115-138 src/runner/main.cpp1-56 src/runner/main.cpp441-447 src/runner/main.cpp621-624
For more on these libraries, see Shared Services.
Settings change: Settings UI โ Runner โ Module โ disk
Sources: src/runner/settings_window.cpp151-192 src/runner/settings_window.cpp228-235 src/runner/main.cpp601-607
Refresh this wiki
This wiki was recently refreshed. Please wait 4 days to refresh again.