mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-06 19:26:39 +02:00
Rename the [Ee]xts dir to ext (#38852)
**WARNING:** This PR will probably blow up all in-flight PRs at some point in the early days of CmdPal, two of us created seperate `Exts` and `exts` dirs. Depending on what the casing was on the branch that you checked one of those out from, it'd get stuck like that on your PC forever. Windows didn't care, so we never noticed. But GitHub does care, and now browsing the source on GitHub is basically impossible. Closes #38081
This commit is contained in:
@@ -0,0 +1,253 @@
|
||||
// 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.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.ServiceProcess;
|
||||
using Microsoft.CmdPal.Ext.WindowsServices.Commands;
|
||||
using Microsoft.CmdPal.Ext.WindowsServices.Properties;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Microsoft.Win32;
|
||||
using Windows.System;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.WindowsServices.Helpers;
|
||||
|
||||
public static class ServiceHelper
|
||||
{
|
||||
public static IEnumerable<ListItem> Search(string search)
|
||||
{
|
||||
var services = ServiceController.GetServices().OrderBy(s => s.DisplayName);
|
||||
IEnumerable<ServiceController> serviceList = [];
|
||||
|
||||
if (search.StartsWith(Resources.wox_plugin_service_status + ":", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
// allows queries like 'status:running'
|
||||
serviceList = services.Where(s => GetLocalizedStatus(s.Status).Contains(search.Split(':')[1], StringComparison.CurrentCultureIgnoreCase));
|
||||
}
|
||||
else if (search.StartsWith(Resources.wox_plugin_service_startup + ":", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
// allows queries like 'startup:automatic'
|
||||
serviceList = services.Where(s => GetLocalizedStartType(s.StartType, s.ServiceName).Contains(search.Split(':')[1], StringComparison.CurrentCultureIgnoreCase));
|
||||
}
|
||||
else
|
||||
{
|
||||
// To show 'starts with' results first, we split the search into two steps and then concatenating the lists.
|
||||
var servicesStartsWith = services
|
||||
.Where(s => s.DisplayName.StartsWith(search, StringComparison.OrdinalIgnoreCase) || s.ServiceName.StartsWith(search, StringComparison.OrdinalIgnoreCase));
|
||||
var servicesContains = services.Except(servicesStartsWith)
|
||||
.Where(s => s.DisplayName.Contains(search, StringComparison.OrdinalIgnoreCase) || s.ServiceName.Contains(search, StringComparison.OrdinalIgnoreCase));
|
||||
serviceList = servicesStartsWith.Concat(servicesContains);
|
||||
}
|
||||
|
||||
var result = serviceList.Select(s =>
|
||||
{
|
||||
var serviceResult = ServiceResult.CreateServiceController(s);
|
||||
if (serviceResult == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ServiceCommand serviceCommand;
|
||||
CommandContextItem[] moreCommands;
|
||||
if (serviceResult.IsRunning)
|
||||
{
|
||||
serviceCommand = new ServiceCommand(serviceResult, Action.Stop);
|
||||
moreCommands = [
|
||||
new CommandContextItem(new RestartServiceCommand(serviceResult)),
|
||||
new CommandContextItem(new OpenServicesCommand(serviceResult))
|
||||
{
|
||||
RequestedShortcut = KeyChordHelpers.FromModifiers(true, false, false, false, (int)VirtualKey.O, 0),
|
||||
},
|
||||
];
|
||||
}
|
||||
else
|
||||
{
|
||||
serviceCommand = new ServiceCommand(serviceResult, Action.Start);
|
||||
moreCommands = [
|
||||
new CommandContextItem(new OpenServicesCommand(serviceResult)),
|
||||
];
|
||||
}
|
||||
|
||||
IconInfo icon = new("\U0001f7e2"); // unicode LARGE GREEN CIRCLE
|
||||
switch (s.Status)
|
||||
{
|
||||
case ServiceControllerStatus.Stopped:
|
||||
icon = new("\U0001F534"); // unicode LARGE RED CIRCLE
|
||||
break;
|
||||
case ServiceControllerStatus.Running:
|
||||
break;
|
||||
case ServiceControllerStatus.Paused:
|
||||
icon = new("\u23F8"); // unicode DOUBLE VERTICAL BAR, aka, "Pause"
|
||||
break;
|
||||
}
|
||||
|
||||
return new ListItem(serviceCommand)
|
||||
{
|
||||
Title = s.DisplayName,
|
||||
Subtitle = ServiceHelper.GetResultSubTitle(s),
|
||||
MoreCommands = moreCommands,
|
||||
Icon = icon,
|
||||
|
||||
// TODO GH #78 we need to improve the icon story
|
||||
// TODO GH #126 investigate tooltip story
|
||||
// ToolTipData = new ToolTipData(serviceResult.DisplayName, serviceResult.ServiceName),
|
||||
// IcoPath = icoPath,
|
||||
};
|
||||
}).Where(s => s != null);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO GH #118 IPublicAPI contextAPI isn't used anymore, but we need equivalent ways to show notifications and status
|
||||
public static void ChangeStatus(ServiceResult serviceResult, Action action)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(serviceResult);
|
||||
|
||||
// ArgumentNullException.ThrowIfNull(contextAPI);
|
||||
try
|
||||
{
|
||||
var info = new ProcessStartInfo
|
||||
{
|
||||
FileName = "net",
|
||||
Verb = "runas",
|
||||
UseShellExecute = true,
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
};
|
||||
|
||||
if (action == Action.Start)
|
||||
{
|
||||
info.Arguments = $"start \"{serviceResult.ServiceName}\"";
|
||||
}
|
||||
else if (action == Action.Stop)
|
||||
{
|
||||
info.Arguments = $"stop \"{serviceResult.ServiceName}\"";
|
||||
}
|
||||
else if (action == Action.Restart)
|
||||
{
|
||||
info.FileName = "cmd";
|
||||
info.Arguments = $"/c net stop \"{serviceResult.ServiceName}\" && net start \"{serviceResult.ServiceName}\"";
|
||||
}
|
||||
|
||||
var process = Process.Start(info);
|
||||
process.WaitForExit();
|
||||
var exitCode = process.ExitCode;
|
||||
|
||||
#pragma warning disable IDE0059, CS0168, SA1005
|
||||
if (exitCode == 0)
|
||||
{
|
||||
// TODO GH #118 feedback to users
|
||||
// contextAPI.ShowNotification(GetLocalizedMessage(action), serviceResult.DisplayName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO GH #108 We need to figure out some logging
|
||||
// contextAPI.ShowNotification(GetLocalizedErrorMessage(action), serviceResult.DisplayName);
|
||||
// Log.Error($"The command returned {exitCode}", MethodBase.GetCurrentMethod().DeclaringType);
|
||||
}
|
||||
}
|
||||
catch (Win32Exception ex)
|
||||
{
|
||||
// TODO GH #108 We need to figure out some logging
|
||||
// Log.Error(ex.Message, MethodBase.GetCurrentMethod().DeclaringType);
|
||||
}
|
||||
}
|
||||
#pragma warning restore IDE0059, CS0168, SA1005
|
||||
|
||||
public static void OpenServices()
|
||||
{
|
||||
try
|
||||
{
|
||||
var startInfo = new System.Diagnostics.ProcessStartInfo
|
||||
{
|
||||
FileName = "services.msc",
|
||||
UseShellExecute = true,
|
||||
};
|
||||
|
||||
System.Diagnostics.Process.Start(startInfo);
|
||||
}
|
||||
#pragma warning disable IDE0059, CS0168, SA1005
|
||||
catch (Exception ex)
|
||||
{
|
||||
// TODO GH #108 We need to figure out some logging
|
||||
}
|
||||
}
|
||||
#pragma warning restore IDE0059, CS0168, SA1005
|
||||
|
||||
private static string GetResultSubTitle(ServiceController serviceController)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(serviceController);
|
||||
return $"{Resources.wox_plugin_service_status}: {GetLocalizedStatus(serviceController.Status)} - {Resources.wox_plugin_service_startup}: {GetLocalizedStartType(serviceController.StartType, serviceController.ServiceName)} - {Resources.wox_plugin_service_name}: {serviceController.ServiceName}";
|
||||
}
|
||||
|
||||
private static string GetLocalizedStatus(ServiceControllerStatus status)
|
||||
{
|
||||
if (status == ServiceControllerStatus.Stopped)
|
||||
{
|
||||
return Resources.wox_plugin_service_stopped;
|
||||
}
|
||||
else if (status == ServiceControllerStatus.StartPending)
|
||||
{
|
||||
return Resources.wox_plugin_service_start_pending;
|
||||
}
|
||||
else if (status == ServiceControllerStatus.StopPending)
|
||||
{
|
||||
return Resources.wox_plugin_service_stop_pending;
|
||||
}
|
||||
else if (status == ServiceControllerStatus.Running)
|
||||
{
|
||||
return Resources.wox_plugin_service_running;
|
||||
}
|
||||
else
|
||||
{
|
||||
return status == ServiceControllerStatus.ContinuePending
|
||||
? Resources.wox_plugin_service_continue_pending
|
||||
: status == ServiceControllerStatus.PausePending
|
||||
? Resources.wox_plugin_service_pause_pending
|
||||
: status == ServiceControllerStatus.Paused ? Resources.wox_plugin_service_paused : status.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetLocalizedStartType(ServiceStartMode startMode, string serviceName)
|
||||
{
|
||||
if (startMode == ServiceStartMode.Boot)
|
||||
{
|
||||
return Resources.wox_plugin_service_start_mode_boot;
|
||||
}
|
||||
else if (startMode == ServiceStartMode.System)
|
||||
{
|
||||
return Resources.wox_plugin_service_start_mode_system;
|
||||
}
|
||||
else
|
||||
{
|
||||
return startMode == ServiceStartMode.Automatic
|
||||
? !IsDelayedStart(serviceName) ? Resources.wox_plugin_service_start_mode_automatic : Resources.wox_plugin_service_start_mode_automaticDelayed
|
||||
: startMode == ServiceStartMode.Manual
|
||||
? Resources.wox_plugin_service_start_mode_manual
|
||||
: startMode == ServiceStartMode.Disabled ? Resources.wox_plugin_service_start_mode_disabled : startMode.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetLocalizedMessage(Action action)
|
||||
{
|
||||
return action == Action.Start
|
||||
? Resources.wox_plugin_service_started_notification
|
||||
: action == Action.Stop
|
||||
? Resources.wox_plugin_service_stopped_notification
|
||||
: action == Action.Restart ? Resources.wox_plugin_service_restarted_notification : string.Empty;
|
||||
}
|
||||
|
||||
private static string GetLocalizedErrorMessage(Action action)
|
||||
{
|
||||
return action == Action.Start
|
||||
? Resources.wox_plugin_service_start_error_notification
|
||||
: action == Action.Stop
|
||||
? Resources.wox_plugin_service_stop_error_notification
|
||||
: action == Action.Restart ? Resources.wox_plugin_service_restart_error_notification : string.Empty;
|
||||
}
|
||||
|
||||
private static bool IsDelayedStart(string serviceName) => (int?)Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Services\" + serviceName, false)?.GetValue("DelayedAutostart", 0, RegistryValueOptions.None) == 1;
|
||||
}
|
||||
Reference in New Issue
Block a user