Skip to content

Commit 7f1233f

Browse files
committed
Keep shortcut matching local to context menu feature
1 parent a664d52 commit 7f1233f

4 files changed

Lines changed: 89 additions & 122 deletions

File tree

source/BulkCrapUninstaller/Forms/Windows/MainWindow.ShortcutUninstall.cs

Lines changed: 66 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ Apache License Version 2.0
44
*/
55

66
using System;
7+
using System.Collections.Generic;
78
using System.IO;
9+
using System.Linq;
810
using System.Windows.Forms;
911
using BulkCrapUninstaller.Functions.ApplicationList;
1012
using Klocman.Tools;
@@ -53,26 +55,77 @@ private void ProcessShortcutUninstall(string shortcutPath)
5355
return;
5456
}
5557

56-
var match = ShortcutUninstallMatcher.MatchExecutablePath(_listView.AllUninstallers, executablePath);
57-
switch (match.Status)
58+
var match = ShortcutUninstallMatcher.MatchExecutablePath(_listView.AllUninstallers, executablePath,
59+
out var ambiguous);
60+
if (ambiguous)
5861
{
59-
case ShortcutUninstallMatchStatus.NotFound:
60-
ShowShortcutUninstallError("No installed application could be identified from this shortcut target.");
61-
return;
62-
case ShortcutUninstallMatchStatus.Ambiguous:
63-
ShowShortcutUninstallError("More than one installed application matches this shortcut target. No application was uninstalled.");
64-
return;
65-
case ShortcutUninstallMatchStatus.Unique:
66-
_appUninstaller.RunUninstall(new[] {match.Entry}, _listView.AllUninstallers, false);
67-
return;
68-
default:
69-
throw new ArgumentOutOfRangeException();
62+
ShowShortcutUninstallError("More than one installed application matches this shortcut target. No application was uninstalled.");
63+
return;
64+
}
65+
66+
if (match == null)
67+
{
68+
ShowShortcutUninstallError("No installed application could be identified from this shortcut target.");
69+
return;
7070
}
71+
72+
_appUninstaller.RunUninstall(new[] {match}, _listView.AllUninstallers, false);
7173
}
7274

7375
private void ShowShortcutUninstallError(string message)
7476
{
7577
MessageBox.Show(this, message, "BCUninstaller", MessageBoxButtons.OK, MessageBoxIcon.Error);
7678
}
7779
}
80+
81+
internal static class ShortcutUninstallMatcher
82+
{
83+
internal static ApplicationUninstallerEntry MatchExecutablePath(
84+
IEnumerable<ApplicationUninstallerEntry> entries, string executablePath, out bool ambiguous)
85+
{
86+
ambiguous = false;
87+
if (entries == null || string.IsNullOrWhiteSpace(executablePath))
88+
return null;
89+
90+
var candidates = entries as IList<ApplicationUninstallerEntry> ?? new List<ApplicationUninstallerEntry>(entries);
91+
92+
var match = FindUnique(candidates,
93+
entry => PathTools.PathsEqual(entry?.UninstallerFullFilename, executablePath), out ambiguous);
94+
if (match != null || ambiguous)
95+
return match;
96+
97+
match = FindUnique(candidates,
98+
entry => entry?.GetSortedExecutables()
99+
.Any(path => PathTools.PathsEqual(path, executablePath)) == true, out ambiguous);
100+
if (match != null || ambiguous)
101+
return match;
102+
103+
return FindUnique(candidates,
104+
entry => PathTools.SubPathIsInsideBasePath(entry?.InstallLocation, executablePath, true, false),
105+
out ambiguous);
106+
}
107+
108+
private static ApplicationUninstallerEntry FindUnique(IEnumerable<ApplicationUninstallerEntry> entries,
109+
Func<ApplicationUninstallerEntry, bool> predicate, out bool ambiguous)
110+
{
111+
ambiguous = false;
112+
ApplicationUninstallerEntry match = null;
113+
114+
foreach (var entry in entries)
115+
{
116+
if (!predicate(entry))
117+
continue;
118+
119+
if (match != null)
120+
{
121+
ambiguous = true;
122+
return null;
123+
}
124+
125+
match = entry;
126+
}
127+
128+
return match;
129+
}
130+
}
78131
}

source/BulkCrapUninstallerTests/ShortcutUninstallMatcherTests.cs

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections.Generic;
2+
using BulkCrapUninstaller.Forms;
23
using Microsoft.VisualStudio.TestTools.UnitTesting;
34
using UninstallTools;
45

@@ -17,10 +18,11 @@ public void MatchExecutablePathReturnsUniqueExactUninstallerMatch()
1718
CreateEntry("C:\\Tools\\Other\\uninstall.exe", "C:\\Tools\\Other")
1819
};
1920

20-
var result = ShortcutUninstallMatcher.MatchExecutablePath(entries, "c:\\tools\\widget\\UNINSTALL.EXE");
21+
var result = ShortcutUninstallMatcher.MatchExecutablePath(entries, "c:\\tools\\widget\\UNINSTALL.EXE",
22+
out var ambiguous);
2123

22-
Assert.AreEqual(ShortcutUninstallMatchStatus.Unique, result.Status);
23-
Assert.AreSame(expected, result.Entry);
24+
Assert.IsFalse(ambiguous);
25+
Assert.AreSame(expected, result);
2426
}
2527

2628
[TestMethod]
@@ -30,10 +32,10 @@ public void MatchExecutablePathReturnsUniqueSortedExecutableMatch()
3032
expected.SortedExecutables = new[] {"C:\\Launchers\\Widget.exe"};
3133

3234
var result = ShortcutUninstallMatcher.MatchExecutablePath(
33-
new List<ApplicationUninstallerEntry> {expected}, "c:\\launchers\\WIDGET.EXE");
35+
new List<ApplicationUninstallerEntry> {expected}, "c:\\launchers\\WIDGET.EXE", out var ambiguous);
3436

35-
Assert.AreEqual(ShortcutUninstallMatchStatus.Unique, result.Status);
36-
Assert.AreSame(expected, result.Entry);
37+
Assert.IsFalse(ambiguous);
38+
Assert.AreSame(expected, result);
3739
}
3840

3941
[TestMethod]
@@ -42,10 +44,10 @@ public void MatchExecutablePathReturnsUniqueEntryForExecutableInsideInstallLocat
4244
var expected = CreateEntry("C:\\Apps\\Widget\\uninstall.exe", "C:\\Apps\\Widget");
4345

4446
var result = ShortcutUninstallMatcher.MatchExecutablePath(
45-
new List<ApplicationUninstallerEntry> {expected}, "C:\\Apps\\Widget\\bin\\Widget.exe");
47+
new List<ApplicationUninstallerEntry> {expected}, "C:\\Apps\\Widget\\bin\\Widget.exe", out var ambiguous);
4648

47-
Assert.AreEqual(ShortcutUninstallMatchStatus.Unique, result.Status);
48-
Assert.AreSame(expected, result.Entry);
49+
Assert.IsFalse(ambiguous);
50+
Assert.AreSame(expected, result);
4951
}
5052

5153
[TestMethod]
@@ -55,10 +57,10 @@ public void MatchExecutablePathPrefersExactUninstallerMatchOverInstallLocationMa
5557
var contained = CreateEntry("C:\\Apps\\Contained\\uninstall.exe", "C:\\Shared");
5658

5759
var result = ShortcutUninstallMatcher.MatchExecutablePath(
58-
new List<ApplicationUninstallerEntry> {exact, contained}, "C:\\Shared\\Tool.exe");
60+
new List<ApplicationUninstallerEntry> {exact, contained}, "C:\\Shared\\Tool.exe", out var ambiguous);
5961

60-
Assert.AreEqual(ShortcutUninstallMatchStatus.Unique, result.Status);
61-
Assert.AreSame(exact, result.Entry);
62+
Assert.IsFalse(ambiguous);
63+
Assert.AreSame(exact, result);
6264
}
6365

6466
[TestMethod]
@@ -70,10 +72,11 @@ public void MatchExecutablePathReturnsAmbiguousForSharedInstallLocation()
7072
CreateEntry("C:\\Apps\\Two\\uninstall.exe", "C:\\Shared")
7173
};
7274

73-
var result = ShortcutUninstallMatcher.MatchExecutablePath(entries, "C:\\Shared\\Tool.exe");
75+
var result = ShortcutUninstallMatcher.MatchExecutablePath(entries, "C:\\Shared\\Tool.exe",
76+
out var ambiguous);
7477

75-
Assert.AreEqual(ShortcutUninstallMatchStatus.Ambiguous, result.Status);
76-
Assert.IsNull(result.Entry);
78+
Assert.IsTrue(ambiguous);
79+
Assert.IsNull(result);
7780
}
7881

7982
[TestMethod]
@@ -85,10 +88,11 @@ public void MatchExecutablePathReturnsNotFoundWhenNoPathEvidenceExists()
8588
new ApplicationUninstallerEntry {DisplayName = "Incomplete entry"}
8689
};
8790

88-
var result = ShortcutUninstallMatcher.MatchExecutablePath(entries, "C:\\Apps\\Unknown\\Unknown.exe");
91+
var result = ShortcutUninstallMatcher.MatchExecutablePath(entries, "C:\\Apps\\Unknown\\Unknown.exe",
92+
out var ambiguous);
8993

90-
Assert.AreEqual(ShortcutUninstallMatchStatus.NotFound, result.Status);
91-
Assert.IsNull(result.Entry);
94+
Assert.IsFalse(ambiguous);
95+
Assert.IsNull(result);
9296
}
9397

9498
private static ApplicationUninstallerEntry CreateEntry(string uninstallerPath, string installLocation)

source/UninstallTools/ShortcutUninstallSupport.cs

Lines changed: 0 additions & 89 deletions
This file was deleted.

source/UninstallTools/UninstallTools.csproj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
</ItemGroup>
1212

1313
<ItemGroup>
14-
<InternalsVisibleTo Include="BCUninstaller" />
1514
<InternalsVisibleTo Include="BulkCrapUninstallerTests" />
1615
</ItemGroup>
1716

@@ -22,7 +21,7 @@
2221
</ItemGroup>
2322

2423
<ItemGroup>
25-
<COMReference Include="Scripting">
24+
<COMReference Include="Scripting">
2625
<Guid>{420B2830-E718-11CF-893D-00A0C9054228}</Guid>
2726
<VersionMajor>1</VersionMajor>
2827
<VersionMinor>0</VersionMinor>

0 commit comments

Comments
 (0)