Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 41 additions & 24 deletions source/UninstallTools/Factory/RegistryFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,27 @@ public IList<ApplicationUninstallerEntry> GetUninstallerEntries(ListGenerationPr
{
var uninstallerRegistryKeys = new List<KeyValuePair<RegistryKey, bool>>();

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<RegistryKey, bool>(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<RegistryKey, bool>(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<RegistryKey, bool> data, List<ApplicationUninstallerEntry> state)
{
Expand Down Expand Up @@ -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<KeyValuePair<RegistryKey, bool>> GetParentRegistryKeys()
{
Expand Down Expand Up @@ -366,4 +383,4 @@ private ApplicationUninstallerEntry TryCreateFromRegistry(RegistryKey uninstalle
return tempEntry;
}
}
}
}
61 changes: 37 additions & 24 deletions source/UninstallTools/Factory/SteamFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,29 +48,42 @@ public IList<ApplicationUninstallerEntry> GetUninstallerEntries(
var results = new List<ApplicationUninstallerEntry>();
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
{
Expand Down Expand Up @@ -145,4 +158,4 @@ public IEnumerable<IJunkResult> FindJunk(ApplicationUninstallerEntry target)

#endregion
}
}
}
131 changes: 73 additions & 58 deletions source/UninstallTools/Factory/StoreAppFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -44,60 +45,74 @@ public IList<ApplicationUninstallerEntry> 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;
}
}
}