Skip to main content

Philosophy

PowerToys follows a pragmatic approach to coding style:
  1. When modifying existing code: Follow the existing style as closely as possible
  2. When writing new code: Follow Modern C++ and C# best practices
  3. When refactoring: Apply modern patterns and reference language guidelines
Consistency within a file or module is more important than strict adherence to global rules. Make the code readable and maintainable.

C++ Style

Core Guidelines

Follow the C++ Core Guidelines for modern C++ development. Key principles:
  • Use RAII (Resource Acquisition Is Initialization)
  • Prefer std::unique_ptr and std::shared_ptr over raw pointers
  • Use const and constexpr where applicable
  • Avoid manual memory management
  • Use standard library algorithms and containers

Code Formatting

PowerToys uses ClangFormat for automatic C++ code formatting.

Using ClangFormat in Visual Studio

Automatic formatting:
  • Format document: Ctrl+K, Ctrl+D
  • Format selection: Ctrl+K, Ctrl+F
Enable automatic formatting:
  1. Tools > Options > Text Editor > C/C++ > Code Style > Formatting
  2. Check “Automatically format on paste”
  3. Check “Automatically format completed statement on ;“

Using ClangFormat from Command Line

Format modified files automatically:
# Format all modified files
.\src\codeAnalysis\format_sources.ps1
Requirements:
  • Run from “Native Tools Command Prompt for VS”
  • Or ensure clang-format.exe is in %PATH%
  • Script uses Git to find modified files
Manual formatting:
# Format specific file
clang-format -i path\to\file.cpp

# Format with style from .clang-format
clang-format -style=file -i path\to\file.cpp

ClangFormat Configuration

Configuration file: src/.clang-format Key formatting rules:
BasedOnStyle: LLVM
IndentWidth: 4
TabWidth: 4
UseTab: Never
ColumnLimit: 120
PointerAlignment: Left
BreakBeforeBraces: Allman

C++ Naming Conventions

ElementConventionExample
ClassesPascalCaseColorPicker, WindowManager
FunctionscamelCase or snake_casegetWindowRect(), init_logger()
VariablescamelCase or snake_casecurrentWindow, window_rect
ConstantsUPPER_CASEMAX_BUFFER_SIZE
Namespaceslowercasefancyzones, powerrenameext
Member variablesm_ prefix (optional)m_windowHandle, m_settings

C++ Best Practices

Modern C++ Features

Prefer smart pointers:
// Good
auto window = std::make_unique<Window>();
std::shared_ptr<Settings> settings = GetSettings();

// Avoid
Window* window = new Window();
delete window;
Use auto for type deduction:
// Good
auto rect = GetWindowRect(hwnd);
auto& settings = GetSettings();

// Avoid
RECT rect = GetWindowRect(hwnd);
Range-based for loops:
// Good
for (const auto& item : collection)
{
    ProcessItem(item);
}

// Avoid
for (size_t i = 0; i < collection.size(); i++)
{
    ProcessItem(collection[i]);
}

String Handling

// Prefer std::wstring for Windows APIs
std::wstring windowTitle = L"PowerToys";

// Use string literals
using namespace std::string_literals;
auto message = L"Error: "s + errorDetails;

// Avoid C-style strings when possible
// Use std::wstring instead of wchar_t*

Error Handling

// Use exceptions for exceptional cases
try
{
    auto result = ProcessInput(input);
}
catch (const std::exception& ex)
{
    Logger::error("Processing failed: {}", ex.what());
}

// Use return codes for expected failures
if (!ValidateInput(input))
{
    return ERROR_INVALID_PARAMETER;
}

Include Order

// 1. Precompiled header (if used)
#include "pch.h"

// 2. Corresponding header file
#include "MyClass.h"

// 3. C system headers
#include <windows.h>

// 4. C++ standard library headers
#include <string>
#include <vector>
#include <memory>

// 5. Third-party library headers
#include <json.hpp>

// 6. Project headers
#include "common/utils.h"
#include "Settings.h"

C# Style

Naming Conventions

ElementConventionExample
ClassesPascalCaseColorPicker, SettingsViewModel
InterfacesIPascalCaseIModule, ISettings
MethodsPascalCaseGetWindowRect(), ProcessInput()
PropertiesPascalCaseWindowTitle, IsEnabled
Fields (private)_camelCase_windowHandle, _settings
ParameterscamelCasewindowHandle, inputText
Local variablescamelCasecurrentWindow, result
ConstantsPascalCaseMaxBufferSize, DefaultTimeout
EnumsPascalCaseWindowState.Maximized

C# Best Practices

Nullable Reference Types

PowerToys enables nullable reference types:
// Good - explicit nullability
public string? GetWindowTitle(Window? window)
{
    if (window == null)
    {
        return null;
    }
    return window.Title;
}

// Use null-forgiving operator when you know it's not null
var title = GetWindowTitle(window)!;

Properties vs Fields

// Good - use properties for public members
public class Settings
{
    public string ModuleName { get; set; }
    public bool IsEnabled { get; set; }
    
    private string _internalState;
}

// Use auto-properties when possible
public string Name { get; set; } = "Default";

LINQ and Modern C#

// Good - use LINQ for collections
var activeModules = modules
    .Where(m => m.IsEnabled)
    .OrderBy(m => m.Name)
    .ToList();

// Pattern matching
if (obj is Settings settings && settings.IsEnabled)
{
    ApplySettings(settings);
}

// Switch expressions
var description = module switch
{
    "FancyZones" => "Window manager",
    "PowerRename" => "Bulk rename tool",
    _ => "Unknown module"
};

Async/Await

// Good - async all the way
public async Task<Settings> LoadSettingsAsync()
{
    var json = await File.ReadAllTextAsync(settingsPath);
    return JsonSerializer.Deserialize<Settings>(json);
}

// Use ConfigureAwait(false) in library code
var result = await ProcessAsync().ConfigureAwait(false);

IDisposable Pattern

public class ResourceManager : IDisposable
{
    private bool _disposed = false;
    private FileStream? _stream;

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                // Dispose managed resources
                _stream?.Dispose();
            }
            _disposed = true;
        }
    }
}

C# Code Formatting

Visual Studio’s default C# formatting is generally acceptable. Key settings:
  • Indentation: 4 spaces (no tabs)
  • Brace style: Allman (braces on new line)
  • Line length: Aim for 120 characters or less
Example:
public class Example
{
    public void Method(string parameter)
    {
        if (condition)
        {
            DoSomething();
        }
        else
        {
            DoSomethingElse();
        }
    }
}

XAML Style

XamlStyler

PowerToys uses XamlStyler for XAML formatting.

Install XamlStyler

Visual Studio Extension

Apply XAML Formatting

In Visual Studio:
  • Format on save (if enabled in XamlStyler options)
  • Manual format: Right-click in XAML editor > Format Document
From command line:
# Format all XAML files
.\.pipelines\applyXamlStyling.ps1 -Main

XAML Conventions

Element ordering:
<Button
    x:Name="SaveButton"
    Grid.Row="1"
    Grid.Column="2"
    Width="100"
    Height="32"
    Margin="8,0,0,0"
    Content="Save"
    Click="SaveButton_Click" />
Use resource strings:
<!-- Good - localizable -->
<TextBlock Text="{x:Bind ViewModel.Title}" />
<Button x:Uid="SaveButton" Content="Save" />

<!-- Avoid - hardcoded strings -->
<Button Content="Save" />
Naming:
  • x:Name in PascalCase: MainGrid, SettingsPanel
  • x:Uid for localization: ModuleName_SettingName

Resource Strings and Localization

Resource String Naming

Pattern: <ModuleName>_<Context>_<Element> Examples:
FancyZones_Settings_EnableZones
ColorPicker_OOBE_Description
PowerRename_Error_InvalidPattern

Using Resource Strings

In XAML:
<TextBlock x:Uid="FancyZones_Settings_Title" />

<!-- In Resources.resw -->
<data name="FancyZones_Settings_Title.Text" xml:space="preserve">
  <value>FancyZones Settings</value>
</data>
In C#:
var resourceLoader = ResourceLoader.GetForViewIndependentUse();
string title = resourceLoader.GetString("FancyZones_Settings_Title");
Never submit PRs that modify localized strings in languages other than English. Localization is handled by Microsoft’s internal localization team.

Code Comments

When to Comment

Good comments explain WHY:
// Delay required for WinAppDriver to stabilize after window creation
Sleep(500);

// Windows 10 SDK bug workaround: CoCreateInstance fails without explicit apartment initialization
CoInitialize(nullptr);
Poor comments explain WHAT (code already shows this):
// Bad - obvious from code
count++; // Increment count

XML Documentation (C#)

/// <summary>
/// Processes the input string and returns the formatted result.
/// </summary>
/// <param name="input">The input string to process.</param>
/// <returns>The processed string, or null if input is invalid.</returns>
/// <exception cref="ArgumentNullException">Thrown when input is null.</exception>
public string? ProcessInput(string input)
{
    // Implementation
}

Doxygen Comments (C++)

/**
 * @brief Retrieves the window rectangle.
 * @param hwnd Handle to the window.
 * @return The window rectangle, or empty rect if hwnd is invalid.
 */
RECT GetWindowRect(HWND hwnd);

Pull Request Guidelines

PR Checklist

Before submitting a PR:
  • Code follows existing style in modified files
  • New code follows modern C++/C# practices
  • Code is formatted (ClangFormat for C++, XamlStyler for XAML)
  • Comments explain complex logic
  • Resource strings used for user-facing text
  • No hardcoded strings in UI
  • Code builds without warnings
  • Tests pass locally

Code Review Expectations

Reviewers will check for:
  • Code readability and maintainability
  • Proper error handling
  • Memory management (C++ leaks, C# disposable patterns)
  • Thread safety for async code
  • Security considerations (input validation, injection attacks)
  • Performance implications
  • Consistency with existing patterns

Before Opening PR

  1. Format your code:
    # C++ files
    .\src\codeAnalysis\format_sources.ps1
    
    # XAML files
    .\.pipelines\applyXamlStyling.ps1 -Main
    
  2. Build successfully:
    .\tools\build\build.ps1 -Configuration Release
    
  3. Run tests:
    • Test Explorer: Run all tests
    • Verify no regressions
  4. Review changes:
    git diff
    
    • Remove debug code
    • Remove commented-out code
    • Check for unintended changes

Project-Specific Guidelines

Settings Integration

Settings JSON structure:
public class ModuleSettings : BasePTModuleSettings
{
    public ModuleSettings()
    {
        Name = "ModuleName";
        Version = "1.0";
    }

    public ModuleProperties Properties { get; set; } = new ModuleProperties();
}

public class ModuleProperties
{
    public bool IsEnabled { get; set; } = true;
    public string HotKey { get; set; } = "Win+Shift+M";
}

Logging Standards

C++ logging:
#include <common/logger/logger.h>

Logger::info("Module initialized");
Logger::warn("Configuration issue: {}", details);
Logger::error("Failed to process: {}", errorMessage);
C# logging:
using ManagedCommon;

Logger.LogInfo("Module initialized");
Logger.LogWarning("Configuration issue");
Logger.LogError("Failed to process", exception);
Logging principles:
  • Log errors and warnings always
  • Log info for important operations
  • Use debug/trace sparingly (disabled by default)
  • Include context in log messages
  • Don’t log sensitive information (passwords, tokens, PII)

Telemetry

C++ telemetry:
#include <common/Telemetry/trace.h>

Trace::ModuleName::Enable(true);
C# telemetry:
using PowerToys.Telemetry;

PowerToysTelemetry.Log.WriteEvent(new ModuleEnabledEvent());
All telemetry respects user privacy settings. Users can disable telemetry in PowerToys Settings.

Code Quality Tools

Static Analysis

PowerToys uses Visual Studio’s code analysis: For C++:
  • Configuration: CppRuleSet.ruleset
  • Properties: Cpp.Build.props
For C#:
  • Built-in Roslyn analyzers
  • Configuration in .editorconfig

Build Properties

Key build properties:
  • Directory.Build.props - Shared properties for all projects
  • Directory.Build.targets - Shared targets
  • Directory.Packages.props - Central package version management

Additional Resources

External Style Guides

PowerToys Documentation

Next Steps

Building

Build PowerToys from source

Debugging

Debug PowerToys effectively

Testing

Write tests for your code

Creating New Utility

Create a new PowerToys utility

Build docs developers (and LLMs) love