mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-24 12:11:09 +01:00
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.
This commit is contained in:
183
tools/module_loader/src/ModuleLoader.cpp
Normal file
183
tools/module_loader/src/ModuleLoader.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
#include "ModuleLoader.h"
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
ModuleLoader::ModuleLoader()
|
||||
: m_hModule(nullptr)
|
||||
, m_module(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
ModuleLoader::~ModuleLoader()
|
||||
{
|
||||
if (m_module)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_module->destroy();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Ignore exceptions during cleanup
|
||||
}
|
||||
m_module = nullptr;
|
||||
}
|
||||
|
||||
if (m_hModule)
|
||||
{
|
||||
FreeLibrary(m_hModule);
|
||||
m_hModule = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool ModuleLoader::Load(const std::wstring& dllPath)
|
||||
{
|
||||
if (m_hModule || m_module)
|
||||
{
|
||||
std::wcerr << L"Error: Module already loaded\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_dllPath = dllPath;
|
||||
|
||||
// Load the DLL
|
||||
m_hModule = LoadLibraryW(dllPath.c_str());
|
||||
if (!m_hModule)
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
std::wcerr << L"Error: Failed to load DLL. Error code: " << error << L"\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the powertoy_create function
|
||||
using powertoy_create_func = PowertoyModuleIface* (*)();
|
||||
auto create_func = reinterpret_cast<powertoy_create_func>(
|
||||
GetProcAddress(m_hModule, "powertoy_create"));
|
||||
|
||||
if (!create_func)
|
||||
{
|
||||
std::wcerr << L"Error: DLL does not export 'powertoy_create' function\n";
|
||||
FreeLibrary(m_hModule);
|
||||
m_hModule = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the module instance
|
||||
m_module = create_func();
|
||||
if (!m_module)
|
||||
{
|
||||
std::wcerr << L"Error: powertoy_create() returned nullptr\n";
|
||||
FreeLibrary(m_hModule);
|
||||
m_hModule = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::wcout << L"Module instance created successfully\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
void ModuleLoader::Enable()
|
||||
{
|
||||
if (!m_module)
|
||||
{
|
||||
throw std::runtime_error("Module not loaded");
|
||||
}
|
||||
|
||||
m_module->enable();
|
||||
}
|
||||
|
||||
void ModuleLoader::Disable()
|
||||
{
|
||||
if (!m_module)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_module->disable();
|
||||
}
|
||||
|
||||
bool ModuleLoader::IsEnabled() const
|
||||
{
|
||||
if (!m_module)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_module->is_enabled();
|
||||
}
|
||||
|
||||
void ModuleLoader::SetConfig(const std::wstring& configJson)
|
||||
{
|
||||
if (!m_module)
|
||||
{
|
||||
throw std::runtime_error("Module not loaded");
|
||||
}
|
||||
|
||||
m_module->set_config(configJson.c_str());
|
||||
}
|
||||
|
||||
std::wstring ModuleLoader::GetModuleName() const
|
||||
{
|
||||
if (!m_module)
|
||||
{
|
||||
return L"<not loaded>";
|
||||
}
|
||||
|
||||
const wchar_t* name = m_module->get_name();
|
||||
return name ? name : L"<unknown>";
|
||||
}
|
||||
|
||||
std::wstring ModuleLoader::GetModuleKey() const
|
||||
{
|
||||
if (!m_module)
|
||||
{
|
||||
return L"<not loaded>";
|
||||
}
|
||||
|
||||
const wchar_t* key = m_module->get_key();
|
||||
return key ? key : L"<unknown>";
|
||||
}
|
||||
|
||||
size_t ModuleLoader::GetHotkeys(PowertoyModuleIface::Hotkey* buffer, size_t bufferSize)
|
||||
{
|
||||
if (!m_module)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m_module->get_hotkeys(buffer, bufferSize);
|
||||
}
|
||||
|
||||
bool ModuleLoader::OnHotkey(size_t hotkeyId)
|
||||
{
|
||||
if (!m_module)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_module->on_hotkey(hotkeyId);
|
||||
}
|
||||
|
||||
std::optional<PowertoyModuleIface::HotkeyEx> ModuleLoader::GetHotkeyEx()
|
||||
{
|
||||
if (!m_module)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return m_module->GetHotkeyEx();
|
||||
}
|
||||
|
||||
void ModuleLoader::OnHotkeyEx()
|
||||
{
|
||||
if (!m_module)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_module->OnHotkeyEx();
|
||||
}
|
||||
Reference in New Issue
Block a user