mirror of
https://github.com/microsoft/PowerToys
synced 2025-08-22 18:17:19 +00:00
198 lines
8.8 KiB
Markdown
198 lines
8.8 KiB
Markdown
|
# 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
|
||
|
|
||
|
1. Initialize logger
|
||
|
2. Create single instance application mutex
|
||
|
3. Initialize common utility code
|
||
|
4. Parse command line arguments
|
||
|
5. Start the tray icon
|
||
|
6. Initialize low-level keyboard hooks
|
||
|
7. Load module interfaces from DLLs
|
||
|
8. Start enabled modules
|
||
|
9. Enter Windows message loop
|
||
|
10. 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` and `tray_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
|
||
|
|
||
|
### 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):
|
||
|
```cpp
|
||
|
current_settings_ipc->send(L"{\"ShowYourself\":\"flyout\"}");
|
||
|
```
|
||
|
|
||
|
- For the main dashboard (menu option or double-click):
|
||
|
```cpp
|
||
|
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:
|
||
|
```csharp
|
||
|
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:
|
||
|
|
||
|
1. Messages from the Runner are received through the IPC callback
|
||
|
2. Messages are parsed as JSON objects
|
||
|
3. Registered handlers in `ShellPage.ShellHandler.IPCResponseHandleList` process the messages
|
||
|
4. The `ReceiveMessage` method in `ShellPage` interprets commands:
|
||
|
- For flyout display: `"ShowYourself": "flyout"`
|
||
|
- For main window: `"ShowYourself": "Dashboard"` or other page names
|
||
|
|
||
|
When showing the flyout, the tray icon can also send position coordinates to place the flyout near the tray icon:
|
||
|
```json
|
||
|
{
|
||
|
"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 IDs
|
||
|
- `resources.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
|
||
|
|
||
|
1. Scan module directory for DLLs
|
||
|
2. Create the module interface object for each module
|
||
|
3. Load settings for each module
|
||
|
4. Initialize each module
|
||
|
5. Check GPO policies to determine which modules can start
|
||
|
6. 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:
|
||
|
|
||
|
```cpp
|
||
|
// Find the window with the PowerToys tray icon class and send it a close message
|
||
|
WM_CLOSE
|
||
|
```
|
||
|
|
||
|
## Key Files and Their Purposes
|
||
|
|
||
|
#### [`main.cpp`](/src/runner/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](https://learn.microsoft.com/windows/win32/winmsg/using-messages-and-message-queues) for the tray UI. Note that this message loop also [handles lowlevel_keyboard_hook events](https://github.com/microsoft/PowerToys/blob/1760af50c8803588cb575167baae0439af38a9c1/src/runner/lowlevel_keyboard_event.cpp#L24).
|
||
|
|
||
|
#### [`powertoy_module.h`](/src/runner/powertoy_module.h) and [`powertoy_module.cpp`](/src/runner/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](https://github.com/microsoft/PowerToys/blob/1760af50c8803588cb575167baae0439af38a9c1/src/runner/powertoy_module.cpp#L13-L24).
|
||
|
|
||
|
#### [`tray_icon.cpp`](/src/runner/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](/doc/devdocs/settings.md) to the main thread, since we're communicating with it from [a dedicated thread](https://github.com/microsoft/PowerToys/blob/7357e40d3f54de51176efe54fda6d57028837b8c/src/runner/settings_window.cpp#L267-L271).
|
||
|
|
||
|
#### [`settings_window.cpp`](/src/runner/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](https://learn.microsoft.com/windows/win32/ipc/pipes) as a transport for json messages.
|
||
|
|
||
|
#### [`general_settings.cpp`](/src/runner/general_settings.cpp)
|
||
|
Contains code for loading, saving and applying the general settings.
|
||
|
|
||
|
#### [`auto_start_helper.cpp`](/src/runner/auto_start_helper.cpp)
|
||
|
Contains helper code for registering and unregistering PowerToys to run when the user logs in.
|
||
|
|
||
|
#### [`unhandled_exception_handler.cpp`](/src/runner/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`](./main.cpp).
|
||
|
|
||
|
#### [`trace.cpp`](/src/runner/trace.cpp)
|
||
|
Contains code for telemetry.
|
||
|
|
||
|
#### [`svgs`](/src/runner/svgs/)
|
||
|
Contains the SVG assets used by the PowerToys modules.
|
||
|
|
||
|
#### [`bug_report.cpp`](/src/runner/bug_report.cpp)
|
||
|
Contains logic to start bug report tool.
|
||
|
|
||
|
#### [`centralized_hotkeys.cpp`](/src/runner/centralized_hotkeys.cpp)
|
||
|
Contains hot key logic registration and un-registration.
|
||
|
|
||
|
#### [`centralized_kb_hook.cpp`](/src/runner/centralized_kb_hook.cpp)
|
||
|
Contains logic to handle PowerToys' keyboard shortcut functionality.
|
||
|
|
||
|
#### [`restart_elevated.cpp`](/src/runner/restart_elevated.cpp)
|
||
|
Contains logic for restarting the current process with different elevation levels.
|
||
|
|
||
|
#### [`RestartManagement.cpp`](/src/runner/RestartManagement.cpp)
|
||
|
Contains code for restarting a process.
|
||
|
|
||
|
#### [`settings_telemetry.cpp`](/src/runner/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`](/src/runner/UpdateUtils.cpp)
|
||
|
Contains code to handle the automatic update checking, notification, and installation process for PowerToys.
|