Add some documentation

This commit is contained in:
Noraa Junker
2025-12-11 18:15:07 +01:00
parent 123d318d6a
commit 5398c16456
7 changed files with 99 additions and 31 deletions

View File

@@ -72,7 +72,13 @@ namespace RunnerV2.Helpers
return [.. matchedFiles];
}
internal static bool RegisterPackage(string packagePath, string[] dependencies)
/// <summary>
/// Installs the specified appx package along with its dependencies.
/// </summary>
/// <param name="packagePath">Path to the package</param>
/// <param name="dependencies">Array of dependency package paths</param>
/// <returns>True if the installation was successful, false otherwise</returns>
internal static bool InstallPackage(string packagePath, string[] dependencies)
{
Logger.LogInfo("Starting package install of package \"" + packagePath + "\"");
PackageManager packageManager = new();
@@ -129,6 +135,11 @@ namespace RunnerV2.Helpers
return false;
}
/// <summary>
/// Checks if the package specified by the given path is already installed and satisfies the required version.
/// </summary>
/// <param name="packagePath">Path to the package.</param>
/// <returns>True if the package is already installed and satisfies the required version, false otherwise.</returns>
private static bool IsPackageSatisfied(string packagePath)
{
if (!GetPackageNameAndVersionFromAppx(packagePath, out string name, out PackageVersion version))
@@ -153,6 +164,13 @@ namespace RunnerV2.Helpers
return false;
}
/// <summary>
/// Gets the package name and version from the specified appx package file.
/// </summary>
/// <param name="packagePath">Path to the package file.</param>
/// <param name="name">Output parameter for the package name.</param>
/// <param name="packageVersion">Output parameter for the package version.</param>
/// <returns>True if the package name and version were successfully retrieved, false otherwise.</returns>
private static bool GetPackageNameAndVersionFromAppx(string packagePath, out string name, out PackageVersion packageVersion)
{
// Todo: Implement this without interop if possible

View File

@@ -10,16 +10,17 @@ using System.IO;
using System.IO.Pipelines;
using System.Linq;
using System.Text.Json;
using System.Threading;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using PowerToys.Interop;
using RunnerV2.ModuleInterfaces;
using Update;
using Windows.Media.Devices;
namespace RunnerV2.Helpers
{
/// <summary>
/// This class provides helper methods to interact with the PowerToys Settings window.
/// </summary>
internal static class SettingsHelper
{
private static readonly SettingsUtils _settingsUtils = new();

View File

@@ -59,7 +59,7 @@ namespace RunnerV2.ModuleInterfaces
if (msixFiles.Length > 0)
{
if (!PackageHelper.RegisterPackage(msixFiles[0], dependencies))
if (!PackageHelper.InstallPackage(msixFiles[0], dependencies))
{
Logger.LogError("Failed to register Command Palette package.");
}

View File

@@ -15,6 +15,9 @@ using RunnerV2.Helpers;
namespace RunnerV2.ModuleInterfaces
{
/// <summary>
/// Base abstract class for modules that launch and manage external processes.
/// </summary>
internal abstract class ProcessModuleAbstractClass
{
/// <summary>
@@ -55,14 +58,36 @@ namespace RunnerV2.ModuleInterfaces
NeverExit = 32,
}
/// <summary>
/// Gets the relative or absolute path to the process executable.
/// </summary>
public abstract string ProcessPath { get; }
/// <summary>
/// Gets the name of the process without the .exe extension.
/// </summary>
/// <remarks>
/// Has no effect if the <see cref="LaunchOptions"/> has the <see cref="ProcessLaunchOptions.UseShellExecute"/> flag set.
/// </remarks>
public abstract string ProcessName { get; }
/// <summary>
/// Gets the arguments to pass to the process on launch.
/// </summary>
/// <remarks>
/// If not overridden, no arguments are passed.
/// If the <see cref="LaunchOptions"/> has the <see cref="ProcessLaunchOptions.RunnerProcessIdAsFirstArgument"/> flag is set, the runner process ID is prepended to these arguments.
/// </remarks>
public virtual string ProcessArguments { get; } = string.Empty;
/// <summary>
/// Gets the options used to configure how the process is launched.
/// </summary>
public abstract ProcessLaunchOptions LaunchOptions { get; }
/// <summary>
/// Ensures that atleast one process is launched. If the process is already running, does nothing.
/// </summary>
public void EnsureLaunched()
{
Process[] processes = Process.GetProcessesByName(ProcessName);
@@ -74,6 +99,10 @@ namespace RunnerV2.ModuleInterfaces
LaunchProcess();
}
/// <summary>
/// Launches the process with the specified options.
/// </summary>
/// <param name="isModuleEnableProcess">Specifies if the <see cref="Runner"/> class is currently calling this function as part of a module startup</param>
public void LaunchProcess(bool isModuleEnableProcess = false)
{
if (isModuleEnableProcess && LaunchOptions.HasFlag(ProcessLaunchOptions.SupressLaunchOnModuleEnabled))
@@ -101,14 +130,20 @@ namespace RunnerV2.ModuleInterfaces
});
}
public void ProcessExit(int msDelay = 500)
/// <summary>
/// Schedules all processes with the specified <see cref="ProcessName"/>.
/// </summary>
/// <remarks>
/// If the <see cref="LaunchOptions"/> has the <see cref="ProcessLaunchOptions.NeverExit"/> flag set, this function does nothing.
/// </remarks>
public void ProcessExit()
{
if (LaunchOptions.HasFlag(ProcessLaunchOptions.NeverExit))
{
return;
}
ProcessHelper.ScheudleProcessKill(ProcessName, msDelay);
ProcessHelper.ScheudleProcessKill(ProcessName);
}
}
}

View File

@@ -190,11 +190,6 @@ namespace RunnerV2
public string LpszClassName;
}
[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
internal delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("Advapi32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool ConvertStringSecurityDescriptorToSecurityDescriptorW(
@@ -233,22 +228,6 @@ namespace RunnerV2
[DllImport("user32.dll")]
internal static extern uint SendInput(uint nInputs, NativeKeyboardHelper.INPUT[] pInputs, int cbSize);
public const int COINIT_MULTITHREADED = 0x0;
[LibraryImport("ole32.dll")]
public static partial int CoInitializeEx(IntPtr pvReserved, int dwCoInit);
[LibraryImport("ole32.dll")]
public static partial void CoUninitialize();
[DllImport("Shlwapi.dll")]
public static extern IntPtr SHCreateStreamOnFileEx(
[MarshalAs(UnmanagedType.LPWStr)] string pszFile,
uint grfMode,
[MarshalAs(UnmanagedType.Bool)]bool fCreate,
IntPtr pstmTemplate,
out IStream stream);
[DllImport("PowerToys.Interop.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern bool GetPackageNameAndVersionFromAppx(
[MarshalAs(UnmanagedType.LPWStr)] string appxPath,

View File

@@ -111,7 +111,7 @@ internal sealed class Program
tempGeneralSettings.IsElevated = isElevated;
_settingsUtils.SaveSettings(tempGeneralSettings.ToJsonString());
_ = Runner.Run(afterInitializationAction);
Runner.Run(afterInitializationAction);
break;
default:
ElevationHelper.RestartScheduled = ElevationHelper.RestartScheduledMode.RestartElevated;
@@ -121,6 +121,11 @@ internal sealed class Program
ElevationHelper.RestartIfScheudled();
}
/// <summary>
/// Returns whether the application should run in a special mode based on the provided arguments.
/// </summary>
/// <param name="args">The arguments passed to <see cref="Main(string[])"/></param>
/// <returns>The <see cref="SpecialMode"/> the app should run in.</returns>
private static SpecialMode ShouldRunInSpecialMode(string[] args)
{
if (args.Length > 0 && args[0].StartsWith("powertoys://", StringComparison.InvariantCultureIgnoreCase))
@@ -137,6 +142,9 @@ internal sealed class Program
return SpecialMode.None;
}
/// <summary>
/// Starts the update process for PowerToys.
/// </summary>
private static void UpdateNow()
{
Process.Start(new ProcessStartInfo()

View File

@@ -27,12 +27,21 @@ namespace RunnerV2
{
internal static partial class Runner
{
/// <summary>
/// Gets the window handle for the Runner main window that hosts the tray icon and receives system messages.
/// </summary>
public static nint RunnerHwnd { get; private set; }
private const string TrayWindowClassName = "pt_tray_icon_window_class";
/// <summary>
/// Gets all the currently loaded modules.
/// </summary>
public static List<IPowerToysModule> LoadedModules { get; } = [];
/// <summary>
/// Gets the list of all available PowerToys modules.
/// </summary>
public static FrozenSet<IPowerToysModule> ModulesToLoad { get; } =
[
new ColorPickerModuleInterface(),
@@ -46,7 +55,11 @@ namespace RunnerV2
new CropAndLockModuleInterface(),
];
internal static bool Run(Action afterInitializationAction)
/// <summary>
/// Runs the main message loop for Runner.
/// </summary>
/// <param name="afterInitializationAction">A function to execute after initialization.</param>
internal static void Run(Action afterInitializationAction)
{
Logger.LogInfo("Runner started");
@@ -65,12 +78,13 @@ namespace RunnerV2
afterInitializationAction();
MessageLoop();
return true;
}
private static readonly uint _taskbarCreatedMessage = RegisterWindowMessageW("TaskbarCreated");
/// <summary>
/// The main message loop that processes Windows messages.
/// </summary>
[STAThread]
private static void MessageLoop()
{
@@ -91,6 +105,9 @@ namespace RunnerV2
Close();
}
/// <summary>
/// Closes Runner and all loaded modules.
/// </summary>
[DoesNotReturn]
internal static void Close()
{
@@ -123,6 +140,10 @@ namespace RunnerV2
Environment.Exit(0);
}
/// <summary>
/// Toggles the state of a module based on its enabled property and GPO rules.
/// </summary>
/// <param name="module">The module to toggle</param>
public static void ToggleModuleStateBasedOnEnabledProperty(IPowerToysModule module)
{
try
@@ -194,6 +215,9 @@ namespace RunnerV2
}
}
/// <summary>
/// Initializes the tray window to receive system messages.
/// </summary>
[STAThread]
private static void InitializeTrayWindow()
{
@@ -238,6 +262,9 @@ namespace RunnerV2
}
}
/// <summary>
/// Handles Windows messages sent to the tray window.
/// </summary>
private static IntPtr HandleMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
switch (msg)