Skip to content

Commit 3ab8748

Browse files
Fix WinGet activation fallback order
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 1dfb890 commit 3ab8748

File tree

4 files changed

+97
-36
lines changed

4 files changed

+97
-36
lines changed

src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,39 @@ internal sealed class NativeWinGetHelper : IWinGetManagerHelper
2121
public PackageManager WinGetManager = null!;
2222
public static PackageManager? ExternalWinGetManager;
2323
private readonly WinGet Manager;
24+
private readonly Func<WinGet, IWinGetManagerHelper> _bundledHelperFactory;
2425

2526
public string ActivationMode { get; private set; } = string.Empty;
2627
public string ActivationSource { get; private set; } = string.Empty;
2728
private bool _isBundledActivation;
2829

30+
internal static IReadOnlyList<string> PreferredActivationModes =>
31+
[
32+
"packaged COM registration",
33+
"lower-trust COM registration",
34+
"bundled in-proc COM",
35+
];
36+
2937
public NativeWinGetHelper(WinGet manager)
38+
: this(manager, bundledHelperFactory: null, skipInitialization: false) { }
39+
40+
internal NativeWinGetHelper(
41+
WinGet manager,
42+
Func<WinGet, IWinGetManagerHelper>? bundledHelperFactory,
43+
bool skipInitialization
44+
)
3045
{
3146
Manager = manager;
47+
_bundledHelperFactory =
48+
bundledHelperFactory ?? (static manager => new BundledWinGetHelper(manager));
3249
if (CoreTools.IsAdministrator())
3350
{
3451
Logger.Info(
3552
"Running elevated, WinGet class registration is likely to fail unless using lower trust class registration is allowed in settings"
3653
);
3754
}
3855

39-
if (TryInitializeBundledFactory())
56+
if (skipInitialization)
4057
{
4158
return;
4259
}
@@ -46,36 +63,47 @@ public NativeWinGetHelper(WinGet manager)
4663
return;
4764
}
4865

49-
InitializeLowerTrustFactory();
66+
if (TryInitializeLowerTrustFactory())
67+
{
68+
return;
69+
}
70+
71+
InitializeBundledFactory();
5072
}
5173

52-
private bool TryInitializeBundledFactory()
74+
internal void UseBundledActivationForTesting()
75+
{
76+
_isBundledActivation = true;
77+
ActivationMode = "bundled in-proc COM";
78+
ActivationSource = "test";
79+
}
80+
81+
private bool TryInitializeLowerTrustFactory()
5382
{
5483
try
5584
{
56-
var factory = new WindowsPackageManagerBundledFactory();
85+
var factory = new WindowsPackageManagerStandardFactory(allowLowerTrustRegistration: true);
5786
var winGetManager = factory.CreatePackageManager();
5887
ApplyFactory(
5988
factory,
6089
winGetManager,
61-
"bundled in-proc COM",
62-
factory.LibraryPath,
63-
"Connected to WinGet API using bundled in-proc activation."
90+
"lower-trust COM registration",
91+
"system COM registration (allow lower trust)",
92+
"Connected to WinGet API using lower-trust COM activation."
6493
);
65-
_isBundledActivation = true;
6694
return true;
6795
}
6896
catch (WinGetComActivationException ex)
6997
{
7098
Logger.Warn(
71-
$"Bundled WinGet in-proc activation failed ({ex.HResultHex}: {ex.Reason}), attempting packaged COM activation..."
99+
$"Lower-trust WinGet COM activation failed ({ex.HResultHex}: {ex.Reason}), attempting bundled in-proc activation..."
72100
);
73101
return false;
74102
}
75103
catch (Exception ex)
76104
{
77105
Logger.Warn(
78-
$"Bundled WinGet in-proc activation failed ({ex.Message}), attempting packaged COM activation..."
106+
$"Lower-trust WinGet COM activation failed ({ex.Message}), attempting bundled in-proc activation..."
79107
);
80108
return false;
81109
}
@@ -112,17 +140,18 @@ private bool TryInitializeStandardFactory()
112140
}
113141
}
114142

115-
private void InitializeLowerTrustFactory()
143+
private void InitializeBundledFactory()
116144
{
117-
var factory = new WindowsPackageManagerStandardFactory(allowLowerTrustRegistration: true);
145+
var factory = new WindowsPackageManagerBundledFactory();
118146
var winGetManager = factory.CreatePackageManager();
119147
ApplyFactory(
120148
factory,
121149
winGetManager,
122-
"lower-trust COM registration",
123-
"system COM registration (allow lower trust)",
124-
"Connected to WinGet API using lower-trust COM activation."
150+
"bundled in-proc COM",
151+
factory.LibraryPath,
152+
"Connected to WinGet API using bundled in-proc activation."
125153
);
154+
_isBundledActivation = true;
126155
}
127156

128157
private void ApplyFactory(
@@ -273,7 +302,7 @@ public IReadOnlyList<Package> GetAvailableUpdates_UnSafe()
273302
if (_isBundledActivation)
274303
{
275304
Logger.Info("WinGet is using bundled in-proc COM — falling back to CLI for update detection");
276-
return new BundledWinGetHelper(Manager).GetAvailableUpdates_UnSafe();
305+
return _bundledHelperFactory(Manager).GetAvailableUpdates_UnSafe();
277306
}
278307

279308
var logger = Manager.TaskLogger.CreateNew(LoggableTaskType.ListUpdates);
@@ -344,6 +373,12 @@ var nativePackage in TaskRecycler<IReadOnlyList<CatalogPackage>>.RunOrAttach(
344373

345374
public IReadOnlyList<Package> GetInstalledPackages_UnSafe()
346375
{
376+
if (_isBundledActivation)
377+
{
378+
Logger.Info("WinGet is using bundled in-proc COM — falling back to CLI for installed package detection");
379+
return _bundledHelperFactory(Manager).GetInstalledPackages_UnSafe();
380+
}
381+
347382
var logger = Manager.TaskLogger.CreateNew(LoggableTaskType.ListInstalledPackages);
348383
List<Package> packages = [];
349384
foreach (

src/UniGetUI.PackageEngine.Tests/WinGetManagerTests.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,41 @@ public void GetInstalledPackagesUpdatesNoPackagesFlagForFailureAndRecovery()
130130
PackageAssert.Matches(Assert.Single(packages), "Contoso Tool", "Contoso.Tool", "1.2.3");
131131
}
132132

133+
[Fact]
134+
public void NativeWinGetHelperPrefersSystemComBeforeBundledActivation()
135+
{
136+
Assert.Equal(
137+
["packaged COM registration", "lower-trust COM registration", "bundled in-proc COM"],
138+
NativeWinGetHelper.PreferredActivationModes
139+
);
140+
}
141+
142+
[Fact]
143+
public void NativeWinGetHelperUsesBundledFallbackForInstalledPackagesWhenBundledActivationIsSelected()
144+
{
145+
var manager = new TestableWinGet();
146+
var expectedPackage = new PackageBuilder()
147+
.WithManager(manager)
148+
.WithName("Contoso Tool")
149+
.WithId("Contoso.Tool")
150+
.WithVersion("1.2.3")
151+
.Build();
152+
var bundledFallbackHelper = new TestWinGetManagerHelper
153+
{
154+
GetInstalledPackagesHandler = () => [expectedPackage],
155+
};
156+
var helper = new NativeWinGetHelper(
157+
manager,
158+
bundledHelperFactory: _ => bundledFallbackHelper,
159+
skipInitialization: true
160+
);
161+
helper.UseBundledActivationForTesting();
162+
163+
var packages = helper.GetInstalledPackages_UnSafe();
164+
165+
PackageAssert.Matches(Assert.Single(packages), "Contoso Tool", "Contoso.Tool", "1.2.3");
166+
}
167+
133168
private sealed class TestableWinGet : WinGet
134169
{
135170
public IReadOnlyList<Package> InvokeGetInstalledPackages() => base.GetInstalledPackages_UnSafe();

src/UniGetUI/Pages/SettingsPages/ManagersPages/PackageManager.xaml.cs

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -193,17 +193,18 @@ protected override void OnNavigatedTo(NavigationEventArgs e)
193193
Text =
194194
$"{CoreTools.Translate("Use bundled WinGet instead of system WinGet")} ({CoreTools.Translate("This may help if WinGet packages are not shown")})",
195195
SettingName = Settings.K.ForceLegacyBundledWinGet,
196-
CornerRadius = new CornerRadius(0, 0, 8, 8),
197-
BorderThickness = new Thickness(1, 0, 1, 1),
196+
CornerRadius = new CornerRadius(0),
197+
BorderThickness = new Thickness(1, 0, 1, 0),
198198
};
199199
WinGet_UseBundled.StateChanged += (_, _) => _ = ReloadPackageManager();
200200
ExtraControls.Children.Add(WinGet_UseBundled);
201201

202-
/*CheckboxCard WinGet_EnableTroubleshooter = new()
202+
CheckboxCard WinGet_EnableTroubleshooter = new()
203203
{
204204
Text = CoreTools.Translate("Enable the automatic WinGet troubleshooter"),
205205
SettingName = Settings.K.DisableWinGetMalfunctionDetector,
206-
CornerRadius = new CornerRadius(0),
206+
CornerRadius = new CornerRadius(0, 0, 8, 8),
207+
BorderThickness = new Thickness(1, 0, 1, 1),
207208
};
208209
WinGet_EnableTroubleshooter.StateChanged += (_, _) =>
209210
{
@@ -212,21 +213,6 @@ protected override void OnNavigatedTo(NavigationEventArgs e)
212213
};
213214
ExtraControls.Children.Add(WinGet_EnableTroubleshooter);
214215

215-
CheckboxCard WinGet_EnableTroubleshooter_v2 = new()
216-
{
217-
Text = CoreTools.Translate("Enable an [experimental] improved WinGet troubleshooter"),
218-
SettingName = Settings.K.DisableNewWinGetTroubleshooter,
219-
// CornerRadius = new CornerRadius(0),
220-
CornerRadius = new CornerRadius(0, 0, 8, 8),
221-
BorderThickness = new Thickness(1, 0, 1, 0),
222-
};
223-
WinGet_EnableTroubleshooter_v2.StateChanged += (_, _) =>
224-
{
225-
MainApp.Instance.MainWindow.WinGetWarningBanner.IsOpen = false;
226-
_ = InstalledPackagesLoader.Instance.ReloadPackages();
227-
};
228-
ExtraControls.Children.Add(WinGet_EnableTroubleshooter_v2);*/
229-
230216
/*CheckboxCard WinGet_HideNonApplicableUpdates = new()
231217
{
232218
Text = CoreTools.Translate("Add updates that fail with a 'no applicable update found' to the ignored updates list"),

src/UniGetUI/Pages/SoftwarePages/InstalledPackagesPage.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,12 +309,12 @@ protected override void WhenPackagesLoaded(ReloadReason reason)
309309
}
310310
}
311311

312+
var infoBar = MainApp.Instance.MainWindow.WinGetWarningBanner;
312313
if (
313314
WinGet.NO_PACKAGES_HAVE_BEEN_LOADED
314315
&& !Settings.Get(Settings.K.DisableWinGetMalfunctionDetector)
315316
)
316317
{
317-
var infoBar = MainApp.Instance.MainWindow.WinGetWarningBanner;
318318
infoBar.IsOpen = true;
319319
infoBar.Title = CoreTools.Translate("WinGet malfunction detected");
320320
infoBar.Message = CoreTools.Translate(
@@ -324,6 +324,11 @@ protected override void WhenPackagesLoaded(ReloadReason reason)
324324
infoBar.ActionButton = button;
325325
button.Click += (_, _) => _ = DialogHelper.HandleBrokenWinGet();
326326
}
327+
else
328+
{
329+
infoBar.IsOpen = false;
330+
infoBar.ActionButton = null;
331+
}
327332
}
328333

329334
protected override void WhenShowingContextMenu(IPackage package) =>

0 commit comments

Comments
 (0)