Developing Shell Extensions for File Explorer Context Menus in PowerToys: A Complete Guide

PowerToys implements File Explorer context menu extensions using the Windows Explorer Command API (IExplorerCommand), creating hierarchical sub-menus through COM objects that dynamically enumerate template items in the New+ module.

The New+ feature in microsoft/PowerToys demonstrates advanced shell extension development by adding dynamic context menus to Windows File Explorer. This implementation showcases how to build scalable, settings-aware context menu extensions using modern Windows APIs. Understanding this architecture provides a blueprint for developing shell extensions for File Explorer context menus in PowerToys or standalone Windows applications.

Architecture of the Explorer Command API Implementation

PowerToys’s New+ shell extension follows a three-layer COM architecture based on the Explorer Command API.

Layer 1: Top-level command (shell_context_menu.cpp) Implements IExplorerCommand to expose the root "New+" menu item. Key methods include GetTitle for localization, GetIcon for the menu icon, and GetFlags returning ECF_HASSUBCOMMANDS to indicate sub-menu availability.

Layer 2: Sub-command enumerator (shell_context_sub_menu.cpp) Implements IEnumExplorerCommand to dynamically generate the menu list. This scans the user's New+ Templates folder and instantiates individual commands for each template file.

Layer 3: Individual template commands (shell_context_sub_menu_item.cpp) Each template item implements IExplorerCommand with GetTitle, GetIcon, and Invoke methods that execute the copy operation when selected.

Core Components for Developing File Explorer Context Menu Extensions

Top-Level Menu Command (shell_context_menu.cpp)

Located at src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_menu.cpp, this file contains the shell_context_menu class implementing the root menu item.

The class exposes four critical methods:

  • GetTitle – Returns the localized string "New+" from resources
  • GetIcon – Resolves the icon path via utilities::get_new_icon_resource_filepath
  • GetState – Queries NewSettingsInstance().GetEnabled() to hide the menu when the feature is disabled
  • EnumSubCommands – Instantiates shell_context_sub_menu to provide the sub-menu enumerator

Dynamic Sub-Menu Enumeration (shell_context_sub_menu.cpp)

The shell_context_sub_menu class in shell_context_sub_menu.cpp implements IEnumExplorerCommand to provide dynamic content.

During construction, it:

  1. Calls utilities::get_new_template_folder_location() to locate user templates
  2. Iterates through template definitions
  3. Creates shell_context_sub_menu_item instances stored in explorer_menu_item_commands
  4. Appends static items: a separator (separator_context_menu_item) and "Open templates" entry (template_folder_context_menu_item)

The class implements standard enumerator methods: Next, Reset, and Skip.

Per-Template Command Execution (shell_context_sub_menu_item.cpp)

Individual menu items are handled by shell_context_sub_menu_item in shell_context_sub_menu_item.cpp.

Each instance:

  • Formats display titles via GetTitle, applying settings like hiding extensions or leading digits
  • Resolves template-specific icons through GetIcon
  • Executes Invoke to call newplus::utilities::copy_template(), copying template contents to the selected folder

Integrating Settings and Utilities

Settings Integration (settings.cpp)

The extension respects PowerToys configuration through settings.cpp. The NewSettingsInstance() singleton reads JSON configuration to determine:

  • Whether the feature is enabled (affects GetState)
  • Display preferences like hiding file extensions or leading digits in template names

Utility Layer (new_utilities.cpp)

Helper functions in new_utilities.cpp handle filesystem operations:

  • copy_template() – Performs the actual file copy from template folder to destination
  • open_template_folder() – Launches the templates directory when users select "Open templates"
  • create_folder_if_not_exist() – Ensures the template directory exists before enumeration

COM Registration and Module Entry Point

Registration occurs in powertoys_module.cpp, which declares the COM class under the ExplorerCommand CLSID. The PowerToys module loader ensures the DLL loads when Explorer constructs the context menu, registering the extension with Windows Explorer's command infrastructure.

Practical Implementation: Adding a Custom Template Item

Below is a minimal example adapted from template_folder.cpp showing how to programmatically add a template item within the sub-menu enumerator:

// Resolve the template folder location
const std::filesystem::path templateRoot = utilities::get_new_template_folder_location();
utilities::create_folder_if_not_exist(templateRoot);

// Create a template item manually (typically loaded from JSON)
auto myProjectTemplate = std::make_unique<template_item>();
myProjectTemplate->set_name(L"My Project");
myProjectTemplate->set_icon(L"myproject.ico");
myProjectTemplate->set_content(L"// My C++ project skeleton");

// Add to the command list for enumeration
explorer_menu_item_commands.push_back(
    Make<shell_context_sub_menu_item>(myProjectTemplate.get(), site_of_folder));

When selected, shell_context_sub_menu_item::Invoke forwards to newplus::utilities::copy_template(), creating the file at the target location.

Summary

  • PowerToys uses IExplorerCommand to implement File Explorer context menu extensions, not legacy context menu handlers
  • Three-layer architecture: Top-level command (shell_context_menu.cpp), enumerator (shell_context_sub_menu.cpp), and item commands (shell_context_sub_menu_item.cpp)
  • Dynamic enumeration: The extension scans %LOCALAPPDATA%\Microsoft\PowerToys\New+\Templates to build menus at runtime
  • Settings-aware: settings.cpp integrates with PowerToys JSON configuration to control visibility and formatting
  • COM registration: powertoys_module.cpp registers the extension using the ExplorerCommand CLSID for automatic loading by Explorer

Frequently Asked Questions

What Windows API does PowerToys use for File Explorer context menus?

PowerToys implements the Explorer Command API using IExplorerCommand and IEnumExplorerCommand interfaces. This modern API, used in the New+ module's shell_context_menu.cpp, provides better performance and reliability than legacy context menu shell extensions.

How does the New+ extension dynamically populate its sub-menu?

The shell_context_sub_menu class in shell_context_sub_menu.cpp implements IEnumExplorerCommand::Next to enumerate template files from the user's New+ Templates folder. It creates a shell_context_sub_menu_item for each template, plus static entries for the separator and "Open templates" command.

Where does PowerToys store the template files for the New+ menu?

Templates are stored in the user's local application data folder, resolved via utilities::get_new_template_folder_location() in new_utilities.cpp. The path typically resolves to %LOCALAPPDATA%\Microsoft\PowerToys\New+\Templates, where the extension reads JSON or text definitions.

How can I disable the New+ context menu without uninstalling PowerToys?

The extension checks NewSettingsInstance().GetEnabled() in shell_context_menu::GetState (located in shell_context_menu.cpp). When disabled in PowerToys Settings, the method returns ECS_HIDDEN, preventing the menu from appearing in File Explorer context menus.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →