using System; using System.Linq; using System.Threading.Tasks; //using Windows.ApplicationModel; //using Windows.Management.Deployment; using TrustedUninstaller.Shared.Exceptions; using TrustedUninstaller.Shared.Tasks; using YamlDotNet.Serialization; using System.Diagnostics; using System.IO; using System.Text; using System.Threading; namespace TrustedUninstaller.Shared.Actions { // Integrate ame-assassin later internal class AppxAction : TaskAction, ITaskAction { public void RunTaskOnMainThread() { throw new NotImplementedException(); } public enum AppxOperation { Remove = 0, ClearCache = 1, } public enum Level { Family = 0, Package = 1, App = 2 } [YamlMember(typeof(string), Alias = "name")] public string Name { get; set; } [YamlMember(typeof(Level), Alias = "type")] public Level? Type { get; set; } = Level.Family; [YamlMember(typeof(AppxOperation), Alias = "operation")] public AppxOperation Operation { get; set; } = AppxOperation.Remove; [YamlMember(typeof(bool), Alias = "verboseOutput")] public bool Verbose { get; set; } = false; [YamlMember(typeof(bool), Alias = "unregister")] public bool Unregister { get; set; } = false; [YamlMember(typeof(string), Alias = "weight")] public int ProgressWeight { get; set; } = 30; public int GetProgressWeight() => ProgressWeight; private bool InProgress { get; set; } public void ResetProgress() => InProgress = false; public string ErrorString() => $"AppxAction failed to remove '{Name}'."; /* private Package GetPackage() { var packageManager = new PackageManager(); return packageManager.FindPackages().FirstOrDefault(package => package.Id.Name == Name); } */ public UninstallTaskStatus GetStatus() { if (InProgress) return UninstallTaskStatus.InProgress; return HasFinished ? UninstallTaskStatus.Completed : UninstallTaskStatus.ToDo; //return GetPackage() == null ? UninstallTaskStatus.Completed : UninstallTaskStatus.ToDo; } private bool HasFinished = false; public async Task RunTask() { if (InProgress) throw new TaskInProgressException("Another Appx action was called while one was in progress."); InProgress = true; Console.WriteLine($"Removing APPX {Type.ToString().ToLower()} '{Name}'..."); WinUtil.CheckKph(); string verboseArg = Verbose ? " -Verbose" : ""; string unregisterArg = Unregister ? " -Verbose" : ""; string kernelDriverArg = AmeliorationUtil.UseKernelDriver ? " -UseKernelDriver" : ""; var psi = new ProcessStartInfo() { UseShellExecute = false, CreateNoWindow = true, Arguments = $@"-{Type.ToString()} ""{Name}""" + verboseArg + unregisterArg + kernelDriverArg, FileName = Directory.GetCurrentDirectory() + "\\ame-assassin\\ame-assassin.exe", RedirectStandardOutput = true, RedirectStandardError = true }; if (Operation == AppxOperation.ClearCache) { psi.Arguments = $@"-ClearCache ""{Name}"""; } var proc = Process.Start(psi); proc.OutputDataReceived += ProcOutputHandler; proc.ErrorDataReceived += ProcOutputHandler; proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); bool exited = proc.WaitForExit(30000); // WaitForExit alone seems to not be entirely reliable while (!exited && ExeRunning("ame-assassin", proc.Id)) { exited = proc.WaitForExit(30000); } using (var log = new StreamWriter("Logs\\Packages.txt", true)) log.Write(output.ToString()); HasFinished = true; InProgress = false; return true; } private StringBuilder output = new StringBuilder(""); private void ProcOutputHandler(object sendingProcess, DataReceivedEventArgs outLine) { var write = outLine.Data == null ? "" : outLine.Data; output.Append(write + Environment.NewLine); if (!write.Equals("Complete!")) Console.WriteLine(write); } private static bool ExeRunning(string name, int id) { try { return Process.GetProcessesByName(name).Any(x => x.Id == id); } catch (Exception) { return false; } } } }