Gleb Khmyznikov 725535b760
Some checks failed
Spell checking / Check Spelling (push) Has been cancelled
Spell checking / Report (Push) (push) Has been cancelled
Spell checking / Report (PR) (push) Has been cancelled
Spell checking / Update PR (push) Has been cancelled
[DevDocs] More content and restructure (#40165)
## 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>
2025-07-01 14:27:34 +02:00

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

  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):

    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:

  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:

{
  "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:

// 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.