diff --git a/source/UninstallTools/Factory/RegistryFactory.cs b/source/UninstallTools/Factory/RegistryFactory.cs index 59d2cb21..2ebaaa9e 100644 --- a/source/UninstallTools/Factory/RegistryFactory.cs +++ b/source/UninstallTools/Factory/RegistryFactory.cs @@ -55,18 +55,27 @@ public IList GetUninstallerEntries(ListGenerationPr { var uninstallerRegistryKeys = new List>(); - progressCallback(new ListGenerationProgress(0, -1, Localisation.Progress_Registry_Gathering)); - - foreach (var kvp in GetParentRegistryKeys()) - { - uninstallerRegistryKeys.AddRange( - kvp.Key.GetSubKeyNames() - .Select(subkeyName => OpenSubKeySafe(kvp.Key, subkeyName)) - .Where(subkey => subkey != null) - .Select(subkey => new KeyValuePair(subkey, kvp.Value))); - - kvp.Key.Close(); - } + progressCallback(new ListGenerationProgress(0, -1, Localisation.Progress_Registry_Gathering)); + + foreach (var kvp in GetParentRegistryKeys()) + { + try + { + uninstallerRegistryKeys.AddRange( + kvp.Key.GetSubKeyNames() + .Select(subkeyName => OpenSubKeySafe(kvp.Key, subkeyName)) + .Where(subkey => subkey != null) + .Select(subkey => new KeyValuePair(subkey, kvp.Value))); + } + catch (Exception ex) when (ex is SecurityException or UnauthorizedAccessException or IOException) + { + Trace.WriteLine($@"Failed to enumerate registry key {kvp.Key.Name} - {ex}"); + } + finally + { + kvp.Key.Close(); + } + } void WorkLogic(KeyValuePair data, List state) { @@ -252,17 +261,25 @@ private static bool GetProtectedFlag(RegistryKey uninstallerKey) return Convert.ToInt32(uninstallerKey.GetValue("NoRemove", 0)) != 0; } - private static RegistryKey OpenSubKeySafe(RegistryKey baseKey, string name, bool writable = false) - { - try - { - return baseKey.OpenSubKey(name, writable); - } - catch (SecurityException) - { - return null; - } - } + private static RegistryKey OpenSubKeySafe(RegistryKey baseKey, string name, bool writable = false) + { + try + { + return baseKey.OpenSubKey(name, writable); + } + catch (SecurityException) + { + return null; + } + catch (UnauthorizedAccessException) + { + return null; + } + catch (IOException) + { + return null; + } + } private static IEnumerable> GetParentRegistryKeys() { @@ -366,4 +383,4 @@ private ApplicationUninstallerEntry TryCreateFromRegistry(RegistryKey uninstalle return tempEntry; } } -} \ No newline at end of file +} diff --git a/source/UninstallTools/Factory/SteamFactory.cs b/source/UninstallTools/Factory/SteamFactory.cs index 41ddd49f..1f9f2694 100644 --- a/source/UninstallTools/Factory/SteamFactory.cs +++ b/source/UninstallTools/Factory/SteamFactory.cs @@ -48,29 +48,42 @@ public IList GetUninstallerEntries( var results = new List(); if (!GetSteamInfo(out var steamLocation)) return results; - var output = FactoryTools.StartHelperAndReadOutput(SteamHelperPath, "l /i"); - if (string.IsNullOrEmpty(output)) return results; - - foreach (var data in FactoryTools.ExtractAppDataSetsFromHelperOutput(output)) - { - if (!int.TryParse(data["AppId"], out var appId)) continue; - - var entry = new ApplicationUninstallerEntry - { - DisplayName = data["Name"], - UninstallString = data["UninstallString"], - InstallLocation = data["InstallDirectory"], - UninstallerKind = UninstallerType.Steam, - IsValid = true, - IsOrphaned = true, - RatingId = "Steam App " + appId.ToString("G") - }; - - if (long.TryParse(data["SizeOnDisk"], out var bytes)) - entry.EstimatedSize = FileSize.FromBytes(bytes); - - results.Add(entry); - } + var output = FactoryTools.StartHelperAndReadOutput(SteamHelperPath, "l /i"); + if (string.IsNullOrEmpty(output)) return results; + + foreach (var data in FactoryTools.ExtractAppDataSetsFromHelperOutput(output)) + { + try + { + if (!data.TryGetValue("AppId", out var appIdString) || !int.TryParse(appIdString, out var appId)) + continue; + if (!data.TryGetValue("UninstallString", out var uninstallString) || string.IsNullOrWhiteSpace(uninstallString)) + continue; + + data.TryGetValue("Name", out var name); + data.TryGetValue("InstallDirectory", out var installDirectory); + + var entry = new ApplicationUninstallerEntry + { + DisplayName = name, + UninstallString = uninstallString, + InstallLocation = installDirectory, + UninstallerKind = UninstallerType.Steam, + IsValid = true, + IsOrphaned = true, + RatingId = "Steam App " + appId.ToString("G") + }; + + if (data.TryGetValue("SizeOnDisk", out var sizeOnDisk) && long.TryParse(sizeOnDisk, out var bytes)) + entry.EstimatedSize = FileSize.FromBytes(bytes); + + results.Add(entry); + } + catch (Exception ex) + { + Trace.WriteLine($"[Factory] Failed to parse a Steam entry from helper output: {ex}"); + } + } results.Add(new ApplicationUninstallerEntry { @@ -145,4 +158,4 @@ public IEnumerable FindJunk(ApplicationUninstallerEntry target) #endregion } -} \ No newline at end of file +} diff --git a/source/UninstallTools/Factory/StoreAppFactory.cs b/source/UninstallTools/Factory/StoreAppFactory.cs index 44875d8a..f7dc5bd3 100644 --- a/source/UninstallTools/Factory/StoreAppFactory.cs +++ b/source/UninstallTools/Factory/StoreAppFactory.cs @@ -3,11 +3,12 @@ Apache License Version 2.0 */ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Globalization; -using System.IO; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Globalization; +using System.IO; using System.Linq; using Klocman.Native; using Klocman.Tools; @@ -44,60 +45,74 @@ public IList GetUninstallerEntries( var output = FactoryTools.StartHelperAndReadOutput(HelperPath, "/query"); if (string.IsNullOrEmpty(output)) return results; - var windowsPath = WindowsTools.GetEnvironmentPath(CSIDL.CSIDL_WINDOWS); - - foreach (var data in FactoryTools.ExtractAppDataSetsFromHelperOutput(output)) - { - if (!data.ContainsKey("InstalledLocation") || !Directory.Exists(data["InstalledLocation"])) continue; - - var fullName = data["FullName"]; - var separatorIndex = fullName.IndexOf("_", StringComparison.Ordinal); - var uninstallStr = $"\"{HelperPath}\" /uninstall \"{fullName}\""; - var isProtected = data.ContainsKey("IsProtected") && Convert.ToBoolean(data["IsProtected"], CultureInfo.InvariantCulture); - var result = new ApplicationUninstallerEntry - { - Comment = fullName, - CacheIdOverride = fullName, - RatingId = separatorIndex >= 0 ? fullName.Substring(0, separatorIndex) : fullName, - UninstallString = uninstallStr, - QuietUninstallString = uninstallStr, - RawDisplayName = string.IsNullOrEmpty(data["DisplayName"]) ? fullName : data["DisplayName"], - Publisher = data["PublisherDisplayName"], - IsValid = true, - UninstallerKind = UninstallerType.StoreApp, - InstallLocation = data["InstalledLocation"], - InstallDate = Directory.GetCreationTime(data["InstalledLocation"]), - IsProtected = isProtected, - SystemComponent = isProtected - }; - - if (File.Exists(data["Logo"])) - { - try - { - result.DisplayIcon = data["Logo"]; - result.IconBitmap = DrawingTools.IconFromImage(new Bitmap(data["Logo"])); - } - catch - { - result.DisplayIcon = null; - result.IconBitmap = null; - } - } - - if (result.InstallLocation.StartsWith(windowsPath, StringComparison.InvariantCultureIgnoreCase)) - { - result.SystemComponent = true; - //result.IsProtected = true; - } - - results.Add(result); - } - - return results; - } + var windowsPath = WindowsTools.GetEnvironmentPath(CSIDL.CSIDL_WINDOWS); + + foreach (var data in FactoryTools.ExtractAppDataSetsFromHelperOutput(output)) + { + try + { + if (!data.TryGetValue("InstalledLocation", out var installLocation) || !Directory.Exists(installLocation)) + continue; + if (!data.TryGetValue("FullName", out var fullName) || string.IsNullOrWhiteSpace(fullName)) + continue; + + var separatorIndex = fullName.IndexOf("_", StringComparison.Ordinal); + var uninstallStr = $"\"{HelperPath}\" /uninstall \"{fullName}\""; + var isProtected = data.TryGetValue("IsProtected", out var isProtectedValue) && + Convert.ToBoolean(isProtectedValue, CultureInfo.InvariantCulture); + + data.TryGetValue("DisplayName", out var displayName); + data.TryGetValue("PublisherDisplayName", out var publisher); + + var result = new ApplicationUninstallerEntry + { + Comment = fullName, + CacheIdOverride = fullName, + RatingId = separatorIndex >= 0 ? fullName.Substring(0, separatorIndex) : fullName, + UninstallString = uninstallStr, + QuietUninstallString = uninstallStr, + RawDisplayName = string.IsNullOrEmpty(displayName) ? fullName : displayName, + Publisher = publisher, + IsValid = true, + UninstallerKind = UninstallerType.StoreApp, + InstallLocation = installLocation, + InstallDate = Directory.GetCreationTime(installLocation), + IsProtected = isProtected, + SystemComponent = isProtected + }; + + if (data.TryGetValue("Logo", out var logoPath) && File.Exists(logoPath)) + { + try + { + result.DisplayIcon = logoPath; + result.IconBitmap = DrawingTools.IconFromImage(new Bitmap(logoPath)); + } + catch + { + result.DisplayIcon = null; + result.IconBitmap = null; + } + } + + if (result.InstallLocation.StartsWith(windowsPath, StringComparison.InvariantCultureIgnoreCase)) + { + result.SystemComponent = true; + //result.IsProtected = true; + } + + results.Add(result); + } + catch (Exception ex) + { + Trace.WriteLine($"[Factory] Failed to parse a Store app entry from helper output: {ex}"); + } + } + + return results; + } public bool IsEnabled() => UninstallToolsGlobalConfig.ScanStoreApps; public string DisplayName => Localisation.Progress_AppStores_WinStore; } -} \ No newline at end of file +}