diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/AdvancedPasteModuleInterface.cs b/src/RunnerV2/RunnerV2/ModuleInterfaces/AdvancedPasteModuleInterface.cs index 183e6ac569..0a316d6ded 100644 --- a/src/RunnerV2/RunnerV2/ModuleInterfaces/AdvancedPasteModuleInterface.cs +++ b/src/RunnerV2/RunnerV2/ModuleInterfaces/AdvancedPasteModuleInterface.cs @@ -17,7 +17,7 @@ using RunnerV2.Helpers; namespace RunnerV2.ModuleInterfaces { - internal sealed class AdvancedPasteModuleInterface : IPowerToysModule, IDisposable + internal sealed class AdvancedPasteModuleInterface : ProcessModuleAbstractClass, IPowerToysModule, IDisposable { public string Name => "AdvancedPaste"; @@ -33,29 +33,17 @@ namespace RunnerV2.ModuleInterfaces _ipc.End(); _ipc = null; } - - ProcessHelper.ScheudleProcessKill("PowerToys.AdvancedPaste"); } private TwoWayPipeMessageIPCManaged? _ipc; + private string _ipcName = @"\\.\pipe\PowerToys.AdvancedPaste"; public void Enable() { - if (Process.GetProcessesByName("PowerToys.AdvancedPaste.exe").Length > 0) - { - return; - } - - string ipcName = @"\\.\pipe\PowerToys.AdvancedPaste"; - _ipc = new TwoWayPipeMessageIPCManaged(string.Empty, ipcName, (_) => { }); + _ipc = new TwoWayPipeMessageIPCManaged(string.Empty, _ipcName, (_) => { }); _ipc.Start(); - if (Shortcuts.Count == 0) - { - PopulateShortcuts(); - } - - Process.Start("WinUI3Apps\\PowerToys.AdvancedPaste.exe", $"{Environment.ProcessId} {ipcName}"); + PopulateShortcuts(); } public void OnSettingsChanged(string settingsKind, JsonElement jsonProperties) @@ -65,10 +53,7 @@ namespace RunnerV2.ModuleInterfaces public void PopulateShortcuts() { - if (_ipc is null) - { - _ipc = new TwoWayPipeMessageIPCManaged(string.Empty, @"\\.\pipe\PowerToys.AdvancedPaste", (_) => { }); - } + _ipc ??= new TwoWayPipeMessageIPCManaged(string.Empty, @"\\.\pipe\PowerToys.AdvancedPaste", (_) => { }); Shortcuts.Clear(); @@ -112,5 +97,13 @@ namespace RunnerV2.ModuleInterfaces } public List<(HotkeySettings Hotkey, Action Action)> Shortcuts { get; } = []; + + public override string ProcessPath => "WinUI3Apps\\PowerToys.AdvancedPaste.exe"; + + public override string ProcessName => "PowerToys.AdvancedPaste"; + + public override string ProcessArguments => _ipcName; + + public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SingletonProcess | ProcessLaunchOptions.RunnerProcessIdAsFirstArgument; } } diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/AlwaysOnTopModuleInterface.cs b/src/RunnerV2/RunnerV2/ModuleInterfaces/AlwaysOnTopModuleInterface.cs index 53176de680..5a755a96de 100644 --- a/src/RunnerV2/RunnerV2/ModuleInterfaces/AlwaysOnTopModuleInterface.cs +++ b/src/RunnerV2/RunnerV2/ModuleInterfaces/AlwaysOnTopModuleInterface.cs @@ -14,7 +14,7 @@ using RunnerV2.Helpers; namespace RunnerV2.ModuleInterfaces { - public partial class AlwaysOnTopModuleInterface : IPowerToysModule, IDisposable + internal sealed partial class AlwaysOnTopModuleInterface : ProcessModuleAbstractClass, IPowerToysModule, IDisposable { public bool Enabled => new SettingsUtils().GetSettings().Enabled.AlwaysOnTop; @@ -22,8 +22,6 @@ namespace RunnerV2.ModuleInterfaces public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredAlwaysOnTopEnabledValue(); - private Process? _process; - private InteropEvent? _pinEventWrapper; public void Disable() @@ -33,44 +31,22 @@ namespace RunnerV2.ModuleInterfaces terminateEventWrapper.Dispose(); _pinEventWrapper?.Dispose(); _pinEventWrapper = null; - - ProcessHelper.ScheudleProcessKill("PowerToys.AlwaysOnTop"); } public void Enable() - { - if (_process?.HasExited == false) - { - return; - } - - _pinEventWrapper = new InteropEvent(InteropEvent.AlwaysOnTopPin); - - var psi = new ProcessStartInfo - { - FileName = "PowerToys.AlwaysOnTop.exe", - Arguments = Environment.ProcessId.ToString(CultureInfo.InvariantCulture), - UseShellExecute = true, - }; - - _process = Process.Start(psi); - } - - public AlwaysOnTopModuleInterface() { InitializeHotkey(); + _pinEventWrapper = new InteropEvent(InteropEvent.AlwaysOnTopPin); } private void InitializeHotkey() { Shortcuts.Clear(); Shortcuts.Add((new SettingsUtils().GetSettings(Name).Properties.Hotkey.Value, () => - { - if (!_process?.HasExited ?? false) { _pinEventWrapper?.Fire(); } - })); + )); } public void OnSettingsChanged(string settingsKind, JsonElement jsonProperties) @@ -80,9 +56,14 @@ namespace RunnerV2.ModuleInterfaces public List<(HotkeySettings Hotkey, Action Action)> Shortcuts { get; } = []; + public override string ProcessPath => "PowerToys.AlwaysOnTop.exe"; + + public override string ProcessName => "PowerToys.AlwaysOnTop"; + + public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SingletonProcess | ProcessLaunchOptions.RunnerProcessIdAsFirstArgument | ProcessLaunchOptions.ElevateIfApplicable; + public void Dispose() { - _process?.Dispose(); _pinEventWrapper?.Dispose(); GC.SuppressFinalize(this); } diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/AwakeModuleInterface.cs b/src/RunnerV2/RunnerV2/ModuleInterfaces/AwakeModuleInterface.cs index 8590445cee..52c0c936a5 100644 --- a/src/RunnerV2/RunnerV2/ModuleInterfaces/AwakeModuleInterface.cs +++ b/src/RunnerV2/RunnerV2/ModuleInterfaces/AwakeModuleInterface.cs @@ -9,10 +9,11 @@ using ManagedCommon; using Microsoft.PowerToys.Settings.UI.Library; using PowerToys.GPOWrapper; using RunnerV2.Helpers; +using Windows.Media.Capture; namespace RunnerV2.ModuleInterfaces { - internal sealed partial class AwakeModuleInterface : IPowerToysModule, IDisposable + internal sealed class AwakeModuleInterface : ProcessModuleAbstractClass, IPowerToysModule { public string Name => "Awake"; @@ -20,38 +21,23 @@ namespace RunnerV2.ModuleInterfaces public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredAwakeEnabledValue(); - private Process? _process; + public override string ProcessPath => "PowerToys.Awake.exe"; + + public override string ProcessName => "PowerToys.Awake"; + + public override string ProcessArguments => $"--use-pt-config --pid {Environment.ProcessId.ToString(CultureInfo.InvariantCulture)}"; + + public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SingletonProcess; public void Disable() { InteropEvent terminateEventWrapper = new(InteropEvent.AwakeTerminate); terminateEventWrapper.Fire(); terminateEventWrapper.Dispose(); - - ProcessHelper.ScheudleProcessKill("PowerToys.Awake"); } public void Enable() { - if (_process?.HasExited == false) - { - return; - } - - var psi = new ProcessStartInfo - { - FileName = "PowerToys.Awake.exe", - Arguments = $"--use-pt-config --pid {Environment.ProcessId.ToString(CultureInfo.InvariantCulture)}", - UseShellExecute = true, - }; - - _process = Process.Start(psi); - } - - public void Dispose() - { - _process?.Dispose(); - GC.SuppressFinalize(this); } } } diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/ColorPickerModuleInterface.cs b/src/RunnerV2/RunnerV2/ModuleInterfaces/ColorPickerModuleInterface.cs index c0857e87b4..1caa0173d1 100644 --- a/src/RunnerV2/RunnerV2/ModuleInterfaces/ColorPickerModuleInterface.cs +++ b/src/RunnerV2/RunnerV2/ModuleInterfaces/ColorPickerModuleInterface.cs @@ -17,7 +17,7 @@ using RunnerV2.Helpers; namespace RunnerV2.ModuleInterfaces { - internal sealed partial class ColorPickerModuleInterface : IPowerToysModule, IDisposable + internal sealed partial class ColorPickerModuleInterface : ProcessModuleAbstractClass, IPowerToysModule, IDisposable { public string Name => "ColorPicker"; @@ -25,8 +25,6 @@ namespace RunnerV2.ModuleInterfaces public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredColorPickerEnabledValue(); - private Process? _process; - private InteropEvent? _showUiEventWrapper; public void Disable() @@ -36,56 +34,40 @@ namespace RunnerV2.ModuleInterfaces terminateEventWrapper.Dispose(); _showUiEventWrapper?.Dispose(); _showUiEventWrapper = null; - - ProcessHelper.ScheudleProcessKill("PowerToys.ColorPickerUI"); } public void Enable() { - if (_process?.HasExited == false) - { - return; - } + InitializeShortcuts(); _showUiEventWrapper = new InteropEvent(InteropEvent.ColorPickerShow); - - var psi = new ProcessStartInfo - { - FileName = "PowerToys.ColorPickerUI.exe", - Arguments = Environment.ProcessId.ToString(CultureInfo.InvariantCulture), - UseShellExecute = true, - }; - - _process = Process.Start(psi); } - public ColorPickerModuleInterface() - { - InitializeHotkey(); - } - - private void InitializeHotkey() + private void InitializeShortcuts() { Shortcuts.Clear(); Shortcuts.Add((new SettingsUtils().GetSettings(Name).Properties.ActivationShortcut, () => { - if (!_process?.HasExited ?? false) - { - _showUiEventWrapper?.Fire(); - } - })); + _showUiEventWrapper?.Fire(); + } + )); } public void OnSettingsChanged(string settingsKind, JsonElement jsonProperties) { - InitializeHotkey(); + InitializeShortcuts(); } public List<(HotkeySettings Hotkey, Action Action)> Shortcuts { get; } = []; + public override string ProcessPath => "PowerToys.ColorPickerUI.exe"; + + public override string ProcessName => "PowerToys.ColorPickerUI"; + + public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SingletonProcess | ProcessLaunchOptions.RunnerProcessIdAsFirstArgument; + public void Dispose() { - _process?.Dispose(); _showUiEventWrapper?.Dispose(); GC.SuppressFinalize(this); } diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/CommandPaletteModuleInterface.cs b/src/RunnerV2/RunnerV2/ModuleInterfaces/CommandPaletteModuleInterface.cs index 933c15c41b..67d5037832 100644 --- a/src/RunnerV2/RunnerV2/ModuleInterfaces/CommandPaletteModuleInterface.cs +++ b/src/RunnerV2/RunnerV2/ModuleInterfaces/CommandPaletteModuleInterface.cs @@ -16,7 +16,7 @@ using Windows.ApplicationModel; namespace RunnerV2.ModuleInterfaces { - internal sealed class CommandPaletteModuleInterface : IPowerToysModule + internal sealed class CommandPaletteModuleInterface : ProcessModuleAbstractClass, IPowerToysModule { private const string PackageName = "Microsoft.CommandPalette" #if DEBUG @@ -30,13 +30,16 @@ namespace RunnerV2.ModuleInterfaces public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredCmdPalEnabledValue(); + public override string ProcessPath => "explorer.exe"; + + public override string ProcessArguments => "x-cmdpal://background"; + + public override string ProcessName => string.Empty; + + public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.UseShellExecute | ProcessLaunchOptions.NeverExit; + public void Disable() { - ProcessHelper.ScheudleProcessKill("Microsoft.CmdPal.UI"); - lock (_launchedLock) - { - _launched = false; - } } public void Enable() @@ -73,64 +76,6 @@ namespace RunnerV2.ModuleInterfaces Logger.LogError("Command Palette package is not registered after attempting to enable it."); return; } - - lock (_launchedLock) - { - if (_launched) - { - return; - } - } - - LaunchApp("explorer.exe", "x-cmdpal://background", false); - } - - private readonly object _launchedLock = new(); - private bool _launched; - - // TODO: Implement retry logic for launching the app - /*private static void TryLaunch(string path, string args) - { - int baseDelay = 1000; - int maxAttempts = 9; - int retryCount = 0; - - do - { - if (LaunchApp) - } - }*/ - - private bool LaunchApp(string path, string args, bool elevated) - { - try - { - Process? process = Process.Start(new ProcessStartInfo - { - FileName = path, - CreateNoWindow = true, - UseShellExecute = true, - Verb = elevated ? "runas" : "open", - Arguments = args, - }); - - if (process is null) - { - Logger.LogError($"Failed to start process for {path} with args {args}"); - } - } - catch (Exception ex) - { - Logger.LogError($"Exception occurred while launching app {path} with args {args}", ex); - return false; - } - - lock (_launchedLock) - { - _launched = true; - } - - return true; } } } diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/CropAndLockModuleInterface.cs b/src/RunnerV2/RunnerV2/ModuleInterfaces/CropAndLockModuleInterface.cs index 5ee3f52806..ec81c1f632 100644 --- a/src/RunnerV2/RunnerV2/ModuleInterfaces/CropAndLockModuleInterface.cs +++ b/src/RunnerV2/RunnerV2/ModuleInterfaces/CropAndLockModuleInterface.cs @@ -15,7 +15,7 @@ using RunnerV2.Helpers; namespace RunnerV2.ModuleInterfaces { - internal sealed partial class CropAndLockModuleInterface : IPowerToysModule, IDisposable + internal sealed partial class CropAndLockModuleInterface : ProcessModuleAbstractClass, IPowerToysModule, IDisposable { public string Name => "CropAndLock"; @@ -33,27 +33,16 @@ namespace RunnerV2.ModuleInterfaces _reparentEvent.Dispose(); _thumbnailEvent.Dispose(); _terminateEvent.Dispose(); - ProcessHelper.ScheudleProcessKill("PowerToys.CropAndLock"); } public void Enable() { - EnsureLaunched(); _reparentEvent = new(InteropEvent.CropAndLockReparent); _thumbnailEvent = new(InteropEvent.CropAndLockThumbnail); _terminateEvent = new(InteropEvent.CropAndLockTerminate); PopulateShortcuts(); } - private void EnsureLaunched() - { - Process[] processes = Process.GetProcessesByName("PowerToys.CropAndLock"); - if (processes.Length == 0) - { - Process.Start("PowerToys.CropAndLock.exe", Environment.ProcessId.ToString(CultureInfo.InvariantCulture)); - } - } - public void PopulateShortcuts() { Shortcuts.Clear(); @@ -69,6 +58,12 @@ namespace RunnerV2.ModuleInterfaces public List<(HotkeySettings Hotkey, Action Action)> Shortcuts { get; } = []; + public override string ProcessPath => "PowerToys.CropAndLock.exe"; + + public override string ProcessName => "PowerToys.CropAndLock"; + + public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SingletonProcess | ProcessLaunchOptions.RunnerProcessIdAsFirstArgument; + public void Dispose() { GC.SuppressFinalize(this); diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/HostsModuleInterface.cs b/src/RunnerV2/RunnerV2/ModuleInterfaces/HostsModuleInterface.cs index ffecfa53a8..02b0a6caa8 100644 --- a/src/RunnerV2/RunnerV2/ModuleInterfaces/HostsModuleInterface.cs +++ b/src/RunnerV2/RunnerV2/ModuleInterfaces/HostsModuleInterface.cs @@ -9,7 +9,7 @@ using RunnerV2.Helpers; namespace RunnerV2.ModuleInterfaces { - internal sealed class HostsModuleInterface : IPowerToysModule + internal sealed class HostsModuleInterface : ProcessModuleAbstractClass, IPowerToysModule { public bool Enabled => new SettingsUtils().GetSettingsOrDefault().Enabled.Hosts; @@ -17,9 +17,14 @@ namespace RunnerV2.ModuleInterfaces public string Name => "Hosts"; + public override string ProcessPath => string.Empty; + + public override string ProcessName => "PowerToys.Hosts"; + + public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SupressLaunchOnModuleEnabled; + public void Disable() { - ProcessHelper.ScheudleProcessKill("PowerToys.Hosts", 0); } public void Enable() diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/PowerAccentModuleInterface.cs b/src/RunnerV2/RunnerV2/ModuleInterfaces/PowerAccentModuleInterface.cs index 9531384741..32964ff149 100644 --- a/src/RunnerV2/RunnerV2/ModuleInterfaces/PowerAccentModuleInterface.cs +++ b/src/RunnerV2/RunnerV2/ModuleInterfaces/PowerAccentModuleInterface.cs @@ -10,7 +10,7 @@ using PowerToys.GPOWrapper; namespace RunnerV2.ModuleInterfaces { - internal sealed class PowerAccentModuleInterface : IPowerToysModule + internal sealed class PowerAccentModuleInterface : ProcessModuleAbstractClass, IPowerToysModule { public string Name => "PowerAccent"; @@ -18,17 +18,18 @@ namespace RunnerV2.ModuleInterfaces public GpoRuleConfigured GpoRuleConfigured => GPOWrapper.GetConfiguredQuickAccentEnabledValue(); + public override string ProcessPath => "PowerToys.PowerAccent.exe"; + + public override string ProcessName => "PowerToys.PowerAccent"; + + public override ProcessLaunchOptions LaunchOptions => ProcessLaunchOptions.SingletonProcess | ProcessLaunchOptions.RunnerProcessIdAsFirstArgument; + public void Disable() { - foreach (var process in Process.GetProcessesByName("PowerToys.PowerAccent.exe")) - { - process.Kill(); - } } public void Enable() { - Process.Start("PowerToys.PowerAccent.exe", Environment.ProcessId.ToString(CultureInfo.InvariantCulture)); } } } diff --git a/src/RunnerV2/RunnerV2/ModuleInterfaces/ProcessModuleAbstractClass.cs b/src/RunnerV2/RunnerV2/ModuleInterfaces/ProcessModuleAbstractClass.cs new file mode 100644 index 0000000000..e6846277c8 --- /dev/null +++ b/src/RunnerV2/RunnerV2/ModuleInterfaces/ProcessModuleAbstractClass.cs @@ -0,0 +1,114 @@ +// 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. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PowerToys.GPOWrapper; +using RunnerV2.Helpers; + +namespace RunnerV2.ModuleInterfaces +{ + internal abstract class ProcessModuleAbstractClass + { + /// + /// Options for launching a process. + /// + [Flags] + public enum ProcessLaunchOptions + { + /// + /// Only a single instance of the process should be running. + /// + SingletonProcess = 1, + + /// + /// Elevate the process if the current process is elevated. + /// + ElevateIfApplicable = 2, + + /// + /// Provide the runner process ID as the first argument to the launched process. + /// + RunnerProcessIdAsFirstArgument = 4, + + /// + /// Indicates that the application should not launch automatically when the specified module is enabled. + /// + SupressLaunchOnModuleEnabled = 8, + + /// + /// Specifies that the process should be started using the operating system shell. + /// + UseShellExecute = 16, + + /// + /// Indicates that the process should never exit automatically. + /// + /// Use this value when using a helper process to launch an application like explorer.exe. + NeverExit = 32, + } + + public abstract string ProcessPath { get; } + + public abstract string ProcessName { get; } + + public virtual string ProcessArguments { get; } = string.Empty; + + public abstract ProcessLaunchOptions LaunchOptions { get; } + + public void EnsureLaunched() + { + Process[] processes = Process.GetProcessesByName(ProcessName); + if (processes.Length > 0) + { + return; + } + + LaunchProcess(); + } + + public void LaunchProcess(bool isModuleEnableProcess = false) + { + if (isModuleEnableProcess && LaunchOptions.HasFlag(ProcessLaunchOptions.SupressLaunchOnModuleEnabled)) + { + return; + } + + if (LaunchOptions.HasFlag(ProcessLaunchOptions.SingletonProcess)) + { + Process[] processes = Process.GetProcessesByName(ProcessName); + if (processes.Length > 0) + { + return; + } + } + + string arguments = (LaunchOptions.HasFlag(ProcessLaunchOptions.RunnerProcessIdAsFirstArgument) ? Environment.ProcessId.ToString(CultureInfo.InvariantCulture) + (string.IsNullOrEmpty(ProcessArguments) ? string.Empty : " ") : string.Empty) + ProcessArguments; + + Process.Start(new ProcessStartInfo() + { + UseShellExecute = LaunchOptions.HasFlag(ProcessLaunchOptions.UseShellExecute), + FileName = ProcessPath, + Arguments = arguments, + Verb = LaunchOptions.HasFlag(ProcessLaunchOptions.ElevateIfApplicable) && ElevationHelper.IsProcessElevated() ? "runas" : "open", + }); + } + + public void ProcessExit(int msDelay = 500) + { + if (LaunchOptions.HasFlag(ProcessLaunchOptions.NeverExit)) + { + return; + } + + ProcessHelper.ScheudleProcessKill(ProcessName, msDelay); + } + } +} diff --git a/src/RunnerV2/RunnerV2/Runner.cs b/src/RunnerV2/RunnerV2/Runner.cs index 7d233da34c..1f765e3f07 100644 --- a/src/RunnerV2/RunnerV2/Runner.cs +++ b/src/RunnerV2/RunnerV2/Runner.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Drawing; +using System.Globalization; using System.IO; using System.Linq; using System.Reflection; @@ -34,13 +35,13 @@ namespace RunnerV2 public static FrozenSet ModulesToLoad { get; } = [ + new ColorPickerModuleInterface(), new AlwaysOnTopModuleInterface(), new HostsModuleInterface(), new PowerAccentModuleInterface(), new AdvancedPasteModuleInterface(), new AwakeModuleInterface(), new CmdNotFoundModuleInterface(), - new ColorPickerModuleInterface(), new CommandPaletteModuleInterface(), new CropAndLockModuleInterface(), ]; @@ -102,6 +103,12 @@ namespace RunnerV2 try { module.Disable(); + + if (module is ProcessModuleAbstractClass pmac) + { + pmac.ProcessExit(); + } + foreach (var hotkey in module.Hotkeys) { HotkeyManager.DisableHotkey(hotkey.Key); @@ -127,6 +134,11 @@ namespace RunnerV2 if (!LoadedModules.Contains(module)) { module.Enable(); + if (module is ProcessModuleAbstractClass pmac) + { + pmac.LaunchProcess(true); + } + LoadedModules.Add(module); } @@ -159,6 +171,11 @@ namespace RunnerV2 { module.Disable(); + if (module is ProcessModuleAbstractClass pmac) + { + pmac.ProcessExit(); + } + foreach (var hotkey in module.Hotkeys) { HotkeyManager.DisableHotkey(hotkey.Key); diff --git a/src/RunnerV2/RunnerV2/RunnerV2.csproj b/src/RunnerV2/RunnerV2/RunnerV2.csproj index 32a7eed81f..a0bb6f6ed3 100644 --- a/src/RunnerV2/RunnerV2/RunnerV2.csproj +++ b/src/RunnerV2/RunnerV2/RunnerV2.csproj @@ -16,6 +16,7 @@ + diff --git a/src/modules/colorPicker/ColorPickerUI/Program.cs b/src/modules/colorPicker/ColorPickerUI/Program.cs index 4b178a4415..3d779fc623 100644 --- a/src/modules/colorPicker/ColorPickerUI/Program.cs +++ b/src/modules/colorPicker/ColorPickerUI/Program.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System; - +using System.Diagnostics; using ColorPicker.Helpers; using ColorPicker.Mouse; using ColorPickerUI;