## Summary of the Pull Request Accumulated information from internal transition about the modules development, and reworked it to be added in dev docs. Also the dev docs intself was restructured to be more organized. New pages was verified by transition team. ## PR Checklist - [x] **Dev docs:** Added/updated --------- Co-authored-by: Zhaopeng Wang (from Dev Box) <zhaopengwang@microsoft.com> Co-authored-by: Hao Liu <liuhao3418@gmail.com> Co-authored-by: Peiyao Zhao <105847726+zhaopy536@users.noreply.github.com> Co-authored-by: Mengyuan <162882040+chenmy77@users.noreply.github.com> Co-authored-by: zhaopeng wang <33367956+wang563681252@users.noreply.github.com> Co-authored-by: Jaylyn Barbee <51131738+Jaylyn-Barbee@users.noreply.github.com>
8.8 KiB
PowerToys Runner
The PowerToys Runner is the main executable (PowerToys.exe
) that loads and manages all PowerToys modules.
Runner Architecture
The Runner is responsible for:
- Managing the tray icon
- Loading and managing module interfaces
- Handling enabling/disabling modules
- Processing global hotkeys
- Managing updates and settings
Key Components
- Main CPP file manages the tray icon and modules
- Creates a list of modules with DLL paths
- Special handling for WinUI 3 apps (separated in different folder)
- DLLs flattening for consistent versions
- Runs as part of the Windows message loop
- Creates a window handle with a specific class name
- Registers itself as the window handler for components requiring a window handler
Process Flow
- Initialize logger
- Create single instance application mutex
- Initialize common utility code
- Parse command line arguments
- Start the tray icon
- Initialize low-level keyboard hooks
- Load module interfaces from DLLs
- Start enabled modules
- Enter Windows message loop
- On exit, stop modules and clean up resources
System Tray Icon Implementation
The system tray icon is one of the first components that starts when calling the render_main
function:
- Defined in
tray_icon.h
andtray_icon.cpp
- Creates a popup window and registers as window handler via
start_tray_icon()
- Processes window messages through
tray_icon_window_proc()
- Uses
WM_COMMAND
and tray icon notifications for handling menu options - Handles left mouse clicks (distinguishes between single and double clicks)
- Monitors taskbar creation to re-register the icon if needed
- Uses
shell_notify_icon
to register with the system tray
Tray Icon Initialization and Message Processing
-
start_tray_icon()
initializes the tray icon by:- Creating a window with the specified class name
- Setting up the notification icon data structure (NOTIFYICONDATA)
- Registering for taskbar recreate messages
- Adding the icon to the system tray
-
tray_icon_window_proc()
processes window messages, including:- Handling
wm_icon_notify
messages from tray icon interactions - Distinguishing between left-click, double-click, and right-click actions
- Showing context menus or opening Settings windows based on interaction type
- Handling
Communication with Settings UI
When the tray icon is clicked or a menu option is selected, the Runner communicates with the Settings UI:
-
For quick access flyout (left-click):
current_settings_ipc->send(L"{\"ShowYourself\":\"flyout\"}");
-
For the main dashboard (menu option or double-click):
current_settings_ipc->send(L"{\"ShowYourself\":\"Dashboard\"}");
IPC Communication Mechanism
- The Runner and Settings UI communicate through Windows Named Pipes
- A two-way pipe (TwoWayPipeMessageIPC) is established between processes
- JSON messages are sent through this pipe to control UI behavior
- The Settings UI initializes the pipe connection on startup:
ipcmanager = new TwoWayPipeMessageIPCManaged(cmdArgs[(int)Arguments.SettingsPipeName], cmdArgs[(int)Arguments.PTPipeName], (string message) => { if (IPCMessageReceivedCallback != null && message.Length > 0) { IPCMessageReceivedCallback(message); } });
Settings UI Message Processing
The Settings UI processes incoming IPC messages through a callback chain:
- Messages from the Runner are received through the IPC callback
- Messages are parsed as JSON objects
- Registered handlers in
ShellPage.ShellHandler.IPCResponseHandleList
process the messages - The
ReceiveMessage
method inShellPage
interprets commands:- For flyout display:
"ShowYourself": "flyout"
- For main window:
"ShowYourself": "Dashboard"
or other page names
- For flyout display:
When showing the flyout, the tray icon can also send position coordinates to place the flyout near the tray icon:
{
"ShowYourself": "flyout",
"x_position": 1234,
"y_position": 567
}
The flyout window is then activated and brought to the foreground using native Windows APIs to ensure visibility.
Tray Icon Menu
- Menus are defined in
.RC
files (Resource files) base.h
defines IDsresources.resx
contains localized strings- The tray icon window proc handles showing the popup menu
Centralized Keyboard Hook
- Located in "centralized_keyboard_hook.cpp"
- Handles hotkeys for multiple modules to prevent performance issues
- Contains optimizations to exit early when possible:
- Ignores keystrokes generated by PowerToys itself
- Ignores when no keys are actually pressed
- Uses metadata to avoid re-processing modified inputs
- Performance consideration: handler must run very fast as it's called on every keystroke
Module Loading Process
- Scan module directory for DLLs
- Create the module interface object for each module
- Load settings for each module
- Initialize each module
- Check GPO policies to determine which modules can start
- Start enabled modules that aren't disabled by policy
Finding and Messaging the Tray Icon
The tray icon class is used when sending messages to the runner. For example, to close the runner:
// Find the window with the PowerToys tray icon class and send it a close message
WM_CLOSE
Key Files and Their Purposes
main.cpp
Contains the executable starting point, initialization code and the list of known PowerToys. All singletons are also initialized here at the start. Loads all the powertoys by scanning the ./modules
folder and enable()
s those marked as enabled in %LOCALAPPDATA%\Microsoft\PowerToys\settings.json
config. Then it runs a message loop for the tray UI. Note that this message loop also handles lowlevel_keyboard_hook events.
powertoy_module.h
and powertoy_module.cpp
Contains code for initializing and managing the PowerToy modules. PowertoyModule
is a RAII-style holder for the PowertoyModuleIface
pointer, which we got by invoking module DLL's powertoy_create
function.
tray_icon.cpp
Contains code for managing the PowerToys tray icon and its menu commands. Note that dispatch_run_on_main_ui_thread
is used to
transfer received json message from the Settings window to the main thread, since we're communicating with it from a dedicated thread.
settings_window.cpp
Contains code for starting the PowerToys settings window and communicating with it. Settings window is a separate process, so we're using Windows pipes as a transport for json messages.
general_settings.cpp
Contains code for loading, saving and applying the general settings.
auto_start_helper.cpp
Contains helper code for registering and unregistering PowerToys to run when the user logs in.
unhandled_exception_handler.cpp
Contains helper code to get stack traces in builds. Can be used by adding a call to init_global_error_handlers
in WinMain
.
trace.cpp
Contains code for telemetry.
svgs
Contains the SVG assets used by the PowerToys modules.
bug_report.cpp
Contains logic to start bug report tool.
centralized_hotkeys.cpp
Contains hot key logic registration and un-registration.
centralized_kb_hook.cpp
Contains logic to handle PowerToys' keyboard shortcut functionality.
restart_elevated.cpp
Contains logic for restarting the current process with different elevation levels.
RestartManagement.cpp
Contains code for restarting a process.
settings_telemetry.cpp
Contains logic that periodically triggers module-specific setting's telemetry delivery and manages timing and error handling for the process.
UpdateUtils.cpp
Contains code to handle the automatic update checking, notification, and installation process for PowerToys.