Files
PowerToys/tools/module_loader/SHARING.md
Mike Hall 452e0dcf51 Module Loader tool for rapid testing of modules (#43813)
## Summary of the Pull Request
ModuleLoader tool, a stand-alone Win32 executable for testing of
PowerToy modules without needing branch builds.

sample output from running the tool is below:

.\ModuleLoader.exe .\powertoys.cursorwrap.dll
PowerToys Module Loader v1.0
=============================

Loading module: .\powertoys.cursorwrap.dll
Detected module name: cursorwrap

Loading settings...
Trying settings path:
C:\Users\mikehall\AppData\Local\Microsoft\PowerToys\cursorwrap\settings.json
Settings file loaded (315 characters)
Settings loaded successfully.

Loading module DLL...
Module instance created successfully
Module DLL loaded successfully.
Module key: CursorWrap
Module name: CursorWrap

Applying settings to module...
Settings applied.

Registering module hotkeys...
Module reports 1 legacy hotkey(s)
  Registering hotkey 0: Win+Alt+U - OK
Hotkeys registered: 1

Enabling module...
Module enabled.

=============================
Module is now running!
=============================

Module Status:
  - Name: CursorWrap
  - Key: CursorWrap
  - Enabled: Yes
  - Hotkeys: 1 registered

Registered Hotkeys:
  Win+Alt+U

Press Ctrl+C to exit.
You can press the module's hotkey to toggle its functionality.

Note that this doesn't integrate with Powertoys settings UI - this is
purely to test Powertoys module functionality.

## PR Checklist

- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

## Detailed Description of the Pull Request / Additional comments
See details above.

## Validation Steps Performed
ModuleLoader tested on Windows 11, Surface Laptop 7 Pro.
2025-11-26 22:08:34 +08:00

14 KiB

Sharing ModuleLoader and Modules

This guide explains how to share the ModuleLoader tool and PowerToy modules with others for testing purposes.

Overview

The ModuleLoader is designed to be a portable, standalone testing tool that can be shared with module developers and testers. It has minimal dependencies and can work with any compatible PowerToy module DLL.


What You Need to Share

For Testing a Module (e.g., CursorWrap)

  1. ModuleLoader.exe - The standalone loader application

    • Location: x64\Debug\ModuleLoader.exe or x64\Release\ModuleLoader.exe
    • No additional DLLs required (uses only Windows system libraries)
  2. The Module DLL - The PowerToy module to test

    • Example: CursorWrap.dll from x64\Debug\ or x64\Release\
    • Location varies by module (see module-specific locations below)
  3. settings.json - Module configuration (place in same folder as the DLL)

    • NEW: Settings can be placed alongside the module DLL for portable testing
    • Location: Same directory as the module DLL (e.g., settings.json next to CursorWrap.dll)
    • Falls back to: %LOCALAPPDATA%\Microsoft\PowerToys\<ModuleName>\settings.json if not found locally

Complete Standalone Package (For Users Without PowerToys Installed)

  1. ModuleLoader.exe
  2. Module DLL
  3. Sample settings.json - Pre-configured settings file
  4. Installation instructions - See "Standalone Package Setup" section below

Debug Builds

If you build the module in Debug configuration:

  • The module will output debug messages via OutputDebugString()
  • View these with DebugView or Visual Studio Output window
  • Example: CursorWrap outputs detailed topology and cursor wrapping debug info

Module-Specific File Locations

CursorWrap

Files to share:
  - x64\Debug\CursorWrap.dll  (or Release)
  - %LOCALAPPDATA%\Microsoft\PowerToys\CursorWrap\settings.json

Size: ~100KB

MouseHighlighter

Files to share:
  - x64\Debug\MouseHighlighter.dll  (or Release)
  - %LOCALAPPDATA%\Microsoft\PowerToys\MouseHighlighter\settings.json

Size: ~150KB

FindMyMouse

Files to share:
  - x64\Debug\FindMyMouse.dll  (or Release)
  - %LOCALAPPDATA%\Microsoft\PowerToys\FindMyMouse\settings.json

Size: ~120KB

MousePointerCrosshairs

Files to share:
  - x64\Debug\MousePointerCrosshairs.dll  (or Release)
  - %LOCALAPPDATA%\Microsoft\PowerToys\MousePointerCrosshairs\settings.json

Size: ~140KB

MouseJump

Files to share:
  - x64\Debug\MouseJump.dll  (or Release)
  - %LOCALAPPDATA%\Microsoft\PowerToys\MouseJump\settings.json

Note: MouseJump is a UI-based module and may not work fully with ModuleLoader
Size: ~200KB

AlwaysOnTop

Files to share:
  - x64\Debug\AlwaysOnTop.dll  (or Release)
  - %LOCALAPPDATA%\Microsoft\PowerToys\AlwaysOnTop\settings.json

Size: ~100KB

Dependency Analysis

ModuleLoader.exe Dependencies

Windows System Libraries Only (automatically available on all Windows systems):

  • KERNEL32.dll - Core Windows API
  • USER32.dll - User interface functions
  • SHELL32.dll - Shell functions
  • ole32.dll - COM library

No PowerToys dependencies required! The ModuleLoader is completely standalone.

Module DLL Dependencies (Typical)

Most PowerToy modules depend on:

  • Windows system DLLs (automatically available)
  • PowerToys common libraries (if any, they're typically statically linked)
  • Module settings - Must be present in %LOCALAPPDATA%\Microsoft\PowerToys\<ModuleName>\

Important: Modules are generally self-contained and statically link most dependencies. You typically only need the module DLL itself.


Creating a Standalone Package

Step 1: Prepare the Files

Create a folder structure like this:

ModuleLoaderPackage\
??? ModuleLoader.exe
??? CursorWrap.dll (or other module)
??? settings.json (module settings - placed locally!)

NEW Simplified Structure: You can now place settings.json directly alongside the module DLL! The ModuleLoader will check this location first before looking in the standard PowerToys settings directories.

Step 2: Extract Settings from Your Machine

# Copy settings from your development machine
$moduleName = "CursorWrap"  # Change as needed
$settingsPath = "$env:LOCALAPPDATA\Microsoft\PowerToys\$moduleName\settings.json"
Copy-Item $settingsPath ".\settings\$moduleName\settings.json"

Step 3: Create Installation Instructions (README.txt)

PowerToys Module Testing Package
=================================

This package contains the ModuleLoader tool for testing PowerToy modules.

Contents:
  - ModuleLoader.exe     : Standalone module loader
  - modules\*.dll        : PowerToy module(s) to test
  - settings\*\*.json    : Module configuration files

Setup (First Time):
-------------------
1. Create settings directory:
   %LOCALAPPDATA%\Microsoft\PowerToys\

2. Copy settings:
   Copy the entire "settings\<ModuleName>" folder to:
   %LOCALAPPDATA%\Microsoft\PowerToys\

   Example for CursorWrap:
   Copy "settings\CursorWrap" to:
   %LOCALAPPDATA%\Microsoft\PowerToys\CursorWrap\

Usage:
------
ModuleLoader.exe modules\CursorWrap.dll

The tool will:
  - Load the module DLL
  - Read settings from %LOCALAPPDATA%\Microsoft\PowerToys\<ModuleName>\
  - Register hotkeys
  - Enable the module

Press Ctrl+C to exit.
Press the module's hotkey to toggle functionality.

Requirements:
-------------
- Windows 10 1803 or later
- No PowerToys installation required!

Troubleshooting:
----------------
If you see "Settings file not found":
  1. Make sure you copied the settings folder correctly
  2. Check that the path is:
     %LOCALAPPDATA%\Microsoft\PowerToys\<ModuleName>\settings.json
  3. You can also run PowerToys once to generate default settings

Debug Logs:
-----------
Module logs are written to:
  %LOCALAPPDATA%\Microsoft\PowerToys\<ModuleName>\Logs\

For debug builds, use DebugView to see real-time output.

Quick Distribution Methods

Method 1: ZIP Archive

# Create a complete package
$moduleName = "CursorWrap"
$packageName = "ModuleLoader-$moduleName-Package"

# Collect files
New-Item $packageName -ItemType Directory
Copy-Item "x64\Debug\ModuleLoader.exe" "$packageName\"
New-Item "$packageName\modules" -ItemType Directory
Copy-Item "x64\Debug\$moduleName.dll" "$packageName\modules\"
New-Item "$packageName\settings\$moduleName" -ItemType Directory -Force
Copy-Item "$env:LOCALAPPDATA\Microsoft\PowerToys\$moduleName\settings.json" "$packageName\settings\$moduleName\"

# Create README
@"
See README in the tools\module_loader folder for instructions
"@ | Out-File "$packageName\README.txt"

# Zip it
Compress-Archive -Path $packageName -DestinationPath "$packageName.zip"

Method 2: Direct Share (Advanced Users)

For developers who already have PowerToys installed:

# Just share the executables
Copy-Item "x64\Debug\ModuleLoader.exe" "\\ShareLocation\"
Copy-Item "x64\Debug\CursorWrap.dll" "\\ShareLocation\"

They can run: ModuleLoader.exe CursorWrap.dll (Settings will be loaded from their existing PowerToys installation)


Platform-Specific Notes

x64 vs ARM64

Important: Match architectures!

  • x64\Debug\ModuleLoader.exe ? Only works with x64 module DLLs
  • ARM64\Debug\ModuleLoader.exe ? Only works with ARM64 module DLLs

Distribution Tip: Provide both architectures if targeting multiple platforms:

ModuleLoaderPackage\
??? x64\
?   ??? ModuleLoader.exe
?   ??? modules\CursorWrap.dll
??? ARM64\
?   ??? ModuleLoader.exe
?   ??? modules\CursorWrap.dll
??? settings\...

Debug vs Release

Debug builds:

  • Larger file size
  • Include debug symbols
  • Verbose logging via OutputDebugString()
  • Recommended for testing/development

Release builds:

  • Smaller file size
  • Optimized performance
  • Minimal logging
  • Recommended for end-user testing

Testing Checklist

Before sharing a module package:

  • ModuleLoader.exe is included
  • Module DLL is included (matching architecture)
  • Sample settings.json is included
  • README/instructions are included
  • Tested on a clean machine (no PowerToys installed)
  • Verified hotkeys work
  • Verified Ctrl+C exits cleanly
  • Confirmed settings path in documentation

Advanced: Portable Package Script

Here's a complete PowerShell script to create a fully portable package:

param(
    [Parameter(Mandatory=$true)]
    [string]$ModuleName,
    
    [ValidateSet("Debug", "Release")]
    [string]$Configuration = "Debug",
    
    [ValidateSet("x64", "ARM64")]
    [string]$Platform = "x64"
)

$packageName = "ModuleLoader-$ModuleName-$Platform-$Configuration"
$packagePath = ".\$packageName"

Write-Host "Creating portable package: $packageName" -ForegroundColor Green

# Create structure
New-Item $packagePath -ItemType Directory -Force | Out-Null
New-Item "$packagePath\modules" -ItemType Directory -Force | Out-Null
New-Item "$packagePath\settings\$ModuleName" -ItemType Directory -Force | Out-Null

# Copy ModuleLoader
$loaderPath = "$Platform\$Configuration\ModuleLoader.exe"
if (Test-Path $loaderPath) {
    Copy-Item $loaderPath "$packagePath\"
    Write-Host "? Copied ModuleLoader.exe" -ForegroundColor Green
} else {
    Write-Host "? ModuleLoader.exe not found at $loaderPath" -ForegroundColor Red
    exit 1
}

# Copy Module DLL
$modulePath = "$Platform\$Configuration\$ModuleName.dll"
if (Test-Path $modulePath) {
    Copy-Item $modulePath "$packagePath\modules\"
    Write-Host "? Copied $ModuleName.dll" -ForegroundColor Green
} else {
    Write-Host "? $ModuleName.dll not found at $modulePath" -ForegroundColor Red
    exit 1
}

# Copy Settings
$settingsPath = "$env:LOCALAPPDATA\Microsoft\PowerToys\$ModuleName\settings.json"
if (Test-Path $settingsPath) {
    Copy-Item $settingsPath "$packagePath\settings\$ModuleName\"
    Write-Host "? Copied settings.json" -ForegroundColor Green
} else {
    Write-Host "? Settings not found at $settingsPath - creating placeholder" -ForegroundColor Yellow
    @"
{
  "name": "$ModuleName",
  "version": "1.0"
}
"@ | Out-File "$packagePath\settings\$ModuleName\settings.json"
}

# Create README
@"
PowerToys $ModuleName Testing Package
======================================

Configuration: $Configuration
Platform: $Platform

Setup Instructions:
-------------------
1. Copy the 'settings\$ModuleName' folder to:
   %LOCALAPPDATA%\Microsoft\PowerToys\

2. Run:
   ModuleLoader.exe modules\$ModuleName.dll

3. Press Ctrl+C to exit

Logs are written to:
  %LOCALAPPDATA%\Microsoft\PowerToys\$ModuleName\Logs\

For more information, see:
  https://github.com/microsoft/PowerToys/tree/main/tools/module_loader
"@ | Out-File "$packagePath\README.txt"

# Create ZIP
$zipPath = "$packageName.zip"
Compress-Archive -Path $packagePath -DestinationPath $zipPath -Force
Write-Host "? Created $zipPath" -ForegroundColor Green

# Show summary
Write-Host "`nPackage Contents:" -ForegroundColor Cyan
Get-ChildItem $packagePath -Recurse | ForEach-Object {
    Write-Host "  $($_.FullName.Replace($packagePath, ''))"
}

Write-Host "`nPackage ready: $zipPath" -ForegroundColor Green
Write-Host "Size: $([math]::Round((Get-Item $zipPath).Length / 1KB, 2)) KB"

Usage:

.\CreateModulePackage.ps1 -ModuleName "CursorWrap" -Configuration Release -Platform x64

FAQ

Q: Can I share just ModuleLoader.exe and the module DLL?

A: Yes, but the recipient must have PowerToys installed (or manually create the settings file).

Q: Does the tester need PowerToys installed?

A: No, if you provide the complete package with settings. ModuleLoader is fully standalone.

Q: What if settings.json doesn't exist?

A: ModuleLoader will show an error. Either:

  1. Run PowerToys once with the module enabled to generate settings
  2. Manually create a minimal settings.json file
  3. Include a sample settings.json in your package

Q: Can I test modules on a virtual machine?

A: Yes! This is a great use case. Just copy the package to the VM - no PowerToys installation needed.

Q: Do I need to include PDB files?

A: Only for debugging. For normal testing, just the EXE and DLL are sufficient.

Q: Can I distribute this to end users?

A: ModuleLoader is a development/testing tool, not intended for end-user distribution. For production use, direct users to install PowerToys.


Security Considerations

When sharing module DLLs:

  1. Verify Source: Only share modules you built from trusted source code
  2. Scan for Malware: Run antivirus scans on the package before sharing
  3. HTTPS Only: Use secure channels (HTTPS, OneDrive, SharePoint) for distribution
  4. Hash Verification: Consider providing SHA256 hashes for file integrity:
    Get-FileHash ModuleLoader.exe -Algorithm SHA256
    Get-FileHash modules\CursorWrap.dll -Algorithm SHA256
    

Example Package (CursorWrap)

Here's what a complete CursorWrap testing package looks like:

ModuleLoader-CursorWrap-x64-Debug.zip (220 KB)
?
??? ModuleLoader-CursorWrap-x64-Debug\
    ??? ModuleLoader.exe (160 KB)
    ??? README.txt (2 KB)
    ??? modules\
    ?   ??? CursorWrap.dll (55 KB)
    ??? settings\
        ??? CursorWrap\
            ??? settings.json (3 KB)

Total package size: ~220 KB (compressed)


Support

For issues with ModuleLoader, see:


License

ModuleLoader is part of PowerToys and is licensed under the MIT License. See the LICENSE file in the PowerToys repository root for details.