Flow.Launcher/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs

732 lines
30 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Principal;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
using Windows.ApplicationModel;
2016-08-19 22:24:21 +00:00
using Windows.Management.Deployment;
2020-04-21 09:12:17 +00:00
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Plugin.Program.Logger;
2021-02-01 11:59:56 +00:00
using Flow.Launcher.Plugin.SharedModels;
using System.Threading.Channels;
2022-11-28 07:51:28 +00:00
using System.Xml;
2022-11-28 11:06:16 +00:00
using Windows.ApplicationModel.Core;
2020-04-21 09:12:17 +00:00
namespace Flow.Launcher.Plugin.Program.Programs
{
2017-01-13 01:21:00 +00:00
[Serializable]
public class UWP
{
public string Name { get; }
public string FullName { get; }
public string FamilyName { get; }
public string Location { get; set; }
2022-11-28 07:51:28 +00:00
public Application[] Apps { get; set; } = Array.Empty<Application>();
public UWP(Package package)
{
2017-01-13 01:21:00 +00:00
Location = package.InstalledLocation.Path;
Name = package.Id.Name;
FullName = package.Id.FullName;
FamilyName = package.Id.FamilyName;
2022-11-28 07:51:28 +00:00
}
2022-11-28 17:22:13 +00:00
public void InitAppsInPackage(Package package)
2022-11-28 07:51:28 +00:00
{
var applist = new List<Application>();
2022-11-28 14:01:16 +00:00
// WinRT
var appListEntries = package.GetAppListEntries();
foreach (var app in appListEntries)
2022-11-28 07:51:28 +00:00
{
2022-11-28 14:01:16 +00:00
try
2022-11-28 07:51:28 +00:00
{
2022-11-28 14:01:16 +00:00
var tmp = new Application(app, this);
applist.Add(tmp);
}
catch (Exception e)
{
2022-11-28 17:46:48 +00:00
ProgramLogger.LogException($"|UWP|InitAppsInPackage|{Location}" +
"|Unexpected exception occurs when trying to construct a Application from package"
+ $"{FullName} from location {Location}", e);
2022-11-28 07:51:28 +00:00
}
2022-11-28 14:01:16 +00:00
}
Apps = applist.ToArray();
2022-11-28 10:46:48 +00:00
2022-11-28 14:01:16 +00:00
try
{
2022-11-28 10:46:48 +00:00
var xmlDoc = GetManifestXml();
if (xmlDoc == null)
{
return;
}
var xmlRoot = xmlDoc.DocumentElement;
2022-11-28 14:01:16 +00:00
var packageVersion = GetPackageVersionFromManifest(xmlRoot);
2022-11-29 04:30:36 +00:00
if (!smallLogoNameFromVersion.TryGetValue(packageVersion, out string logoName) ||
!bigLogoNameFromVersion.TryGetValue(packageVersion, out string bigLogoName))
2022-11-28 17:46:48 +00:00
{
return;
}
2022-11-28 18:14:43 +00:00
2022-11-28 10:46:48 +00:00
var namespaceManager = new XmlNamespaceManager(xmlDoc.NameTable);
2022-11-29 09:49:36 +00:00
namespaceManager.AddNamespace("d", "http://schemas.microsoft.com/appx/manifest/foundation/windows10"); // still need a name
2022-11-28 10:46:48 +00:00
namespaceManager.AddNamespace("rescap", "http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities");
namespaceManager.AddNamespace("uap10", "http://schemas.microsoft.com/appx/manifest/uap/windows10/10");
2022-11-29 09:49:36 +00:00
var allowElevationNode = xmlRoot.SelectSingleNode("//rescap:Capability[@Name='allowElevation']", namespaceManager);
2022-11-28 10:46:48 +00:00
bool packageCanElevate = allowElevationNode != null;
2022-11-29 09:49:36 +00:00
var appsNode = xmlRoot.SelectSingleNode("d:Applications", namespaceManager);
2022-11-28 10:46:48 +00:00
foreach (var app in Apps)
{
// According to https://learn.microsoft.com/windows/apps/desktop/modernize/grant-identity-to-nonpackaged-apps#create-a-package-manifest-for-the-sparse-package
// and https://learn.microsoft.com/uwp/schemas/appxpackage/uapmanifestschema/element-application#attributes
var id = app.UserModelId.Split('!')[1];
2022-11-29 09:49:36 +00:00
var appNode = appsNode?.SelectSingleNode($"d:Application[@Id='{id}']", namespaceManager);
2022-11-28 10:46:48 +00:00
if (appNode != null)
{
2022-11-29 09:49:36 +00:00
app.CanRunElevated = packageCanElevate || Application.IfAppCanRunElevated(appNode);
2022-11-28 17:46:48 +00:00
2022-11-29 09:49:36 +00:00
// local name to fit all versions
var visualElement = appNode.SelectSingleNode($"*[local-name()='VisualElements']", namespaceManager);
2022-11-28 18:06:11 +00:00
var logoUri = visualElement?.Attributes[logoName]?.Value;
2022-11-29 09:50:49 +00:00
app.LogoPath = app.LogoPathFromUri(logoUri, (64, 64));
// use small logo or may have a big margin
var previewUri = visualElement?.Attributes[logoName]?.Value;
app.PreviewImagePath = app.LogoPathFromUri(previewUri, (256, 256));
2022-11-28 10:46:48 +00:00
}
}
2022-11-28 07:51:28 +00:00
}
catch (Exception e)
{
2022-11-28 17:46:48 +00:00
ProgramLogger.LogException($"|UWP|InitAppsInPackage|{Location}" +
"|Unexpected exception occurs when trying to construct a Application from package"
+ $"{FullName} from location {Location}", e);
2022-11-28 07:51:28 +00:00
}
}
private XmlDocument GetManifestXml()
{
var manifest = Path.Combine(Location, "AppxManifest.xml");
try
{
var file = File.ReadAllText(manifest);
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(file);
return xmlDoc;
}
catch (FileNotFoundException e)
{
ProgramLogger.LogException("UWP", "GetManifestXml", $"{Location}", "AppxManifest.xml not found.", e);
return null;
}
catch (Exception e)
{
ProgramLogger.LogException("UWP", "GetManifestXml", $"{Location}", "An unexpected error occured and unable to parse AppxManifest.xml", e);
return null;
}
}
2022-11-29 09:49:36 +00:00
private PackageVersion GetPackageVersionFromManifest(XmlNode xmlRoot)
{
2022-11-28 14:01:16 +00:00
if (xmlRoot != null)
{
2022-11-28 14:01:16 +00:00
var namespaces = xmlRoot.Attributes;
foreach (XmlAttribute ns in namespaces)
{
if (versionFromNamespace.TryGetValue(ns.Value, out var packageVersion))
{
return packageVersion;
}
}
ProgramLogger.LogException($"|UWP|GetPackageVersionFromManifest|{Location}" +
2022-11-28 17:46:48 +00:00
"|Trying to get the package version of the UWP program, but an unknown UWP appmanifest version in package "
+ $"{FullName} from location {Location}", new FormatException());
2022-11-28 14:01:16 +00:00
return PackageVersion.Unknown;
}
else
{
2022-11-28 14:01:16 +00:00
ProgramLogger.LogException($"|UWP|GetPackageVersionFromManifest|{Location}" +
2022-11-28 17:46:48 +00:00
"|Can't parse AppManifest.xml of package "
+ $"{FullName} from location {Location}", new ArgumentNullException(nameof(xmlRoot)));
2022-11-28 14:01:16 +00:00
return PackageVersion.Unknown;
}
}
2022-11-28 14:01:16 +00:00
private static readonly Dictionary<string, PackageVersion> versionFromNamespace = new()
{
{
"http://schemas.microsoft.com/appx/manifest/foundation/windows10", PackageVersion.Windows10
},
{
"http://schemas.microsoft.com/appx/2013/manifest", PackageVersion.Windows81
},
{
"http://schemas.microsoft.com/appx/2010/manifest", PackageVersion.Windows8
},
2022-11-28 14:01:16 +00:00
};
2022-11-29 04:30:36 +00:00
private static readonly Dictionary<PackageVersion, string> smallLogoNameFromVersion = new()
2022-11-28 14:01:16 +00:00
{
{
2022-11-28 14:01:16 +00:00
PackageVersion.Windows10, "Square44x44Logo"
},
{
PackageVersion.Windows81, "Square30x30Logo"
},
{
PackageVersion.Windows8, "SmallLogo"
},
};
2022-11-29 04:30:36 +00:00
private static readonly Dictionary<PackageVersion, string> bigLogoNameFromVersion = new()
{
{
2022-12-07 06:56:34 +00:00
PackageVersion.Windows10, "Square150x150Logo"
2022-11-29 04:30:36 +00:00
},
{
2022-12-07 06:56:34 +00:00
PackageVersion.Windows81, "Square150x150Logo"
2022-11-29 04:30:36 +00:00
},
{
PackageVersion.Windows8, "Logo"
},
};
public static Application[] All(Settings settings)
{
var support = SupportUWP();
2022-12-20 11:48:10 +00:00
if (support && settings.EnableUWP)
{
2017-04-01 18:15:23 +00:00
var applications = CurrentUserPackages().AsParallel().SelectMany(p =>
{
UWP u;
try
{
u = new UWP(p);
2022-11-28 17:22:13 +00:00
u.InitAppsInPackage(p);
2017-04-01 18:15:23 +00:00
}
#if !DEBUG
2017-04-01 18:15:23 +00:00
catch (Exception e)
{
2022-08-10 18:52:16 +00:00
ProgramLogger.LogException($"|UWP|All|{p.InstalledLocation}|An unexpected error occured and unable to convert Package to UWP for {p.Id.FullName}", e);
return Array.Empty<Application>();
2017-04-01 18:15:23 +00:00
}
#endif
#if DEBUG //make developer aware and implement handling
2019-11-16 00:37:01 +00:00
catch
{
2019-11-16 00:37:01 +00:00
throw;
}
#endif
2017-04-01 18:15:23 +00:00
return u.Apps;
}).ToArray();
var updatedListWithoutDisabledApps = applications
.Where(t1 => !Main._settings.DisabledProgramSources
2022-10-24 17:13:36 +00:00
.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier));
return updatedListWithoutDisabledApps.ToArray();
2016-08-20 00:17:28 +00:00
}
else
{
2022-10-21 10:35:10 +00:00
return Array.Empty<Application>();
2016-08-20 00:17:28 +00:00
}
}
public static bool SupportUWP()
{
var windows10 = new Version(10, 0);
var support = Environment.OSVersion.Version.Major >= windows10.Major;
return support;
}
private static IEnumerable<Package> CurrentUserPackages()
{
2017-04-01 18:15:23 +00:00
var u = WindowsIdentity.GetCurrent().User;
2017-04-01 18:15:23 +00:00
if (u != null)
{
2017-04-01 18:15:23 +00:00
var id = u.Value;
2021-02-11 19:18:38 +00:00
PackageManager m;
try
{
m = new PackageManager();
}
catch
{
2021-02-23 19:34:09 +00:00
// Bug from https://github.com/microsoft/CsWinRT, using Microsoft.Windows.SDK.NET.Ref 10.0.19041.0.
// Only happens on the first time, so a try catch can fix it.
2021-02-11 19:18:38 +00:00
m = new PackageManager();
}
2017-04-01 18:15:23 +00:00
var ps = m.FindPackagesForUser(id);
ps = ps.Where(p =>
{
2019-11-01 19:44:55 +00:00
try
{
var f = p.IsFramework;
var d = p.IsDevelopmentMode;
var path = p.InstalledLocation.Path;
2022-11-28 17:22:13 +00:00
return !f && !d && !string.IsNullOrEmpty(path);
2019-11-01 19:44:55 +00:00
}
catch (Exception e)
{
2022-11-28 17:22:13 +00:00
ProgramLogger.LogException("UWP", "CurrentUserPackages", $"{id}", "An unexpected error occured and "
+ $"unable to verify if package is valid", e);
2019-11-01 19:44:55 +00:00
return false;
}
2017-04-01 18:15:23 +00:00
});
return ps;
}
else
{
2022-10-21 10:35:10 +00:00
return Array.Empty<Package>();
}
}
private static Channel<byte> PackageChangeChannel = Channel.CreateBounded<byte>(1);
public static async Task WatchPackageChange()
{
if (Environment.OSVersion.Version.Major >= 10)
{
var catalog = PackageCatalog.OpenForCurrentUser();
catalog.PackageInstalling += (_, args) =>
{
if (args.IsComplete)
PackageChangeChannel.Writer.TryWrite(default);
};
catalog.PackageUninstalling += (_, args) =>
2022-01-08 22:03:53 +00:00
{
if (args.IsComplete)
PackageChangeChannel.Writer.TryWrite(default);
2022-01-08 22:03:53 +00:00
};
catalog.PackageUpdating += (_, args) =>
{
if (args.IsComplete)
PackageChangeChannel.Writer.TryWrite(default);
};
while (await PackageChangeChannel.Reader.WaitToReadAsync().ConfigureAwait(false))
{
await Task.Delay(3000).ConfigureAwait(false);
PackageChangeChannel.Reader.TryRead(out _);
await Task.Run(Main.IndexUwpPrograms);
}
2022-11-28 11:06:16 +00:00
}
}
public override string ToString()
{
return FamilyName;
}
public override bool Equals(object obj)
{
2019-11-16 00:37:01 +00:00
if (obj is UWP uwp)
{
return FamilyName.Equals(uwp.FamilyName);
}
else
{
return false;
}
}
public override int GetHashCode()
{
return FamilyName.GetHashCode();
}
2017-01-13 01:21:00 +00:00
[Serializable]
public class Application : IProgram
{
2022-11-14 16:07:12 +00:00
private string _uid = string.Empty;
public string UniqueIdentifier { get => _uid; set => _uid = value == null ? string.Empty : value.ToLowerInvariant(); }
2022-11-28 14:13:55 +00:00
public string DisplayName { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string UserModelId { get; set; } = string.Empty;
2022-11-29 04:12:09 +00:00
//public string BackgroundColor { get; set; } = string.Empty; // preserve for future use
public string Name => DisplayName;
2022-11-28 14:13:55 +00:00
public string Location { get; set; } = string.Empty;
2022-11-28 14:08:21 +00:00
public bool Enabled { get; set; } = false;
2022-11-28 07:51:28 +00:00
public bool CanRunElevated { get; set; } = false;
2022-11-28 14:01:16 +00:00
public string LogoPath { get; set; } = string.Empty;
2022-11-29 04:30:36 +00:00
public string PreviewImagePath { get; set; } = string.Empty;
2022-11-28 07:51:28 +00:00
2022-11-28 11:06:16 +00:00
public Application(AppListEntry appListEntry, UWP package)
2022-11-28 10:43:56 +00:00
{
UserModelId = appListEntry.AppUserModelId;
UniqueIdentifier = appListEntry.AppUserModelId;
DisplayName = appListEntry.DisplayInfo.DisplayName;
Description = appListEntry.DisplayInfo.Description;
2022-11-28 11:06:16 +00:00
Location = package.Location;
2022-11-28 10:43:56 +00:00
Enabled = true;
}
public Result Result(string query, IPublicAPI api)
{
string title;
MatchResult matchResult;
// We suppose Name won't be null
if (!Main._settings.EnableDescription || Description == null || Name.StartsWith(Description))
{
title = Name;
matchResult = StringMatcher.FuzzySearch(query, title);
}
else if (Description.StartsWith(Name))
{
title = Description;
matchResult = StringMatcher.FuzzySearch(query, Description);
}
else
{
title = $"{Name}: {Description}";
var nameMatch = StringMatcher.FuzzySearch(query, Name);
var desciptionMatch = StringMatcher.FuzzySearch(query, Description);
if (desciptionMatch.Score > nameMatch.Score)
{
for (int i = 0; i < desciptionMatch.MatchData.Count; i++)
{
desciptionMatch.MatchData[i] += Name.Length + 2; // 2 is ": "
}
matchResult = desciptionMatch;
}
else matchResult = nameMatch;
}
2021-02-02 09:28:52 +00:00
if (!matchResult.Success)
return null;
2019-11-28 23:38:50 +00:00
var result = new Result
{
Title = title,
2022-11-28 11:06:16 +00:00
SubTitle = Main._settings.HideAppsPath ? string.Empty : Location,
2022-11-28 14:55:10 +00:00
IcoPath = LogoPath,
2022-12-05 08:01:20 +00:00
Preview = new Result.PreviewInfo
{
IsMedia = false,
PreviewImagePath = PreviewImagePath,
Description = Description
},
Score = matchResult.Score,
TitleHighlightData = matchResult.MatchData,
ContextData = this,
Action = e =>
{
var elevated = (
e.SpecialKeyState.CtrlPressed &&
e.SpecialKeyState.ShiftPressed &&
!e.SpecialKeyState.AltPressed &&
!e.SpecialKeyState.WinPressed
);
2022-11-28 17:02:53 +00:00
bool shouldRunElevated = elevated && CanRunElevated;
_ = Task.Run(() => Launch(shouldRunElevated)).ConfigureAwait(false);
if (elevated && !shouldRunElevated)
{
2022-11-29 10:13:55 +00:00
var title = api.GetTranslation("flowlauncher_plugin_program_disable_dlgtitle_error");
2022-11-28 17:02:53 +00:00
var message = api.GetTranslation("flowlauncher_plugin_program_run_as_administrator_not_supported_message");
api.ShowMsg(title, message, string.Empty);
}
return true;
}
};
return result;
}
public List<Result> ContextMenus(IPublicAPI api)
{
var contextMenus = new List<Result>
{
new Result
{
2020-04-21 12:54:41 +00:00
Title = api.GetTranslation("flowlauncher_plugin_program_open_containing_folder"),
Action = _ =>
{
2022-11-28 11:06:16 +00:00
Main.Context.API.OpenDirectory(Location);
return true;
},
IcoPath = "Images/folder.png"
}
};
if (CanRunElevated)
{
contextMenus.Add(new Result
{
Title = api.GetTranslation("flowlauncher_plugin_program_run_as_administrator"),
Action = _ =>
{
2022-11-28 17:02:53 +00:00
Task.Run(() => Launch(true)).ConfigureAwait(false);
return true;
},
IcoPath = "Images/cmd.png"
});
}
return contextMenus;
}
2022-11-28 18:14:43 +00:00
private void Launch(bool elevated = false)
{
2022-11-28 17:02:53 +00:00
string command = "shell:AppsFolder\\" + UserModelId;
command = Environment.ExpandEnvironmentVariables(command.Trim());
var info = new ProcessStartInfo(command)
{
2022-11-28 11:06:16 +00:00
UseShellExecute = true,
2022-11-28 17:02:53 +00:00
Verb = elevated ? "runas" : ""
};
Main.StartProcess(Process.Start, info);
}
2022-11-29 09:49:36 +00:00
internal static bool IfAppCanRunElevated(XmlNode appNode)
2022-11-28 10:43:56 +00:00
{
// According to https://learn.microsoft.com/windows/apps/desktop/modernize/grant-identity-to-nonpackaged-apps#create-a-package-manifest-for-the-sparse-package
// and https://learn.microsoft.com/uwp/schemas/appxpackage/uapmanifestschema/element-application#attributes
2022-11-29 09:49:36 +00:00
return appNode?.Attributes["EntryPoint"]?.Value == "Windows.FullTrustApplication" ||
appNode?.Attributes["uap10:TrustLevel"]?.Value == "mediumIL";
2022-11-28 10:43:56 +00:00
}
2022-11-29 04:30:36 +00:00
internal string LogoPathFromUri(string uri, (int, int) desiredSize)
2016-11-29 01:46:29 +00:00
{
// all https://msdn.microsoft.com/windows/uwp/controls-and-patterns/tiles-and-notifications-app-assets
// windows 10 https://msdn.microsoft.com/en-us/library/windows/apps/dn934817.aspx
// windows 8.1 https://msdn.microsoft.com/en-us/library/windows/apps/hh965372.aspx#target_size
// windows 8 https://msdn.microsoft.com/en-us/library/windows/apps/br211475.aspx
2022-11-28 14:01:16 +00:00
if (string.IsNullOrWhiteSpace(uri))
{
ProgramLogger.LogException($"|UWP|LogoPathFromUri|{Location}" +
$"|{UserModelId} 's logo uri is null or empty: {Location}", new ArgumentException("uri"));
return string.Empty;
2022-11-28 14:01:16 +00:00
}
2022-11-28 11:06:16 +00:00
string path = Path.Combine(Location, uri);
2022-10-19 18:30:58 +00:00
2022-11-29 04:30:36 +00:00
var pxCount = desiredSize.Item1 * desiredSize.Item2;
var logoPath = TryToFindLogo(uri, path, pxCount);
if (logoPath == string.Empty)
2016-11-29 01:46:29 +00:00
{
2022-11-28 11:06:16 +00:00
var tmp = Path.Combine(Location, "Assets", uri);
2022-11-28 09:48:27 +00:00
if (!path.Equals(tmp, StringComparison.OrdinalIgnoreCase))
{
2022-11-28 11:06:16 +00:00
// TODO: Don't know why, just keep it at the moment
// Maybe on older version of Windows 10?
// for C:\Windows\MiracastView etc
2022-11-29 04:30:36 +00:00
return TryToFindLogo(uri, tmp, pxCount);
2022-11-28 09:48:27 +00:00
}
2016-11-29 01:46:29 +00:00
}
return logoPath;
2016-11-29 01:46:29 +00:00
2022-11-29 04:30:36 +00:00
string TryToFindLogo(string uri, string path, int px)
2016-11-29 01:46:29 +00:00
{
var extension = Path.GetExtension(path);
if (extension != null)
{
2022-10-28 08:36:44 +00:00
//if (File.Exists(path))
//{
// return path; // shortcut, avoid enumerating files
//}
2016-11-29 01:46:29 +00:00
var logoNamePrefix = Path.GetFileNameWithoutExtension(uri); // e.g Square44x44
var logoDir = Path.GetDirectoryName(path); // e.g ..\..\Assets
2022-11-28 18:06:11 +00:00
if (String.IsNullOrEmpty(logoNamePrefix) || !Directory.Exists(logoDir))
{
// Known issue: Edge always triggers it since logo is not at uri
2022-11-28 11:06:16 +00:00
ProgramLogger.LogException($"|UWP|LogoPathFromUri|{Location}" +
$"|{UserModelId} can't find logo uri for {uri} in package location (logo name or directory not found): {Location}", new FileNotFoundException());
return string.Empty;
}
var logos = Directory.EnumerateFiles(logoDir, $"{logoNamePrefix}*{extension}");
// Currently we don't care which one to choose
// Just ignore all qualifiers
// select like logo.[xxx_yyy].png
// https://learn.microsoft.com/en-us/windows/uwp/app-resources/tailor-resources-lang-scale-contrast
// todo select from file name like pt run
2022-10-28 08:36:44 +00:00
var selected = logos.FirstOrDefault();
2022-10-31 12:03:34 +00:00
var closest = selected;
int min = int.MaxValue;
2022-11-28 11:06:16 +00:00
foreach (var logo in logos)
{
2022-10-28 08:36:44 +00:00
var imageStream = File.OpenRead(logo);
var decoder = BitmapDecoder.Create(imageStream, BitmapCreateOptions.IgnoreColorProfile, BitmapCacheOption.None);
var height = decoder.Frames[0].PixelHeight;
var width = decoder.Frames[0].PixelWidth;
2022-11-29 04:30:36 +00:00
int pixelCountDiff = Math.Abs(height * width - px);
2022-11-28 11:06:16 +00:00
if (pixelCountDiff < min)
{
2022-11-29 04:30:36 +00:00
// try to find the closest to desired size
2022-10-31 12:03:34 +00:00
closest = logo;
if (pixelCountDiff == 0)
2022-11-29 04:30:36 +00:00
break; // found
2022-10-31 12:03:34 +00:00
min = pixelCountDiff;
}
}
2022-10-31 12:03:34 +00:00
selected = closest;
if (!string.IsNullOrEmpty(selected))
{
return selected;
}
else
{
2022-11-28 11:06:16 +00:00
ProgramLogger.LogException($"|UWP|LogoPathFromUri|{Location}" +
$"|{UserModelId} can't find logo uri for {uri} in package location (can't find specified logo): {Location}", new FileNotFoundException());
return string.Empty;
}
2016-11-29 01:46:29 +00:00
}
else
{
2022-11-28 11:06:16 +00:00
ProgramLogger.LogException($"|UWP|LogoPathFromUri|{Location}" +
$"|Unable to find extension from {uri} for {UserModelId} " +
2022-11-28 11:06:16 +00:00
$"in package location {Location}", new FileNotFoundException());
2016-11-29 01:46:29 +00:00
return string.Empty;
}
}
}
2022-11-29 04:12:09 +00:00
#region logo legacy
// preserve for potential future use
//public ImageSource Logo()
//{
// var logo = ImageFromPath(LogoPath);
// var plated = PlatedImage(logo); // TODO: maybe get plated directly from app package?
// // todo magic! temp fix for cross thread object
// plated.Freeze();
// return plated;
//}
//private BitmapImage ImageFromPath(string path)
//{
// if (File.Exists(path))
// {
// var image = new BitmapImage();
// image.BeginInit();
// image.UriSource = new Uri(path);
// image.CacheOption = BitmapCacheOption.OnLoad;
// image.EndInit();
// image.Freeze();
// return image;
// }
// else
// {
// ProgramLogger.LogException($"|UWP|ImageFromPath|{(string.IsNullOrEmpty(path) ? "Not Avaliable" : path)}" +
// $"|Unable to get logo for {UserModelId} from {path} and" +
// $" located in {Location}", new FileNotFoundException());
// return new BitmapImage(new Uri(Constant.MissingImgIcon));
// }
//}
//private ImageSource PlatedImage(BitmapImage image)
//{
// if (!string.IsNullOrEmpty(BackgroundColor) && BackgroundColor != "transparent")
// {
// var width = image.Width;
// var height = image.Height;
// var x = 0;
// var y = 0;
// var group = new DrawingGroup();
// var converted = ColorConverter.ConvertFromString(BackgroundColor);
// if (converted != null)
// {
// var color = (Color)converted;
// var brush = new SolidColorBrush(color);
// var pen = new Pen(brush, 1);
// var backgroundArea = new Rect(0, 0, width, width);
// var rectabgle = new RectangleGeometry(backgroundArea);
// var rectDrawing = new GeometryDrawing(brush, pen, rectabgle);
// group.Children.Add(rectDrawing);
// var imageArea = new Rect(x, y, image.Width, image.Height);
// var imageDrawing = new ImageDrawing(image, imageArea);
// group.Children.Add(imageDrawing);
// // http://stackoverflow.com/questions/6676072/get-system-drawing-bitmap-of-a-wpf-area-using-visualbrush
// var visual = new DrawingVisual();
// var context = visual.RenderOpen();
// context.DrawDrawing(group);
// context.Close();
// const int dpiScale100 = 96;
// var bitmap = new RenderTargetBitmap(
// Convert.ToInt32(width), Convert.ToInt32(height),
// dpiScale100, dpiScale100,
// PixelFormats.Pbgra32
// );
// bitmap.Render(visual);
// return bitmap;
// }
// else
// {
// ProgramLogger.LogException($"|UWP|PlatedImage|{Location}" +
// $"|Unable to convert background string {BackgroundColor} " +
// $"to color for {Location}", new InvalidOperationException());
// return new BitmapImage(new Uri(Constant.MissingImgIcon));
// }
// }
// else
// {
// // todo use windows theme as background
// return image;
// }
//}
#endregion
public override string ToString()
{
return $"{DisplayName}: {Description}";
}
public override bool Equals(object obj)
{
if (obj is Application other)
{
return UniqueIdentifier == other.UniqueIdentifier;
}
else
{
return false;
}
}
public override int GetHashCode()
{
return UniqueIdentifier.GetHashCode();
}
}
public enum PackageVersion
{
Windows10,
Windows81,
Windows8,
Unknown
}
}
}