PackageRepository.cs
1 // Copyright (c) Microsoft Corporation 2 // The Microsoft Corporation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Linq; 7 8 using Microsoft.Plugin.Program.Logger; 9 using Microsoft.Plugin.Program.Programs; 10 using Windows.ApplicationModel; 11 using Wox.Infrastructure.Storage; 12 using Wox.Plugin; 13 using Wox.Plugin.Logger; 14 15 namespace Microsoft.Plugin.Program.Storage 16 { 17 /// <summary> 18 /// A repository for storing packaged applications such as UWP apps or appx packaged desktop apps. 19 /// This repository will also monitor for changes to the PackageCatalog and update the repository accordingly 20 /// </summary> 21 internal class PackageRepository : ListRepository<UWPApplication>, IProgramRepository 22 { 23 private readonly IPackageCatalog _packageCatalog; 24 private readonly PluginInitContext _context; 25 26 public PackageRepository(IPackageCatalog packageCatalog, PluginInitContext context) 27 { 28 _packageCatalog = packageCatalog ?? throw new ArgumentNullException(nameof(packageCatalog), "PackageRepository expects an interface to be able to subscribe to package events"); 29 _context = context ?? throw new ArgumentNullException(nameof(context)); 30 31 _packageCatalog.PackageInstalling += OnPackageInstalling; 32 _packageCatalog.PackageUninstalling += OnPackageUninstalling; 33 _packageCatalog.PackageUpdating += OnPackageUpdating; 34 } 35 36 public void OnPackageInstalling(PackageCatalog p, PackageInstallingEventArgs args) 37 { 38 if (args.IsComplete) 39 { 40 AddPackage(args.Package); 41 } 42 } 43 44 public void OnPackageUninstalling(PackageCatalog p, PackageUninstallingEventArgs args) 45 { 46 if (args.Progress == 0) 47 { 48 RemovePackage(args.Package); 49 } 50 } 51 52 public void OnPackageUpdating(PackageCatalog p, PackageUpdatingEventArgs args) 53 { 54 if (args.Progress == 0) 55 { 56 RemovePackage(args.SourcePackage); 57 } 58 59 if (args.IsComplete) 60 { 61 AddPackage(args.TargetPackage); 62 } 63 } 64 65 private void AddPackage(Package package) 66 { 67 var packageWrapper = PackageWrapper.GetWrapperFromPackage(package); 68 if (string.IsNullOrEmpty(packageWrapper.InstalledLocation)) 69 { 70 return; 71 } 72 73 try 74 { 75 var uwp = new UWP(packageWrapper); 76 uwp.InitializeAppInfo(packageWrapper.InstalledLocation); 77 foreach (var app in uwp.Apps) 78 { 79 app.UpdateLogoPath(_context.API.GetCurrentTheme()); 80 Add(app); 81 } 82 } 83 84 // InitializeAppInfo will throw if there is no AppxManifest.xml for the package. 85 // Note there are sometimes multiple packages per product and this doesn't necessarily mean that we haven't found the app. 86 // e.g. "Could not find file 'C:\\Program Files\\WindowsApps\\Microsoft.WindowsTerminalPreview_2020.616.45.0_neutral_~_8wekyb3d8bbwe\\AppxManifest.xml'." 87 catch (System.IO.FileNotFoundException e) 88 { 89 ProgramLogger.Exception(e.Message, e, GetType(), package.InstalledLocation.ToString()); 90 } 91 } 92 93 private void RemovePackage(Package package) 94 { 95 // find apps associated with this package. 96 var packageWrapper = PackageWrapper.GetWrapperFromPackage(package); 97 var uwp = new UWP(packageWrapper); 98 var apps = Items.Where(a => a.Package.Equals(uwp)).ToArray(); 99 100 foreach (var app in apps) 101 { 102 Remove(app); 103 } 104 } 105 106 public void IndexPrograms() 107 { 108 var windows10 = new Version(10, 0); 109 var support = Environment.OSVersion.Version.Major >= windows10.Major; 110 111 var applications = support ? Programs.UWP.All() : Array.Empty<UWPApplication>(); 112 Log.Info($"Indexed {applications.Length} packaged applications", GetType()); 113 SetList(applications); 114 } 115 } 116 }