mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 11:48:06 +01:00
first round review, and rollback many to main branch status
This commit is contained in:
@@ -58,9 +58,6 @@
|
|||||||
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.Ollama" Version="1.66.0-alpha" />
|
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.Ollama" Version="1.66.0-alpha" />
|
||||||
<PackageVersion Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
|
<PackageVersion Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
|
||||||
<PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.3179.45" />
|
<PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.3179.45" />
|
||||||
<PackageVersion Include="Microsoft.CommandPalette.Extensions" Version="0.5.250829002" />
|
|
||||||
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools.MSIX" Version="1.7.20250829.1" />
|
|
||||||
<PackageVersion Include="Shmuelie.WinRTServer" Version="2.1.1" />
|
|
||||||
<!-- Package Microsoft.Win32.SystemEvents added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Drawing.Common but the 8.0.1 version wasn't published to nuget. -->
|
<!-- Package Microsoft.Win32.SystemEvents added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Drawing.Common but the 8.0.1 version wasn't published to nuget. -->
|
||||||
<PackageVersion Include="Microsoft.Win32.SystemEvents" Version="9.0.10" />
|
<PackageVersion Include="Microsoft.Win32.SystemEvents" Version="9.0.10" />
|
||||||
<PackageVersion Include="Microsoft.WindowsPackageManager.ComInterop" Version="1.10.340" />
|
<PackageVersion Include="Microsoft.WindowsPackageManager.ComInterop" Version="1.10.340" />
|
||||||
@@ -72,7 +69,7 @@
|
|||||||
This is present due to a bug in CsWinRT where WPF projects cause the analyzer to fail.
|
This is present due to a bug in CsWinRT where WPF projects cause the analyzer to fail.
|
||||||
-->
|
-->
|
||||||
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
|
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
|
||||||
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4948" />
|
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.6901" />
|
||||||
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.8.250907003" />
|
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.8.250907003" />
|
||||||
<PackageVersion Include="Microsoft.WindowsAppSDK.AI" Version="1.8.37" />
|
<PackageVersion Include="Microsoft.WindowsAppSDK.AI" Version="1.8.37" />
|
||||||
<PackageVersion Include="Microsoft.WindowsAppSDK.Runtime" Version="1.8.250907003" />
|
<PackageVersion Include="Microsoft.WindowsAppSDK.Runtime" Version="1.8.250907003" />
|
||||||
|
|||||||
2305
PowerToys.sln
2305
PowerToys.sln
File diff suppressed because it is too large
Load Diff
@@ -6,12 +6,11 @@
|
|||||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||||
xmlns:uap2="http://schemas.microsoft.com/appx/manifest/uap/windows10/2"
|
xmlns:uap2="http://schemas.microsoft.com/appx/manifest/uap/windows10/2"
|
||||||
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
|
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
|
||||||
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
|
|
||||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||||
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||||
xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
|
xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
|
||||||
xmlns:systemai="http://schemas.microsoft.com/appx/manifest/systemai/windows10"
|
xmlns:systemai="http://schemas.microsoft.com/appx/manifest/systemai/windows10"
|
||||||
IgnorableNamespaces="uap uap2 uap3 com rescap desktop uap10 systemai">
|
IgnorableNamespaces="uap uap2 uap3 rescap desktop uap10 systemai">
|
||||||
<Identity
|
<Identity
|
||||||
Name="Microsoft.PowerToys.SparseApp"
|
Name="Microsoft.PowerToys.SparseApp"
|
||||||
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
|
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
|
||||||
@@ -67,51 +66,5 @@
|
|||||||
AppListEntry="none">
|
AppListEntry="none">
|
||||||
</uap:VisualElements>
|
</uap:VisualElements>
|
||||||
</Application>
|
</Application>
|
||||||
<!-- Temporarily disabled: PowerToys Command Palette Extension now packaged with its own manifest -->
|
|
||||||
<!--
|
|
||||||
<Application Id="CmdPalExt.PowerToys"
|
|
||||||
Executable="WinUI3Apps\CmdPalExtensions\Microsoft.CmdPal.Ext.PowerToys\Microsoft.CmdPal.Ext.PowerToys.exe"
|
|
||||||
EntryPoint="Windows.FullTrustApplication">
|
|
||||||
<uap:VisualElements
|
|
||||||
DisplayName="PowerToys Command Palette Extension"
|
|
||||||
Description="Expose PowerToys commands to Windows Command Palette"
|
|
||||||
BackgroundColor="transparent"
|
|
||||||
Square150x150Logo="Images\Square150x150Logo.png"
|
|
||||||
Square44x44Logo="Images\Square44x44Logo.png">
|
|
||||||
<uap:DefaultTile Wide310x150Logo="Images\Square150x150Logo.png" />
|
|
||||||
</uap:VisualElements>
|
|
||||||
<Extensions>
|
|
||||||
<com:Extension Category="windows.comServer">
|
|
||||||
<com:ComServer>
|
|
||||||
<com:ExeServer Executable="WinUI3Apps\CmdPalExtensions\Microsoft.CmdPal.Ext.PowerToys\Microsoft.CmdPal.Ext.PowerToys.exe"
|
|
||||||
Arguments="-RegisterProcessAsComServer"
|
|
||||||
DisplayName="PowerToys Command Palette Extension">
|
|
||||||
<com:Class Id="3D0F0E1F-6F0C-4D5C-91C0-5C4A4B1A5D55"
|
|
||||||
DisplayName="PowerToys Command Palette Extension" />
|
|
||||||
</com:ExeServer>
|
|
||||||
</com:ComServer>
|
|
||||||
</com:Extension>
|
|
||||||
<uap3:Extension Category="windows.appExtension">
|
|
||||||
<uap3:AppExtension Name="com.microsoft.commandpalette"
|
|
||||||
Id="PowerToys"
|
|
||||||
PublicFolder="WinUI3Apps\CmdPalExtensions\Microsoft.CmdPal.Ext.PowerToys\Public"
|
|
||||||
DisplayName="PowerToys"
|
|
||||||
Description="Surface PowerToys commands inside Command Palette">
|
|
||||||
<uap3:Properties>
|
|
||||||
<CmdPalProvider xmlns="http://schemas.microsoft.com/commandpalette/2024/extension">
|
|
||||||
<Metadata DisplayName="PowerToys" Description="Built-in PowerToys commands." />
|
|
||||||
<Activation>
|
|
||||||
<CreateInstance ClassId="3D0F0E1F-6F0C-4D5C-91C0-5C4A4B1A5D55" />
|
|
||||||
</Activation>
|
|
||||||
<SupportedInterfaces>
|
|
||||||
<Commands />
|
|
||||||
</SupportedInterfaces>
|
|
||||||
</CmdPalProvider>
|
|
||||||
</uap3:Properties>
|
|
||||||
</uap3:AppExtension>
|
|
||||||
</uap3:Extension>
|
|
||||||
</Extensions>
|
|
||||||
</Application>
|
|
||||||
-->
|
|
||||||
</Applications>
|
</Applications>
|
||||||
</Package>
|
</Package>
|
||||||
@@ -3,8 +3,6 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
|
|
||||||
#pragma comment(lib, "Shlwapi.lib")
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
|||||||
@@ -901,60 +901,6 @@ public:
|
|||||||
{
|
{
|
||||||
return m_enabled;
|
return m_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::wstring describe() override
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
auto baseDescription = PowertoyModuleIface::describe();
|
|
||||||
auto descriptionObject = winrt::Windows::Data::Json::JsonObject::Parse(winrt::hstring(baseDescription));
|
|
||||||
auto methodsArray = descriptionObject.GetNamedArray(L"methods");
|
|
||||||
|
|
||||||
winrt::Windows::Data::Json::JsonObject launchMethod;
|
|
||||||
launchMethod.SetNamedValue(L"name", winrt::Windows::Data::Json::JsonValue::CreateStringValue(L"launch"));
|
|
||||||
launchMethod.SetNamedValue(L"description", winrt::Windows::Data::Json::JsonValue::CreateStringValue(L"Open Advanced Paste UI"));
|
|
||||||
methodsArray.Append(launchMethod);
|
|
||||||
|
|
||||||
return descriptionObject.Stringify().c_str();
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
return PowertoyModuleIface::describe();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual std::wstring invoke(const wchar_t* method, const wchar_t* jsonParams) override
|
|
||||||
{
|
|
||||||
if (method != nullptr && wcscmp(method, L"launch") == 0)
|
|
||||||
{
|
|
||||||
if (!is_enabled())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
enable();
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
return L"{\"ok\":false,\"error\":\"EnableFailed\"}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_process_manager.start();
|
|
||||||
m_process_manager.bring_to_front();
|
|
||||||
m_process_manager.send_message(CommonSharedConstants::ADVANCED_PASTE_SHOW_UI_MESSAGE);
|
|
||||||
Trace::AdvancedPaste_Invoked(L"AdvancedPasteUI");
|
|
||||||
return L"{\"ok\":true}";
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
return L"{\"ok\":false,\"error\":\"LaunchFailed\"}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return PowertoyModuleIface::invoke(method, jsonParams);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" />
|
<ProjectReference Include="..\..\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" />
|
||||||
<ProjectReference Include="..\..\ext\Microsoft.CmdPal.Ext.Indexer\Microsoft.CmdPal.Ext.Indexer.csproj" />
|
<ProjectReference Include="..\..\ext\Microsoft.CmdPal.Ext.Indexer\Microsoft.CmdPal.Ext.Indexer.csproj" />
|
||||||
<ProjectReference Include="..\Microsoft.CmdPal.Ext.Apps\Microsoft.CmdPal.Ext.Apps.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Update="Assets\**\*.*">
|
<Content Update="Assets\**\*.*">
|
||||||
|
|||||||
@@ -1,15 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <compare>
|
#include <compare>
|
||||||
#include <filesystem>
|
|
||||||
#include <optional>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <cwchar>
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#include <common/utils/gpo.h>
|
#include <common/utils/gpo.h>
|
||||||
#include <common/utils/process_path.h>
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
DLL Interface for PowerToys. The powertoy_create() (see below) must return
|
DLL Interface for PowerToys. The powertoy_create() (see below) must return
|
||||||
@@ -45,13 +37,6 @@
|
|||||||
class PowertoyModuleIface
|
class PowertoyModuleIface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct CmdPalCommand
|
|
||||||
{
|
|
||||||
std::wstring name;
|
|
||||||
std::wstring method;
|
|
||||||
std::wstring description;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Describes a hotkey which can trigger an action in the PowerToy */
|
/* Describes a hotkey which can trigger an action in the PowerToy */
|
||||||
struct Hotkey
|
struct Hotkey
|
||||||
{
|
{
|
||||||
@@ -170,86 +155,6 @@ public:
|
|||||||
return powertoys_gpo::gpo_rule_configured_not_configured;
|
return powertoys_gpo::gpo_rule_configured_not_configured;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::wstring describe()
|
|
||||||
{
|
|
||||||
auto moduleName = std::wstring(get_name());
|
|
||||||
auto moduleKey = std::wstring(get_key());
|
|
||||||
std::wstring description = L"{\"name\":\"" + moduleKey + L"\",";
|
|
||||||
description += L"\"displayName\":\"" + moduleName + L"\",";
|
|
||||||
description += L"\"methods\":[";
|
|
||||||
description += L"{\"name\":\"navigateToSettings\",\"description\":\"Open " + moduleName + L" settings\"},";
|
|
||||||
description += L"{\"name\":\"enable\",\"description\":\"Enable the module\"},";
|
|
||||||
description += L"{\"name\":\"disable\",\"description\":\"Disable the module\"}";
|
|
||||||
description += L"]}";
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual std::wstring invoke(const wchar_t* method, const wchar_t* /*jsonParams*/)
|
|
||||||
{
|
|
||||||
if (method != nullptr && wcscmp(method, L"navigateToSettings") == 0)
|
|
||||||
{
|
|
||||||
const auto moduleKey = std::wstring(get_key());
|
|
||||||
const auto exePath = get_module_folderpath() + L"\\PowerToys.exe";
|
|
||||||
if (!std::filesystem::exists(exePath))
|
|
||||||
{
|
|
||||||
return L"{\"ok\":false,\"error\":\"PowerToysExeNotFound\"}";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::wstring args = L"--open-settings=" + moduleKey;
|
|
||||||
std::wstring commandLine = L"\"" + exePath + L"\" " + args;
|
|
||||||
std::vector<wchar_t> commandLineBuffer(commandLine.begin(), commandLine.end());
|
|
||||||
commandLineBuffer.push_back(L'\0');
|
|
||||||
|
|
||||||
STARTUPINFO startupInfo{};
|
|
||||||
startupInfo.cb = sizeof(startupInfo);
|
|
||||||
PROCESS_INFORMATION processInformation{};
|
|
||||||
|
|
||||||
if (CreateProcessW(exePath.c_str(),
|
|
||||||
commandLineBuffer.data(),
|
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
FALSE,
|
|
||||||
0,
|
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
&startupInfo,
|
|
||||||
&processInformation))
|
|
||||||
{
|
|
||||||
CloseHandle(processInformation.hProcess);
|
|
||||||
CloseHandle(processInformation.hThread);
|
|
||||||
return L"{\"ok\":true}";
|
|
||||||
}
|
|
||||||
|
|
||||||
return L"{\"ok\":false,\"error\":\"LaunchFailed\"}";
|
|
||||||
}
|
|
||||||
else if (method != nullptr && wcscmp(method, L"enable") == 0)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
enable();
|
|
||||||
return L"{\"ok\":true,\"result\":{\"enabled\":true}}";
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
return L"{\"ok\":false,\"error\":\"EnableFailed\"}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (method != nullptr && wcscmp(method, L"disable") == 0)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
disable();
|
|
||||||
return L"{\"ok\":true,\"result\":{\"enabled\":false}}";
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
return L"{\"ok\":false,\"error\":\"DisableFailed\"}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return L"{\"ok\":false,\"error\":\"Method.NotFound\"}";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some actions like AdvancedPaste generate new inputs, which we don't want to catch again.
|
// Some actions like AdvancedPaste generate new inputs, which we don't want to catch again.
|
||||||
// The flag was purposefully chose to not collide with other keyboard manager flags.
|
// The flag was purposefully chose to not collide with other keyboard manager flags.
|
||||||
const static inline ULONG_PTR CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG = 0x110;
|
const static inline ULONG_PTR CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG = 0x110;
|
||||||
|
|||||||
@@ -37,7 +37,6 @@
|
|||||||
<ProjectReference Include="..\..\Wox.Plugin\Wox.Plugin.csproj">
|
<ProjectReference Include="..\..\Wox.Plugin\Wox.Plugin.csproj">
|
||||||
<Private>false</Private>
|
<Private>false</Private>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\Community.PowerToys.Run.Plugin.WebSearch\Community.PowerToys.Run.Plugin.WebSearch.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
<ProjectReference Include="..\Microsoft.Plugin.Folder\Microsoft.Plugin.Folder.csproj">
|
<ProjectReference Include="..\Microsoft.Plugin.Folder\Microsoft.Plugin.Folder.csproj">
|
||||||
<Private>false</Private>
|
<Private>false</Private>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\Microsoft.Plugin.Program.UnitTests\Microsoft.Plugin.Program.UnitTests.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,327 +0,0 @@
|
|||||||
#include "pch.h"
|
|
||||||
#include "cmdpal_rpc_server.h"
|
|
||||||
|
|
||||||
#include "powertoy_module.h"
|
|
||||||
#include <common/logger/logger.h>
|
|
||||||
|
|
||||||
using namespace winrt::Windows::Data::Json;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
constexpr wchar_t PIPE_NAME[] = LR"(\\.\pipe\PowerToys.CmdPal.Rpc)";
|
|
||||||
|
|
||||||
std::string ToUtf8(const winrt::hstring& value)
|
|
||||||
{
|
|
||||||
return winrt::to_string(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
winrt::hstring ToHString(const std::string& value)
|
|
||||||
{
|
|
||||||
return winrt::to_hstring(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CmdPalRpcServer::CmdPalRpcServer() = default;
|
|
||||||
|
|
||||||
CmdPalRpcServer::~CmdPalRpcServer()
|
|
||||||
{
|
|
||||||
Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CmdPalRpcServer::Start()
|
|
||||||
{
|
|
||||||
if (m_running.exchange(true))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_worker = std::thread([this]() { Run(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void CmdPalRpcServer::Stop()
|
|
||||||
{
|
|
||||||
if (!m_running.exchange(false))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trigger the server loop to exit by briefly connecting to the pipe.
|
|
||||||
for (int attempt = 0; attempt < 5; ++attempt)
|
|
||||||
{
|
|
||||||
auto pipe = CreateFileW(PIPE_NAME, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
|
||||||
if (pipe != INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
CloseHandle(pipe);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto error = GetLastError();
|
|
||||||
if (error == ERROR_FILE_NOT_FOUND)
|
|
||||||
{
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
||||||
}
|
|
||||||
else if (error == ERROR_PIPE_BUSY)
|
|
||||||
{
|
|
||||||
WaitNamedPipeW(PIPE_NAME, 200);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_worker.joinable())
|
|
||||||
{
|
|
||||||
m_worker.join();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CmdPalRpcServer::Run()
|
|
||||||
{
|
|
||||||
while (m_running.load())
|
|
||||||
{
|
|
||||||
HANDLE pipe = CreateNamedPipeW(PIPE_NAME,
|
|
||||||
PIPE_ACCESS_DUPLEX,
|
|
||||||
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
|
|
||||||
PIPE_UNLIMITED_INSTANCES,
|
|
||||||
64 * 1024,
|
|
||||||
64 * 1024,
|
|
||||||
0,
|
|
||||||
nullptr);
|
|
||||||
|
|
||||||
if (pipe == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
Logger::error(L"CmdPalRpcServer: failed to create pipe. Error: {}", GetLastError());
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL connected = ConnectNamedPipe(pipe, nullptr) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
|
|
||||||
if (!connected)
|
|
||||||
{
|
|
||||||
CloseHandle(pipe);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
HandleClient(pipe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CmdPalRpcServer::HandleClient(HANDLE pipe)
|
|
||||||
{
|
|
||||||
auto closePipe = wil::scope_exit([pipe]() {
|
|
||||||
FlushFileBuffers(pipe);
|
|
||||||
DisconnectNamedPipe(pipe);
|
|
||||||
CloseHandle(pipe);
|
|
||||||
});
|
|
||||||
|
|
||||||
while (m_running.load())
|
|
||||||
{
|
|
||||||
uint32_t length = 0;
|
|
||||||
DWORD bytesRead = 0;
|
|
||||||
if (!ReadFile(pipe, &length, sizeof(length), &bytesRead, nullptr) || bytesRead == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string payload;
|
|
||||||
payload.resize(length);
|
|
||||||
DWORD totalRead = 0;
|
|
||||||
while (totalRead < length)
|
|
||||||
{
|
|
||||||
DWORD chunkRead = 0;
|
|
||||||
if (!ReadFile(pipe, payload.data() + totalRead, length - totalRead, &chunkRead, nullptr) || chunkRead == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
totalRead += chunkRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto response = ProcessMessage(payload);
|
|
||||||
uint32_t responseLength = static_cast<uint32_t>(response.size());
|
|
||||||
DWORD bytesWritten = 0;
|
|
||||||
if (!WriteFile(pipe, &responseLength, sizeof(responseLength), &bytesWritten, nullptr))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (responseLength > 0)
|
|
||||||
{
|
|
||||||
DWORD totalWritten = 0;
|
|
||||||
while (totalWritten < responseLength)
|
|
||||||
{
|
|
||||||
DWORD chunkWritten = 0;
|
|
||||||
if (!WriteFile(pipe, response.data() + totalWritten, responseLength - totalWritten, &chunkWritten, nullptr))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
totalWritten += chunkWritten;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string CmdPalRpcServer::ProcessMessage(const std::string& message)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
auto request = JsonObject::Parse(ToHString(message));
|
|
||||||
std::wstring id;
|
|
||||||
if (auto idValue = request.TryLookup(L"id"))
|
|
||||||
{
|
|
||||||
if (idValue.ValueType() == JsonValueType::String)
|
|
||||||
{
|
|
||||||
id = idValue.GetString().c_str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!request.HasKey(L"module") || !request.HasKey(L"method"))
|
|
||||||
{
|
|
||||||
return BuildErrorResponse(id, L"Bad.Request", L"Missing module or method");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto moduleName = request.Lookup(L"module").GetString();
|
|
||||||
auto methodName = request.Lookup(L"method").GetString();
|
|
||||||
|
|
||||||
if (moduleName == L"core" && methodName == L"listModules")
|
|
||||||
{
|
|
||||||
return ListModulesResponse(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ProcessModuleRequest(request, id);
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
return BuildErrorResponse(L"", L"Bad.Request", L"Malformed JSON");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string CmdPalRpcServer::ProcessModuleRequest(const JsonObject& request, const std::wstring& id)
|
|
||||||
{
|
|
||||||
std::wstring moduleKey = request.Lookup(L"module").GetString().c_str();
|
|
||||||
auto methodName = request.Lookup(L"method").GetString();
|
|
||||||
|
|
||||||
auto& loadedModules = modules();
|
|
||||||
auto moduleIt = loadedModules.find(moduleKey);
|
|
||||||
if (moduleIt == loadedModules.end())
|
|
||||||
{
|
|
||||||
return BuildErrorResponse(id, L"Module.NotFound", L"Requested module is not available");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::wstring params = L"{}";
|
|
||||||
if (auto paramsValue = request.TryLookup(L"params"))
|
|
||||||
{
|
|
||||||
params = paramsValue.Stringify().c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto start = std::chrono::steady_clock::now();
|
|
||||||
std::wstring moduleResponse;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
moduleResponse = moduleIt->second->invoke(methodName.c_str(), params.c_str());
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
return BuildErrorResponse(id, L"Module.Failure", L"Module threw an exception");
|
|
||||||
}
|
|
||||||
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count();
|
|
||||||
|
|
||||||
JsonObject response;
|
|
||||||
if (!id.empty())
|
|
||||||
{
|
|
||||||
response.SetNamedValue(L"id", JsonValue::CreateStringValue(id));
|
|
||||||
}
|
|
||||||
response.SetNamedValue(L"elapsedMs", JsonValue::CreateNumberValue(static_cast<double>(elapsed)));
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
auto moduleJsonValue = JsonValue::Parse(winrt::hstring(moduleResponse.c_str()));
|
|
||||||
bool ok = true;
|
|
||||||
if (moduleJsonValue.ValueType() == JsonValueType::Object)
|
|
||||||
{
|
|
||||||
auto moduleObject = moduleJsonValue.GetObject();
|
|
||||||
if (moduleObject.HasKey(L"ok"))
|
|
||||||
{
|
|
||||||
ok = moduleObject.GetNamedBoolean(L"ok");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
response.SetNamedValue(L"ok", JsonValue::CreateBooleanValue(ok));
|
|
||||||
if (ok)
|
|
||||||
{
|
|
||||||
response.SetNamedValue(L"result", moduleJsonValue);
|
|
||||||
}
|
|
||||||
else if (moduleJsonValue.ValueType() == JsonValueType::Object)
|
|
||||||
{
|
|
||||||
auto moduleObject = moduleJsonValue.GetObject();
|
|
||||||
if (moduleObject.HasKey(L"error"))
|
|
||||||
{
|
|
||||||
response.SetNamedValue(L"error", moduleObject.Lookup(L"error"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
response.SetNamedValue(L"error", moduleJsonValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
response.SetNamedValue(L"error", moduleJsonValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ToUtf8(response.Stringify());
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
return BuildErrorResponse(id, L"Module.Failure", L"Module returned invalid JSON");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string CmdPalRpcServer::ListModulesResponse(const std::wstring& id)
|
|
||||||
{
|
|
||||||
JsonObject response;
|
|
||||||
if (!id.empty())
|
|
||||||
{
|
|
||||||
response.SetNamedValue(L"id", JsonValue::CreateStringValue(id));
|
|
||||||
}
|
|
||||||
response.SetNamedValue(L"ok", JsonValue::CreateBooleanValue(true));
|
|
||||||
|
|
||||||
JsonArray modulesArray;
|
|
||||||
for (auto& entry : modules())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
auto describeJson = JsonValue::Parse(winrt::hstring(entry.second->describe()));
|
|
||||||
if (describeJson.ValueType() == JsonValueType::Object)
|
|
||||||
{
|
|
||||||
modulesArray.Append(describeJson.GetObject());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
JsonObject fallback;
|
|
||||||
fallback.SetNamedValue(L"name", JsonValue::CreateStringValue(entry.first));
|
|
||||||
modulesArray.Append(fallback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonObject payload;
|
|
||||||
payload.SetNamedValue(L"modules", modulesArray);
|
|
||||||
response.SetNamedValue(L"result", payload);
|
|
||||||
|
|
||||||
return ToUtf8(response.Stringify());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string CmdPalRpcServer::BuildErrorResponse(const std::wstring& id, const std::wstring_view code, const std::wstring_view message)
|
|
||||||
{
|
|
||||||
JsonObject response;
|
|
||||||
if (!id.empty())
|
|
||||||
{
|
|
||||||
response.SetNamedValue(L"id", JsonValue::CreateStringValue(id));
|
|
||||||
}
|
|
||||||
response.SetNamedValue(L"ok", JsonValue::CreateBooleanValue(false));
|
|
||||||
JsonObject error;
|
|
||||||
error.SetNamedValue(L"code", JsonValue::CreateStringValue(winrt::hstring(code.data(), static_cast<uint32_t>(code.size()))));
|
|
||||||
error.SetNamedValue(L"message", JsonValue::CreateStringValue(winrt::hstring(message.data(), static_cast<uint32_t>(message.size()))));
|
|
||||||
response.SetNamedValue(L"error", error);
|
|
||||||
return ToUtf8(response.Stringify());
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <string>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include <winrt/Windows.Data.Json.h>
|
|
||||||
#include <Windows.h>
|
|
||||||
|
|
||||||
class CmdPalRpcServer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CmdPalRpcServer();
|
|
||||||
~CmdPalRpcServer();
|
|
||||||
|
|
||||||
CmdPalRpcServer(const CmdPalRpcServer&) = delete;
|
|
||||||
CmdPalRpcServer& operator=(const CmdPalRpcServer&) = delete;
|
|
||||||
|
|
||||||
void Start();
|
|
||||||
void Stop();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void Run();
|
|
||||||
void HandleClient(HANDLE pipe);
|
|
||||||
std::string ProcessMessage(const std::string& message);
|
|
||||||
std::string ProcessModuleRequest(const winrt::Windows::Data::Json::JsonObject& request, const std::wstring& id);
|
|
||||||
std::string ListModulesResponse(const std::wstring& id);
|
|
||||||
std::string BuildErrorResponse(const std::wstring& id, const std::wstring_view code, const std::wstring_view message);
|
|
||||||
|
|
||||||
std::atomic_bool m_running{ false };
|
|
||||||
std::thread m_worker;
|
|
||||||
};
|
|
||||||
@@ -36,7 +36,6 @@
|
|||||||
#include <RestartManager.h>
|
#include <RestartManager.h>
|
||||||
#include "centralized_kb_hook.h"
|
#include "centralized_kb_hook.h"
|
||||||
#include "centralized_hotkeys.h"
|
#include "centralized_hotkeys.h"
|
||||||
#include "cmdpal_rpc_server.h"
|
|
||||||
|
|
||||||
#if _DEBUG && _WIN64
|
#if _DEBUG && _WIN64
|
||||||
#include "unhandled_exception_handler.h"
|
#include "unhandled_exception_handler.h"
|
||||||
@@ -108,7 +107,6 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow
|
|||||||
start_tray_icon(isProcessElevated);
|
start_tray_icon(isProcessElevated);
|
||||||
set_tray_icon_visible(get_general_settings().showSystemTrayIcon);
|
set_tray_icon_visible(get_general_settings().showSystemTrayIcon);
|
||||||
CentralizedKeyboardHook::Start();
|
CentralizedKeyboardHook::Start();
|
||||||
CmdPalRpcServer cmdPalRpcServer;
|
|
||||||
|
|
||||||
int result = -1;
|
int result = -1;
|
||||||
try
|
try
|
||||||
@@ -211,7 +209,6 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow
|
|||||||
}
|
}
|
||||||
// Start initial powertoys
|
// Start initial powertoys
|
||||||
start_enabled_powertoys();
|
start_enabled_powertoys();
|
||||||
cmdPalRpcServer.Start();
|
|
||||||
std::wstring product_version = get_product_version();
|
std::wstring product_version = get_product_version();
|
||||||
Trace::EventLaunch(product_version, isProcessElevated);
|
Trace::EventLaunch(product_version, isProcessElevated);
|
||||||
PTSettingsHelper::save_last_version_run(product_version);
|
PTSettingsHelper::save_last_version_run(product_version);
|
||||||
|
|||||||
@@ -66,7 +66,6 @@
|
|||||||
<PrecompiledHeader Condition="'$(UsePrecompiledHeaders)' != 'false'">Create</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(UsePrecompiledHeaders)' != 'false'">Create</PrecompiledHeader>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="powertoy_module.cpp" />
|
<ClCompile Include="powertoy_module.cpp" />
|
||||||
<ClCompile Include="cmdpal_rpc_server.cpp" />
|
|
||||||
<ClCompile Include="main.cpp" />
|
<ClCompile Include="main.cpp" />
|
||||||
<ClCompile Include="restart_elevated.cpp" />
|
<ClCompile Include="restart_elevated.cpp" />
|
||||||
<ClCompile Include="centralized_kb_hook.cpp" />
|
<ClCompile Include="centralized_kb_hook.cpp" />
|
||||||
@@ -89,7 +88,6 @@
|
|||||||
<ClInclude Include="settings_telemetry.h" />
|
<ClInclude Include="settings_telemetry.h" />
|
||||||
<ClInclude Include="UpdateUtils.h" />
|
<ClInclude Include="UpdateUtils.h" />
|
||||||
<ClInclude Include="powertoy_module.h" />
|
<ClInclude Include="powertoy_module.h" />
|
||||||
<ClInclude Include="cmdpal_rpc_server.h" />
|
|
||||||
<ClInclude Include="resource.h" />
|
<ClInclude Include="resource.h" />
|
||||||
<ClInclude Include="restart_elevated.h" />
|
<ClInclude Include="restart_elevated.h" />
|
||||||
<ClInclude Include="settings_window.h" />
|
<ClInclude Include="settings_window.h" />
|
||||||
|
|||||||
Reference in New Issue
Block a user