LenovoLegionToolkit
269 строк · 9.1 Кб
1using System;2using System.Collections.Generic;3using System.ComponentModel;4using System.Diagnostics;5using System.Linq;6using System.ServiceProcess;7using System.Threading.Tasks;8using LenovoLegionToolkit.Lib.Extensions;9using LenovoLegionToolkit.Lib.Utils;10using TaskService = Microsoft.Win32.TaskScheduler.TaskService;11
12namespace LenovoLegionToolkit.Lib.SoftwareDisabler;13
14public class SoftwareDisablerException : Exception15{
16public SoftwareDisablerException(string message, Exception innerException) : base(message, innerException) { }17}
18
19public abstract class AbstractSoftwareDisabler20{
21protected abstract IEnumerable<string> ScheduledTasksPaths { get; }22protected abstract IEnumerable<string> ServiceNames { get; }23protected abstract IEnumerable<string> ProcessNames { get; }24
25public Task<SoftwareStatus> GetStatusAsync() => Task.Run(() =>26{27bool isEnabled;28bool isInstalled;29
30try31{32var services = RunningServices().ToArray();33var processes = RunningProcesses().ToArray();34
35if (Log.Instance.IsTraceEnabled)36{37Log.Instance.Trace($"Running services count: {services.Length}. [type={GetType().Name}, services={string.Join(",", services)}]");38Log.Instance.Trace($"Running processes count: {processes.Length}. [type={GetType().Name}, processes={string.Join(",", processes)}]");39}40
41isEnabled = services.Any() || processes.Any();42isInstalled = IsInstalled();43}44catch (Exception ex)45{46if (Log.Instance.IsTraceEnabled)47Log.Instance.Trace($"Exception while getting status. [type={GetType().Name}]", ex);48
49isEnabled = false;50isInstalled = false;51}52
53if (Log.Instance.IsTraceEnabled)54Log.Instance.Trace($"Status: {isEnabled},{isInstalled} [type={GetType().Name}]");55
56if (isEnabled)57return SoftwareStatus.Enabled;58
59if (!isInstalled)60return SoftwareStatus.NotFound;61
62return SoftwareStatus.Disabled;63});64
65public virtual Task EnableAsync() => Task.Run(() =>66{67if (Log.Instance.IsTraceEnabled)68Log.Instance.Trace($"Enabling... [type={GetType().Name}]");69
70SetScheduledTasksEnabled(true);71SetServicesEnabled(true);72
73if (Log.Instance.IsTraceEnabled)74Log.Instance.Trace($"Enabled [type={GetType().Name}]");75});76
77public virtual Task DisableAsync() => Task.Run(async () =>78{79if (Log.Instance.IsTraceEnabled)80Log.Instance.Trace($"Disabling... [type={GetType().Name}]");81
82SetScheduledTasksEnabled(false);83SetServicesEnabled(false);84await KillProcessesAsync().ConfigureAwait(false);85
86if (Log.Instance.IsTraceEnabled)87Log.Instance.Trace($"Disabled [type={GetType().Name}]");88});89
90private bool IsInstalled() => ServiceController.GetServices().Any(s => ServiceNames.Contains(s.ServiceName));91
92private IEnumerable<string> RunningServices()93{94var services = ServiceController.GetServices();95return ServiceNames.Where(s => IsServiceEnabled(s, services));96}97
98protected virtual IEnumerable<string> RunningProcesses()99{100foreach (var process in Process.GetProcesses())101{102foreach (var processName in ProcessNames)103{104var name = string.Empty;105
106try107{108name = process.ProcessName;109if (!name.StartsWith(processName, StringComparison.InvariantCultureIgnoreCase))110continue;111}112catch { /* Ignored. */ }113
114if (!string.IsNullOrEmpty(name))115yield return name;116}117}118}119
120private static bool IsServiceEnabled(string serviceName, IEnumerable<ServiceController> services)121{122try123{124var service = services.FirstOrDefault(s => s.ServiceName == serviceName);125if (service is null)126return false;127
128return service.Status is not ServiceControllerStatus.Stopped;129}130catch (InvalidOperationException)131{132return false;133}134}135
136private void SetScheduledTasksEnabled(bool enabled)137{138var taskService = TaskService.Instance;139foreach (var path in ScheduledTasksPaths)140SetTasksInFolderEnabled(taskService, path, enabled);141}142
143private void SetTasksInFolderEnabled(TaskService taskService, string path, bool enabled)144{145if (Log.Instance.IsTraceEnabled)146Log.Instance.Trace($"Setting tasks in folder {path} to {enabled}. [type={GetType().Name}]");147
148var folder = taskService.GetFolder(path);149if (folder is null)150{151if (Log.Instance.IsTraceEnabled)152Log.Instance.Trace($"Folder not found [path={path}, type={GetType().Name}]]");153
154return;155}156
157foreach (var task in folder.Tasks.ToArray())158{159task.Definition.Settings.Enabled = enabled;160try161{162task.RegisterChanges();163}164catch (Exception ex)165{166if (Log.Instance.IsTraceEnabled)167Log.Instance.Trace($"Failed to register changes on task {task.Name} in {task.Path}.", ex);168
169throw new SoftwareDisablerException($"Failed to register changes on task {task.Name} in {task.Path}. [type={GetType().Name}]", ex);170}171}172}173
174private void SetServicesEnabled(bool enabled)175{176foreach (var serviceName in ServiceNames)177SetServiceEnabled(serviceName, enabled);178}179
180private void SetServiceEnabled(string serviceName, bool enabled)181{182try183{184if (Log.Instance.IsTraceEnabled)185Log.Instance.Trace($"Setting service {serviceName} to {enabled}. [type={GetType().Name}]");186
187if (!ServiceController.GetServices().Any(s => s.ServiceName == serviceName))188{189if (Log.Instance.IsTraceEnabled)190Log.Instance.Trace($"Service {serviceName} not found. [type={GetType().Name}]");191
192return;193}194
195var service = new ServiceController(serviceName);196
197try198{199if (Log.Instance.IsTraceEnabled)200Log.Instance.Trace($"Changing service {serviceName} start mode to {enabled}. [type={GetType().Name}]");201
202service.ChangeStartMode(enabled);203
204if (enabled)205{206if (service.Status != ServiceControllerStatus.Running)207{208if (Log.Instance.IsTraceEnabled)209Log.Instance.Trace($"Starting service {serviceName}... [type={GetType().Name}]");210service.Start();211service.WaitForStatus(ServiceControllerStatus.Running);212}213else214{215if (Log.Instance.IsTraceEnabled)216Log.Instance.Trace($"Will not start service {serviceName}. [status={service.Status}, type={GetType().Name}]]");217}218}219else220{221if (service.CanStop)222{223if (Log.Instance.IsTraceEnabled)224Log.Instance.Trace($"Stopping service {serviceName}... [type={GetType().Name}]");225service.Stop();226service.WaitForStatus(ServiceControllerStatus.Stopped);227}228else229{230if (Log.Instance.IsTraceEnabled)231Log.Instance.Trace($"Will not stop service {serviceName}. [status={service.Status}, canStop={service.CanStop}, type={GetType().Name}]]");232}233}234}235finally236{237service.Close();238}239}240catch (InvalidOperationException ex) when (ex.InnerException is Win32Exception { NativeErrorCode: 1060 })241{242if (Log.Instance.IsTraceEnabled)243Log.Instance.Trace($"Service {serviceName} could not be set to {enabled}");244
245throw new SoftwareDisablerException(serviceName, ex);246}247}248
249protected virtual async Task KillProcessesAsync()250{251foreach (var process in Process.GetProcesses())252foreach (var processName in ProcessNames)253{254try255{256if (process.ProcessName.StartsWith(processName, StringComparison.InvariantCultureIgnoreCase))257{258process.Kill();259await process.WaitForExitAsync().ConfigureAwait(false);260}261}262catch (Exception ex)263{264if (Log.Instance.IsTraceEnabled)265Log.Instance.Trace($"Couldn't kill process.", ex);266}267}268}269}
270