mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-06 03:07:04 +02:00
rewrite uwp by not using GetAppListEntriesAsync,
because 1. logo is not squarelogo44x44 2. can't get details info (background etc)
This commit is contained in:
@@ -5,13 +5,13 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Xml.Linq;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.ApplicationModel.Core;
|
||||
using Windows.Foundation;
|
||||
using Windows.Management.Deployment;
|
||||
using Windows.Storage.Streams;
|
||||
using AppxPackaing;
|
||||
using Shell;
|
||||
using Wox.Infrastructure;
|
||||
@@ -26,29 +26,38 @@ namespace Wox.Plugin.Program.Programs
|
||||
public string Name { get; }
|
||||
public string FullName { get; }
|
||||
public string FamilyName { get; }
|
||||
|
||||
public string DisplayName { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string PublisherDisplayName { get; set; }
|
||||
public string Location { get; set; }
|
||||
|
||||
public Application[] Apps { get; set; }
|
||||
public Package Package { get; }
|
||||
|
||||
public PackageVersion Version { get; set; }
|
||||
|
||||
public UWP(Package package)
|
||||
{
|
||||
Package = package;
|
||||
Location = Package.InstalledLocation.Path;
|
||||
Name = Package.Id.Name;
|
||||
FullName = Package.Id.FullName;
|
||||
FamilyName = Package.Id.FamilyName;
|
||||
Location = Package.InstalledLocation.Path;
|
||||
Apps = MergedApps();
|
||||
InitializeAppInfo();
|
||||
Apps = Apps.Where(a =>
|
||||
{
|
||||
var valid =
|
||||
!string.IsNullOrEmpty(a.UserModelId) &&
|
||||
!string.IsNullOrEmpty(a.DisplayName);
|
||||
return valid;
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
private Application[] AppInfos()
|
||||
private void InitializeAppInfo()
|
||||
{
|
||||
var path = Path.Combine(Location, "AppxManifest.xml");
|
||||
var appx = new AppxFactory();
|
||||
|
||||
var namespaces = XmlNamespaces(path);
|
||||
InitPackageVersion(namespaces);
|
||||
|
||||
var appxFactory = new AppxFactory();
|
||||
IStream stream;
|
||||
const uint noAttribute = 0x80;
|
||||
const Stgm exclusiveRead = Stgm.Read | Stgm.ShareExclusive;
|
||||
@@ -56,129 +65,249 @@ namespace Wox.Plugin.Program.Programs
|
||||
|
||||
if (result == Hresult.Ok)
|
||||
{
|
||||
var reader = appx.CreateManifestReader(stream);
|
||||
|
||||
var properties = reader.GetProperties();
|
||||
PublisherDisplayName = properties.GetStringValue("PublisherDisplayName");
|
||||
DisplayName = properties.GetStringValue("DisplayName");
|
||||
Description = properties.GetStringValue("Description");
|
||||
|
||||
var apps = reader.GetApplications();
|
||||
var parsedApps = new List<Application>();
|
||||
while (apps.GetHasCurrent() != 0)
|
||||
var reader = appxFactory.CreateManifestReader(stream);
|
||||
var manifestApps = reader.GetApplications();
|
||||
var apps = new List<Application>();
|
||||
while (manifestApps.GetHasCurrent() != 0)
|
||||
{
|
||||
var current = apps.GetCurrent();
|
||||
var appListEntry = current.GetStringValue("AppListEntry");
|
||||
var manifestApp = manifestApps.GetCurrent();
|
||||
var appListEntry = manifestApp.GetStringValue("AppListEntry");
|
||||
if (appListEntry != "none")
|
||||
{
|
||||
var app = new Application
|
||||
{
|
||||
UserModelId = current.GetAppUserModelId(),
|
||||
BackgroundColor = current.GetStringValue("BackgroundColor") ?? string.Empty,
|
||||
Location = Location,
|
||||
LogoPath = Application.LogoFromManifest(current, Location),
|
||||
Valid = true // useless for now
|
||||
UserModelId = manifestApp.GetAppUserModelId(),
|
||||
DisplayName = manifestApp.GetStringValue("DisplayName"),
|
||||
Description = manifestApp.GetStringValue("Description"),
|
||||
BackgroundColor = manifestApp.GetStringValue("BackgroundColor"),
|
||||
Location = Location
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(app.UserModelId))
|
||||
{
|
||||
parsedApps.Add(app);
|
||||
}
|
||||
app.DisplayName = ResourceFromPri(FullName, app.DisplayName);
|
||||
app.Description = ResourceFromPri(FullName, app.Description);
|
||||
// todo move into Application class, so it can specific app info when logo error
|
||||
app.LogoUri = LogoUriFromManifest(manifestApp);
|
||||
app.LogoPath = LogoPathFromUri(app.LogoUri);
|
||||
apps.Add(app);
|
||||
}
|
||||
apps.MoveNext();
|
||||
manifestApps.MoveNext();
|
||||
}
|
||||
Apps = apps.Where(a => a.AppListEntry != "none").ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
return parsedApps.ToArray();
|
||||
/// http://www.hanselman.com/blog/GetNamespacesFromAnXMLDocumentWithXPathDocumentAndLINQToXML.aspx
|
||||
private static string[] XmlNamespaces(string path)
|
||||
{
|
||||
XDocument z = XDocument.Load(path);
|
||||
if (z.Root != null)
|
||||
{
|
||||
var namespaces = z.Root.Attributes().
|
||||
Where(a => a.IsNamespaceDeclaration).
|
||||
GroupBy(
|
||||
a => a.Name.Namespace == XNamespace.None ? string.Empty : a.Name.LocalName,
|
||||
a => XNamespace.Get(a.Value)
|
||||
).Select(
|
||||
g => g.First().ToString()
|
||||
).ToArray();
|
||||
return namespaces;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Application[] { };
|
||||
Log.Error($"can't find namespaces for <{path}>");
|
||||
return new string[] {};
|
||||
}
|
||||
}
|
||||
|
||||
private Application[] AppDisplayInfos()
|
||||
private void InitPackageVersion(string[] namespaces)
|
||||
{
|
||||
IReadOnlyList<AppListEntry> apps;
|
||||
try
|
||||
var versionFromNamespace = new Dictionary<string, PackageVersion>
|
||||
{
|
||||
apps = Package.GetAppListEntriesAsync().AsTask().Result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{"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},
|
||||
};
|
||||
|
||||
foreach (var n in versionFromNamespace.Keys)
|
||||
{
|
||||
var message = $"{e.Message} @ {Name}";
|
||||
Console.WriteLine(message);
|
||||
return new Application[] { };
|
||||
if (namespaces.Contains(n))
|
||||
{
|
||||
Version = versionFromNamespace[n];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var displayinfos = apps.Select(a =>
|
||||
{
|
||||
RandomAccessStreamReference logo;
|
||||
try
|
||||
{
|
||||
// todo: which size is valid?
|
||||
logo = a.DisplayInfo.GetLogo(new Size(44, 44));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var message = $"Can't get logo for {Name}";
|
||||
Log.Error(message);
|
||||
Log.Exception(e);
|
||||
logo = RandomAccessStreamReference.CreateFromUri(new Uri(Constant.ErrorIcon));
|
||||
}
|
||||
var parsed = new Application
|
||||
{
|
||||
DisplayName = a.DisplayInfo.DisplayName,
|
||||
Description = a.DisplayInfo.Description,
|
||||
LogoStream = logo
|
||||
};
|
||||
return parsed;
|
||||
}).ToArray();
|
||||
|
||||
return displayinfos;
|
||||
Log.Error($"Unknown Appmanifest version: {FullName}");
|
||||
Version = PackageVersion.Unknown;
|
||||
}
|
||||
|
||||
private Application[] MergedApps()
|
||||
private string LogoUriFromManifest(IAppxManifestApplication app)
|
||||
{
|
||||
// todo can't find api, so just hard code it
|
||||
if (Location.Contains("SystemApps") || Location.Contains("WindowsApps"))
|
||||
var logoKeyFromVersion = new Dictionary<PackageVersion, string>
|
||||
{
|
||||
// we must parse AppInfo first, because we want to make sure AppListEntry != "none"
|
||||
var infos = AppInfos();
|
||||
if (infos.Length > 0)
|
||||
{PackageVersion.Windows10, "Square44x44Logo"},
|
||||
{PackageVersion.Windows81, "Square30x30Logo"},
|
||||
{PackageVersion.Windows8, "SmallLogo"},
|
||||
};
|
||||
if (logoKeyFromVersion.ContainsKey(Version))
|
||||
{
|
||||
var key = logoKeyFromVersion[Version];
|
||||
var logoUri = app.GetStringValue(key);
|
||||
return logoUri;
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private string LogoPathFromUri(string uri)
|
||||
{
|
||||
// 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
|
||||
|
||||
string path;
|
||||
if (uri.Contains("\\"))
|
||||
{
|
||||
path = Path.Combine(Location, uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
// for C:\Windows\MiracastView etc
|
||||
path = Path.Combine(Location, "Assets", uri);
|
||||
}
|
||||
|
||||
var extension = Path.GetExtension(path);
|
||||
if (extension != null)
|
||||
{
|
||||
var end = path.Length - extension.Length;
|
||||
var prefix = path.Substring(0, end);
|
||||
var paths = new List<string> {path};
|
||||
|
||||
// todo hidpi icon
|
||||
if (Version == PackageVersion.Windows10)
|
||||
{
|
||||
var displayInfos = AppDisplayInfos();
|
||||
var apps = infos;
|
||||
// todo: temp hack for multipla application mismatch problem
|
||||
// e.g. mail and calendar, skype video and messaging
|
||||
// https://github.com/Wox-launcher/Wox/issues/198#issuecomment-244778783
|
||||
var length = infos.Length;
|
||||
for (int i = 0; i < length; i++)
|
||||
paths.Add($"{prefix}.scale-100{extension}");
|
||||
paths.Add($"{prefix}.scale-200{extension}");
|
||||
}
|
||||
else if (Version == PackageVersion.Windows81)
|
||||
{
|
||||
paths.Add($"{prefix}.scale-100{extension}");
|
||||
paths.Add($"{prefix}.scale-120{extension}");
|
||||
paths.Add($"{prefix}.scale-140{extension}");
|
||||
paths.Add($"{prefix}.scale-160{extension}");
|
||||
paths.Add($"{prefix}.scale-180{extension}");
|
||||
}
|
||||
else if (Version == PackageVersion.Windows8)
|
||||
{
|
||||
paths.Add($"{prefix}.scale-100{extension}");
|
||||
}
|
||||
|
||||
var selected = paths.FirstOrDefault(File.Exists);
|
||||
if (!string.IsNullOrEmpty(selected))
|
||||
{
|
||||
return selected;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"<{FullName}> can't find logo uri: <{uri}>");
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"<{FullName}> cantains uri doesn't have extension: <{uri}>");
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private string ResourceFromPri(string packageFullName, string resourceReference)
|
||||
{
|
||||
const string prefix = "ms-resource:";
|
||||
if (!string.IsNullOrWhiteSpace(resourceReference) && resourceReference.StartsWith(prefix))
|
||||
{
|
||||
// magic comes from @talynone
|
||||
// https://github.com/talynone/Wox.Plugin.WindowsUniversalAppLauncher/blob/master/StoreAppLauncher/Helpers/NativeApiHelper.cs#L139-L153
|
||||
string key = resourceReference.Substring(prefix.Length);
|
||||
string parsed;
|
||||
if (key.StartsWith("//"))
|
||||
{
|
||||
parsed = prefix + key;
|
||||
}
|
||||
else if (key.StartsWith("/"))
|
||||
{
|
||||
parsed = prefix + "//" + key;
|
||||
}
|
||||
else
|
||||
{
|
||||
parsed = $"{prefix}//{Name}/resources/{key}";
|
||||
}
|
||||
|
||||
var outBuffer = new StringBuilder(128);
|
||||
string source = $"@{{{packageFullName}? {parsed}}}";
|
||||
var capacity = (uint) outBuffer.Capacity;
|
||||
var hResult = SHLoadIndirectString(source, outBuffer, capacity, IntPtr.Zero);
|
||||
if (hResult == Hresult.Ok)
|
||||
{
|
||||
var loaded = outBuffer.ToString();
|
||||
if (!string.IsNullOrEmpty(loaded))
|
||||
{
|
||||
var j = length - i - 1;
|
||||
apps[i].DisplayName = displayInfos[j].DisplayName;
|
||||
apps[i].Description = displayInfos[j].Description;
|
||||
apps[i].LogoStream = displayInfos[j].LogoStream;
|
||||
return loaded;
|
||||
}
|
||||
return apps;
|
||||
else
|
||||
{
|
||||
var error = $"Load {source} failed, null or empty result";
|
||||
Debug.WriteLine(error);
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// known hresult 2147942522:
|
||||
// 'Microsoft Corporation' violates pattern constraint of '\bms-resource:.{1,256}'.
|
||||
// for
|
||||
// Microsoft.MicrosoftOfficeHub_17.7608.23501.0_x64__8wekyb3d8bbwe: ms-resource://Microsoft.MicrosoftOfficeHub/officehubintl/AppManifest_GetOffice_Description
|
||||
// Microsoft.BingFoodAndDrink_3.0.4.336_x64__8wekyb3d8bbwe: ms-resource:AppDescription
|
||||
var message = $"Load {source} failed, HResult error code: {hResult}";
|
||||
Log.Error(message);
|
||||
var exception = Marshal.GetExceptionForHR((int) hResult);
|
||||
Log.Exception(exception);
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
return new Application[] { };
|
||||
else
|
||||
{
|
||||
return resourceReference;
|
||||
}
|
||||
}
|
||||
|
||||
public static Application[] All()
|
||||
{
|
||||
|
||||
|
||||
var windows10 = new Version(10, 0);
|
||||
var support = Environment.OSVersion.Version.Major >= windows10.Major;
|
||||
if (support)
|
||||
{
|
||||
var applications = CurrentUserPackages().AsParallel().SelectMany(p => new UWP(p).Apps);
|
||||
applications = applications.Where(a => a.Valid);
|
||||
return applications.ToArray();
|
||||
var watch = new System.Diagnostics.Stopwatch();
|
||||
watch.Start();
|
||||
|
||||
var applications = CurrentUserPackages().AsParallel().SelectMany(p => new UWP(p).Apps).ToArray();
|
||||
|
||||
watch.Stop();
|
||||
Log.Info("UWP ALL" + watch.ElapsedMilliseconds);
|
||||
|
||||
return applications;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Application[] { };
|
||||
return new Application[] {};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static IEnumerable<Package> CurrentUserPackages()
|
||||
@@ -190,12 +319,14 @@ namespace Wox.Plugin.Program.Programs
|
||||
var userSecurityId = user.Value;
|
||||
var packageManager = new PackageManager();
|
||||
var packages = packageManager.FindPackagesForUser(userSecurityId);
|
||||
packages = packages.Where(p => !p.IsFramework && !p.IsDevelopmentMode && !string.IsNullOrEmpty(p.InstalledLocation.Path));
|
||||
packages =
|
||||
packages.Where(
|
||||
p => !p.IsFramework && !p.IsDevelopmentMode && !string.IsNullOrEmpty(p.InstalledLocation.Path));
|
||||
return packages;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Package[] { };
|
||||
return new Package[] {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,23 +356,22 @@ namespace Wox.Plugin.Program.Programs
|
||||
|
||||
public class Application : IProgram
|
||||
{
|
||||
public string AppListEntry { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public string Description { get; set; }
|
||||
public RandomAccessStreamReference LogoStream { get; set; }
|
||||
public string UserModelId { get; set; }
|
||||
public string PublisherDisplayName { get; set; }
|
||||
public string BackgroundColor { get; set; }
|
||||
public string LogoPath { get; set; }
|
||||
|
||||
public string LogoUri { get; set; }
|
||||
public string LogoPath { get; set; }
|
||||
public string Location { get; set; }
|
||||
public bool Valid { get; set; }
|
||||
|
||||
private int Score(string query)
|
||||
{
|
||||
var score1 = StringMatcher.Score(DisplayName, query);
|
||||
var score2 = StringMatcher.ScoreForPinyin(DisplayName, query);
|
||||
var score3 = StringMatcher.Score(Description, query);
|
||||
var score = new[] { score1, score2, score3 }.Max();
|
||||
var score = new[] {score1, score2, score3}.Max();
|
||||
return score;
|
||||
}
|
||||
|
||||
@@ -294,205 +424,103 @@ namespace Wox.Plugin.Program.Programs
|
||||
return contextMenus;
|
||||
}
|
||||
|
||||
private void Launch(IPublicAPI api)
|
||||
private async void Launch(IPublicAPI api)
|
||||
{
|
||||
try
|
||||
var appManager = new ApplicationActivationManager();
|
||||
uint unusedPid;
|
||||
const string noArgs = "";
|
||||
const ACTIVATEOPTIONS noFlags = ACTIVATEOPTIONS.AO_NONE;
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var appManager = new ApplicationActivationManager();
|
||||
uint unusedPid;
|
||||
const string noArgs = "";
|
||||
const ACTIVATEOPTIONS noFlags = ACTIVATEOPTIONS.AO_NONE;
|
||||
appManager.ActivateApplication(UserModelId, noArgs, noFlags, out unusedPid);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
var name = "Plugin: Program";
|
||||
var message = $"Can't start UWP: {DisplayName}";
|
||||
api.ShowMsg(name, message, string.Empty);
|
||||
}
|
||||
try
|
||||
{
|
||||
appManager.ActivateApplication(UserModelId, noArgs, noFlags, out unusedPid);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
var name = "Plugin: Program";
|
||||
var message = $"Can't start UWP: {DisplayName}";
|
||||
api.ShowMsg(name, message, string.Empty);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public ImageSource Logo()
|
||||
{
|
||||
var logo = !string.IsNullOrEmpty(LogoPath) ? ImageFromPath(LogoPath) : ImageFromStream(LogoStream);
|
||||
var validBaground = !string.IsNullOrEmpty(BackgroundColor) && BackgroundColor != "transparent";
|
||||
var plated = validBaground ? PlatedImage(logo) : logo;
|
||||
var logo = ImageFromPath(LogoPath);
|
||||
var plated = PlatedImage(logo);
|
||||
|
||||
// todo magic! temp fix for cross thread object
|
||||
plated.Freeze();
|
||||
return plated;
|
||||
}
|
||||
|
||||
internal static string LogoFromManifest(IAppxManifestApplication application, string location)
|
||||
{
|
||||
// todo use hidpi logo when use hidpi screen
|
||||
var path1 = Path.Combine(location, application.GetStringValue("Square44x44Logo"));
|
||||
path1 = LogoFromPath(path1);
|
||||
if (!string.IsNullOrEmpty(path1))
|
||||
{
|
||||
return path1;
|
||||
}
|
||||
else
|
||||
{
|
||||
var path2 = Path.Combine(location, application.GetStringValue("Square150x150Logo"));
|
||||
path2 = LogoFromPath(path2);
|
||||
if (!string.IsNullOrEmpty(path2))
|
||||
{
|
||||
return path2;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Constant.ErrorIcon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string LogoFromPath(string path)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
// https://msdn.microsoft.com/windows/uwp/controls-and-patterns/tiles-and-notifications-app-assets
|
||||
var extension = Path.GetExtension(path);
|
||||
if (!string.IsNullOrEmpty(extension))
|
||||
{
|
||||
var paths = new List<string>();
|
||||
var end = path.Length - extension.Length;
|
||||
var prefix = path.Substring(0, end);
|
||||
// todo: remove hard cod scale
|
||||
paths.Add($"{prefix}.scale-200{extension}");
|
||||
paths.Add($"{prefix}.scale-100{extension}");
|
||||
|
||||
// hack for C:\Windows\ImmersiveControlPanel
|
||||
var directory = Directory.GetParent(path).FullName;
|
||||
var filename = Path.GetFileNameWithoutExtension(path);
|
||||
prefix = Path.Combine(directory, "images", filename);
|
||||
paths.Add($"{prefix}.scale-200{extension}");
|
||||
paths.Add($"{prefix}.scale-100{extension}");
|
||||
|
||||
foreach (var p in paths)
|
||||
{
|
||||
if (File.Exists(p))
|
||||
{
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
// for js based application, e.g cut the rope
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
private BitmapImage ImageFromPath(string path)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
if (File.Exists(path))
|
||||
{
|
||||
// https://msdn.microsoft.com/windows/uwp/controls-and-patterns/tiles-and-notifications-app-assets
|
||||
|
||||
var extension = Path.GetExtension(path);
|
||||
if (!string.IsNullOrEmpty(extension))
|
||||
{
|
||||
var paths = new List<string>();
|
||||
var prefix = path.Substring(0, extension.Length);
|
||||
// todo: remove hard cod scale
|
||||
paths.Add($"{prefix}.scale-200{extension}");
|
||||
paths.Add($"{prefix}.scale-100{extension}");
|
||||
// hack for C:\Windows\ImmersiveControlPanel
|
||||
var directory = Directory.GetParent(path).FullName;
|
||||
var filename = Path.GetFileNameWithoutExtension(path);
|
||||
prefix = Path.Combine(directory, "images", filename);
|
||||
paths.Add($"{prefix}.scale-200{extension}");
|
||||
paths.Add($"{prefix}.scale-100{extension}");
|
||||
foreach (var p in paths)
|
||||
{
|
||||
if (File.Exists(p))
|
||||
{
|
||||
return new BitmapImage(new Uri(p));
|
||||
}
|
||||
}
|
||||
return new BitmapImage(new Uri(Constant.ErrorIcon));
|
||||
}
|
||||
else
|
||||
{
|
||||
return new BitmapImage(new Uri(Constant.ErrorIcon));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// for js based application, e.g cut the rope
|
||||
var image = new BitmapImage(new Uri(path));
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
private BitmapImage ImageFromStream(RandomAccessStreamReference reference)
|
||||
{
|
||||
IRandomAccessStreamWithContentType stream;
|
||||
try
|
||||
else
|
||||
{
|
||||
stream = reference.OpenReadAsync().AsTask().Result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var message = $"{e.Message} @ {DisplayName}";
|
||||
Log.Error(message);
|
||||
Log.Exception(e);
|
||||
Log.Error($"Can't get logo for <{UserModelId}> with path <{path}>");
|
||||
return new BitmapImage(new Uri(Constant.ErrorIcon));
|
||||
}
|
||||
|
||||
var image = new BitmapImage();
|
||||
image.BeginInit();
|
||||
image.StreamSource = stream.AsStream();
|
||||
image.EndInit();
|
||||
return image;
|
||||
}
|
||||
|
||||
private ImageSource PlatedImage(BitmapImage image)
|
||||
{
|
||||
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)
|
||||
if (!string.IsNullOrEmpty(BackgroundColor) && BackgroundColor != "transparent")
|
||||
{
|
||||
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 width = image.Width;
|
||||
var height = image.Height;
|
||||
var x = 0;
|
||||
var y = 0;
|
||||
|
||||
var imageArea = new Rect(x, y, image.Width, image.Height);
|
||||
var imageDrawing = new ImageDrawing(image, imageArea);
|
||||
group.Children.Add(imageDrawing);
|
||||
var group = new DrawingGroup();
|
||||
|
||||
// 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;
|
||||
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
|
||||
{
|
||||
Log.Error($"Can't convert background string <{BackgroundColor}> to color");
|
||||
return new BitmapImage(new Uri(Constant.ErrorIcon));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new BitmapImage(new Uri(Constant.ErrorIcon));
|
||||
// todo use windows theme as background
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,19 +530,32 @@ namespace Wox.Plugin.Program.Programs
|
||||
}
|
||||
}
|
||||
|
||||
public enum PackageVersion
|
||||
{
|
||||
Windows10,
|
||||
Windows81,
|
||||
Windows8,
|
||||
Unknown
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum Stgm : uint
|
||||
{
|
||||
Read = 0x0,
|
||||
ShareExclusive = 0x10
|
||||
ShareExclusive = 0x10,
|
||||
}
|
||||
|
||||
private enum Hresult : uint
|
||||
{
|
||||
Ok = 0x0000
|
||||
Ok = 0x0000,
|
||||
}
|
||||
|
||||
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
|
||||
private static extern Hresult SHCreateStreamOnFileEx(string fileName, Stgm grfMode, uint attributes, bool create, IStream reserved, out IStream stream);
|
||||
private static extern Hresult SHCreateStreamOnFileEx(string fileName, Stgm grfMode, uint attributes, bool create,
|
||||
IStream reserved, out IStream stream);
|
||||
|
||||
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
|
||||
private static extern Hresult SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, uint cchOutBuf,
|
||||
IntPtr ppvReserved);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user