Implement restart as non elevated and get last updated state

This commit is contained in:
Noraa Junker
2026-02-12 02:02:28 +01:00
parent b1bfa4bdc6
commit 7e7a9d23b8
13 changed files with 162 additions and 15 deletions

View File

@@ -6,6 +6,7 @@ using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using static RunnerV2.NativeMethods;
namespace RunnerV2.Helpers
@@ -31,17 +32,22 @@ namespace RunnerV2.Helpers
case RestartScheduledMode.None:
return;
case RestartScheduledMode.RestartElevated:
RestartAsAdministrator("--restartedElevated");
RestartAsAdministrator("--restartedElevated --restarted");
break;
case RestartScheduledMode.RestartElevatedWithOpenSettings:
RestartAsAdministrator("--restartedElevated --open-settings");
RestartAsAdministrator("--restartedElevated --open-settings --restarted");
break;
case RestartScheduledMode.RestartNonElevated:
// Todo: restart unelevated
RestartAsNonElevated("--restarted --open-settings");
break;
}
}
private static void RestartAsNonElevated(string arguments)
{
PowerToys.Interop.Elevation.RunNonElevated(Environment.ProcessPath, arguments);
}
private static void RestartAsAdministrator(string arguments)
{
Logger.LogInfo("Restarting as administrator, because it was scheudled.");
@@ -62,6 +68,8 @@ namespace RunnerV2.Helpers
{
Logger.LogError("Failed to restart as administrator.", ex);
}
Environment.Exit(0);
}
internal static bool IsProcessElevated(bool useCachedValue = true)

View File

@@ -119,13 +119,18 @@ namespace RunnerV2.Helpers
Runner.Close();
break;
case "restart_maintain_elevation":
// Todo:
ElevationHelper.RestartScheduled = ElevationHelper.IsProcessElevated() ? ElevationHelper.RestartScheduledMode.RestartElevatedWithOpenSettings : ElevationHelper.RestartScheduledMode.RestartNonElevated;
ElevationHelper.RestartIfScheudled();
break;
case "check_for_updates":
UpdateSettingsHelper.TriggerUpdateCheck();
break;
case "request_update_state_date":
// Todo:
JsonObject response = [];
response["updateStateDate"] = UpdateSettingsHelper.GetLastCheckedDate();
_ipc?.Send(response.ToJsonString());
break;
}

View File

@@ -5,6 +5,7 @@
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using ManagedCommon;
using RunnerV2.Helpers;
@@ -61,6 +62,11 @@ namespace RunnerV2.Models
/// Sets the launched process to realtime priority.
/// </summary>
RealtimePriority = 128,
/// <summary>
/// Indicates that the process should never be launched with elevated privileges, even if the runner process is elevated.
/// </summary>
NeverElevate = 256,
}
/// <summary>
@@ -126,6 +132,12 @@ namespace RunnerV2.Models
string arguments = (LaunchOptions.HasFlag(ProcessLaunchOptions.RunnerProcessIdAsFirstArgument) ? Environment.ProcessId.ToString(CultureInfo.InvariantCulture) + (string.IsNullOrEmpty(ProcessArguments) ? string.Empty : " ") : string.Empty) + ProcessArguments;
if (ElevationHelper.IsProcessElevated() && LaunchOptions.HasFlag(ProcessLaunchOptions.NeverElevate))
{
PowerToys.Interop.Elevation.RunNonElevated(Path.GetFullPath(ProcessPath), arguments);
return;
}
Process? p = Process.Start(new ProcessStartInfo()
{
UseShellExecute = LaunchOptions.HasFlag(ProcessLaunchOptions.UseShellExecute),

View File

@@ -38,7 +38,7 @@ namespace RunnerV2.ModuleInterfaces
public override string ProcessName => "PowerToys.Peek.UI";
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.RunnerProcessIdAsFirstArgument | ProcessLaunchOptions.SingletonProcess;
public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.RunnerProcessIdAsFirstArgument | ProcessLaunchOptions.SingletonProcess | (SettingsUtils.Default.GetSettings<PeekSettings>(Name).Properties.AlwaysRunNotElevated.Value ? ProcessLaunchOptions.NeverElevate : 0);
public List<(HotkeySettings Hotkey, Action Action)> Shortcuts { get; } = [];

View File

@@ -56,11 +56,14 @@ internal sealed class Program
throw new NotImplementedException("Special modes are not implemented yet.");
}
// If PowerToys restarted the old process may still be around
bool hasRestartedArgment = args.Contains("--restarted");
bool shouldOpenSettings = args.Any(s => s.StartsWith("--open-settings", StringComparison.InvariantCulture));
bool shouldOpenSettingsToSpecificPage = args.Any(s => s.StartsWith("--open-settings=", StringComparison.InvariantCulture));
// Check if PowerToys is already running
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 1)
if ((!hasRestartedArgment && Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 1) || Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 2)
{
IntPtr hwndMain = NativeMethods.FindWindowW(Runner.TrayWindowClassName, null!);
NativeMethods.PostMessageW(hwndMain, 0x0111, 1, IntPtr.Zero);
@@ -74,7 +77,16 @@ internal sealed class Program
bool isElevated = ElevationHelper.IsProcessElevated();
bool hasDontElevateArgument = args.Contains("--dont-elevate");
bool runElevatedSetting = GeneralSettings.RunElevated;
bool runElevatedSetting = false;
try
{
runElevatedSetting = GeneralSettings.RunElevated;
}
catch
{
Logger.LogError("Could not retrieve run elevated setting");
}
bool hasRestartedElevatedArgment = args.Contains("--restartedElevated");
Action afterInitializationAction = () => { };
@@ -112,8 +124,8 @@ internal sealed class Program
switch ((isElevated, hasDontElevateArgument, runElevatedSetting, hasRestartedElevatedArgment))
{
case (true, true, false, _):
// Todo: Scheudle restart as non elevated
throw new NotImplementedException();
ElevationHelper.RestartScheduled = ElevationHelper.RestartScheduledMode.RestartNonElevated;
break;
case (true, _, _, _):
case (_, _, false, _):
case (_, true, _, _):

View File

@@ -135,7 +135,14 @@ namespace RunnerV2
while (GetMessageW(out MSG msg, IntPtr.Zero, 0, 0) != 0 || true)
{
TranslateMessage(ref msg);
DispatchMessageW(ref msg);
try
{
DispatchMessageW(ref msg);
}
catch (Exception e)
{
Logger.LogError("Uncaught error in message loop: ", e);
}
// Supress duplicate handling of HOTKEY messages
if (msg.Message == (uint)WindowMessages.HOTKEY)
@@ -196,8 +203,6 @@ namespace RunnerV2
{
if ((module.Enabled && (module.GpoRuleConfigured != PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)) || module.GpoRuleConfigured == PowerToys.GPOWrapper.GpoRuleConfigured.Enabled)
{
/* Todo: conflict manager */
if (!LoadedModules.Contains(module))
{
module.Enable();

View File

@@ -51,6 +51,18 @@ namespace Update
_updateThread.Start();
}
public static string GetLastCheckedDate()
{
UpdatingSettings updatingSettings = UpdatingSettings.LoadSettings();
if (long.TryParse(updatingSettings.LastCheckedDate, out long lastCheckedDateSeconds))
{
DateTimeOffset lastCheckedDate = DateTimeOffset.FromUnixTimeSeconds(lastCheckedDateSeconds);
return lastCheckedDate.ToString("g", CultureInfo.CurrentCulture);
}
return string.Empty;
}
internal record UpdateInfo
{
private UpdateInfo()

View File

@@ -0,0 +1,14 @@
#include "pch.h"
#define SUPRESS_LOGGER
#include "../utils/elevation.h"
#include "Elevation.h"
#include "Elevation.g.cpp"
namespace winrt::PowerToys::Interop::implementation
{
void Elevation::RunNonElevated(const winrt::hstring& file, const winrt::hstring& params)
{
RunNonElevatedFailsafe((std::wstring)file, params.c_str(), get_module_folderpath());
}
}

View File

@@ -0,0 +1,17 @@
#pragma once
#include "Elevation.g.h"
namespace winrt::PowerToys::Interop::implementation
{
struct Elevation : ElevationT<Elevation>
{
static void RunNonElevated(const winrt::hstring& file, const winrt::hstring& params);
};
}
namespace winrt::PowerToys::Interop::factory_implementation
{
struct Elevation : ElevationT<Elevation, implementation::Elevation>
{
};
}

View File

@@ -0,0 +1,12 @@
namespace PowerToys
{
namespace Interop
{
[default_interface] runtimeclass Elevation
{
static void RunNonElevated(String file, String params);
}
}
}

View File

@@ -41,7 +41,6 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
@@ -101,6 +100,7 @@
<ClInclude Include="Constants.h">
<DependentUpon>KeyboardListener.idl</DependentUpon>
</ClInclude>
<ClInclude Include="Elevation.h" />
<ClInclude Include="HotkeyManager.h">
<DependentUpon>HotkeyManager.idl</DependentUpon>
</ClInclude>
@@ -131,6 +131,7 @@
<ClCompile Include="Constants.cpp">
<DependentUpon>KeyboardListener.idl</DependentUpon>
</ClCompile>
<ClCompile Include="Elevation.cpp" />
<ClCompile Include="HotkeyManager.cpp">
<DependentUpon>HotkeyManager.idl</DependentUpon>
</ClCompile>
@@ -168,6 +169,7 @@
<Midl Include="Clipboard.idl" />
<Midl Include="CommonManaged.idl" />
<Midl Include="Constants.idl" />
<Midl Include="Elevation.idl" />
<Midl Include="HotkeyManager.idl" />
<Midl Include="KeyboardHook.idl" />
<Midl Include="LayoutMapManaged.idl" />
@@ -175,6 +177,11 @@
<Midl Include="ThemeHelper.idl" />
<Midl Include="TwoWayPipeMessageIPCManaged.idl" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\logger\logger.vcxproj">
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
</ProjectReference>
</ItemGroup>
<ImportGroup Label="ExtensionTargets" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@@ -63,6 +63,9 @@
<ClInclude Include="Clipboard.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Elevation.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="keyboard_layout.cpp">
@@ -101,6 +104,9 @@
<ClCompile Include="Clipboard.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Elevation.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="interop.rc">
@@ -142,6 +148,9 @@
<Midl Include="Clipboard.idl">
<Filter>Source Files</Filter>
</Midl>
<Midl Include="Elevation.idl">
<Filter>Source Files</Filter>
</Midl>
</ItemGroup>
<ItemGroup>
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />

View File

@@ -17,11 +17,45 @@
#include <string>
#include <filesystem>
#ifndef SUPRESS_LOGGER
#include <common/logger/logger.h>
#endif // SUPRESS_LOGGER
#include <common/utils/winapi_error.h>
#include <common/utils/process_path.h>
#include <common/utils/processApi.h>
#ifdef SUPRESS_LOGGER
class Logger
{
public:
template<typename FormatString, typename... Args>
static void trace(const FormatString&, const Args&...)
{
}
template<typename FormatString, typename... Args>
static void debug(const FormatString&, const Args&...)
{
}
template<typename FormatString, typename... Args>
static void info(const FormatString&, const Args&...)
{
}
template<typename FormatString, typename... Args>
static void warn(const FormatString&, const Args&...)
{
}
template<typename FormatString, typename... Args>
static void error(const FormatString&, const Args&...)
{
}
template<typename FormatString, typename... Args>
static void critical(const FormatString&, const Args&...)
{
}
};
#endif // SUPRESS_LOGGER
namespace
{
inline std::wstring GetErrorString(HRESULT handle)
@@ -406,7 +440,7 @@ inline std::optional<ProcessInfo> RunNonElevatedFailsafe(const std::wstring& fil
{
Logger::warn(L"RunNonElevatedEx() failed. Trying fallback");
std::wstring action_runner_path = get_module_folderpath() + L"\\PowerToys.ActionRunner.exe";
std::wstring newParams = fmt::format(L"-run-non-elevated -target \"{}\" {}", file, params);
std::wstring newParams = std::format(L"-run-non-elevated -target \"{}\" {}", file, params);
launched = run_non_elevated(action_runner_path, newParams, nullptr, working_dir.c_str());
if (launched)
{