Files

209 lines
6.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AxCopilot.SDK;
using AxCopilot.Services;
using Microsoft.Win32;
namespace AxCopilot.Handlers;
public class UninstallHandler : IActionHandler
{
private static readonly string[] _regPaths = new string[2] { "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall", "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall" };
private static (DateTime At, List<InstalledApp> Apps)? _cache;
private static readonly TimeSpan CacheTtl = TimeSpan.FromSeconds(30.0);
public string? Prefix => "uninstall";
public PluginMetadata Metadata => new PluginMetadata("Uninstall", "앱 제거 — uninstall 뒤에 앱 이름 입력", "1.0", "AX");
public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
{
string q = query.Trim();
if (string.IsNullOrWhiteSpace(q))
{
return Task.FromResult((IEnumerable<LauncherItem>)new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem("제거할 앱 이름을 입력하세요", "예: uninstall chrome · uninstall office", null, null, null, "\ue74d")));
}
List<InstalledApp> installedApps = GetInstalledApps();
List<InstalledApp> source = (from a in installedApps
where a.Name.Contains(q, StringComparison.OrdinalIgnoreCase) || (a.Publisher?.Contains(q, StringComparison.OrdinalIgnoreCase) ?? false)
orderby a.Name
select a).Take(12).ToList();
if (!source.Any())
{
return Task.FromResult((IEnumerable<LauncherItem>)new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem("검색 결과 없음", "'" + q + "'에 해당하는 설치된 앱이 없습니다", null, null, null, "\ue946")));
}
List<LauncherItem> result = source.Select((InstalledApp a) => new LauncherItem(a.Name, BuildSubtitle(a), null, a, null, "\ue74d")).ToList();
return Task.FromResult((IEnumerable<LauncherItem>)result);
}
public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
{
if (!(item.Data is InstalledApp installedApp))
{
return Task.CompletedTask;
}
if (string.IsNullOrWhiteSpace(installedApp.UninstallString))
{
LogService.Warn("제거 문자열 없음: " + installedApp.Name);
return Task.CompletedTask;
}
try
{
string text = installedApp.UninstallString.Trim();
if (text.StartsWith("msiexec", StringComparison.OrdinalIgnoreCase))
{
string arguments = text.Substring("msiexec".Length).Trim();
Process.Start(new ProcessStartInfo("msiexec.exe", arguments)
{
UseShellExecute = true
});
}
else
{
string fileName;
string arguments2;
if (text.StartsWith('"'))
{
int num = text.IndexOf('"', 1);
fileName = ((num > 0) ? text.Substring(1, num - 1) : text);
object obj;
if (num <= 0)
{
obj = "";
}
else
{
string text2 = text;
int num2 = num + 1;
obj = text2.Substring(num2, text2.Length - num2).Trim();
}
arguments2 = (string)obj;
}
else
{
int num3 = text.IndexOf(' ');
if (num3 > 0)
{
fileName = text.Substring(0, num3);
string text2 = text;
int num2 = num3 + 1;
arguments2 = text2.Substring(num2, text2.Length - num2);
}
else
{
fileName = text;
arguments2 = "";
}
}
ProcessStartInfo startInfo = new ProcessStartInfo(fileName, arguments2)
{
UseShellExecute = true
};
Process.Start(startInfo);
}
}
catch (Exception ex)
{
LogService.Warn("제거 실행 실패 [" + installedApp.Name + "]: " + ex.Message);
}
return Task.CompletedTask;
}
private static string BuildSubtitle(InstalledApp a)
{
List<string> list = new List<string>();
if (!string.IsNullOrWhiteSpace(a.Publisher))
{
list.Add(a.Publisher);
}
if (!string.IsNullOrWhiteSpace(a.Version))
{
list.Add("v" + a.Version);
}
if (!string.IsNullOrWhiteSpace(a.InstallDate))
{
list.Add(a.InstallDate);
}
list.Add("Enter로 제거");
return string.Join(" · ", list);
}
private static List<InstalledApp> GetInstalledApps()
{
if (_cache.HasValue && DateTime.Now - _cache.Value.At < CacheTtl)
{
return _cache.Value.Apps;
}
List<InstalledApp> list = new List<InstalledApp>();
HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
RegistryKey[] array = new RegistryKey[2]
{
Registry.LocalMachine,
Registry.CurrentUser
};
foreach (RegistryKey registryKey in array)
{
string[] regPaths = _regPaths;
foreach (string name in regPaths)
{
try
{
using RegistryKey registryKey2 = registryKey.OpenSubKey(name);
if (registryKey2 == null)
{
continue;
}
string[] subKeyNames = registryKey2.GetSubKeyNames();
foreach (string name2 in subKeyNames)
{
try
{
using RegistryKey registryKey3 = registryKey2.OpenSubKey(name2);
if (registryKey3 != null)
{
string text = registryKey3.GetValue("DisplayName") as string;
string text2 = registryKey3.GetValue("UninstallString") as string;
if (!string.IsNullOrWhiteSpace(text) && !string.IsNullOrWhiteSpace(text2) && (!text.StartsWith("KB", StringComparison.OrdinalIgnoreCase) || text.Length >= 12) && hashSet.Add(text) && (!(registryKey3.GetValue("SystemComponent") is int num) || num != 1))
{
list.Add(new InstalledApp
{
Name = text,
UninstallString = text2,
Publisher = (registryKey3.GetValue("Publisher") as string),
Version = (registryKey3.GetValue("DisplayVersion") as string),
InstallDate = FormatDate(registryKey3.GetValue("InstallDate") as string)
});
}
}
}
catch
{
}
}
}
catch
{
}
}
}
list.Sort((InstalledApp a, InstalledApp b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase));
_cache = (DateTime.Now, list);
return list;
}
private static string? FormatDate(string? raw)
{
if (raw != null && raw.Length == 8 && int.TryParse(raw, out var _))
{
return $"{raw.Substring(0, 4)}-{raw.Substring(4, 2)}-{raw.Substring(6, 2)}";
}
return null;
}
}