mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-06 03:07:04 +02:00
whitespace forced changes (#6002)
This commit is contained in:
@@ -1,48 +1,48 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using static Microsoft.Plugin.Program.Programs.UWP;
|
||||
|
||||
namespace Microsoft.Plugin.Program.Programs
|
||||
{
|
||||
public static class AppxPackageHelper
|
||||
{
|
||||
// This function returns a list of attributes of applications
|
||||
public static List<IAppxManifestApplication> GetAppsFromManifest(IStream stream)
|
||||
{
|
||||
List<IAppxManifestApplication> apps = new List<IAppxManifestApplication>();
|
||||
var appxFactory = new AppxFactory();
|
||||
var reader = ((IAppxFactory)appxFactory).CreateManifestReader(stream);
|
||||
var manifestApps = reader.GetApplications();
|
||||
|
||||
while (manifestApps.GetHasCurrent())
|
||||
{
|
||||
var manifestApp = manifestApps.GetCurrent();
|
||||
var hr = manifestApp.GetStringValue("AppListEntry", out var appListEntry);
|
||||
_ = CheckHRAndReturnOrThrow(hr, appListEntry);
|
||||
if (appListEntry != "none")
|
||||
{
|
||||
apps.Add(manifestApp);
|
||||
}
|
||||
|
||||
manifestApps.MoveNext();
|
||||
}
|
||||
|
||||
return apps;
|
||||
}
|
||||
|
||||
public static T CheckHRAndReturnOrThrow<T>(Hresult hr, T result)
|
||||
{
|
||||
if (hr != Hresult.Ok)
|
||||
{
|
||||
Marshal.ThrowExceptionForHR((int)hr);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using static Microsoft.Plugin.Program.Programs.UWP;
|
||||
|
||||
namespace Microsoft.Plugin.Program.Programs
|
||||
{
|
||||
public static class AppxPackageHelper
|
||||
{
|
||||
// This function returns a list of attributes of applications
|
||||
public static List<IAppxManifestApplication> GetAppsFromManifest(IStream stream)
|
||||
{
|
||||
List<IAppxManifestApplication> apps = new List<IAppxManifestApplication>();
|
||||
var appxFactory = new AppxFactory();
|
||||
var reader = ((IAppxFactory)appxFactory).CreateManifestReader(stream);
|
||||
var manifestApps = reader.GetApplications();
|
||||
|
||||
while (manifestApps.GetHasCurrent())
|
||||
{
|
||||
var manifestApp = manifestApps.GetCurrent();
|
||||
var hr = manifestApp.GetStringValue("AppListEntry", out var appListEntry);
|
||||
_ = CheckHRAndReturnOrThrow(hr, appListEntry);
|
||||
if (appListEntry != "none")
|
||||
{
|
||||
apps.Add(manifestApp);
|
||||
}
|
||||
|
||||
manifestApps.MoveNext();
|
||||
}
|
||||
|
||||
return apps;
|
||||
}
|
||||
|
||||
public static T CheckHRAndReturnOrThrow<T>(Hresult hr, T result)
|
||||
{
|
||||
if (hr != Hresult.Ok)
|
||||
{
|
||||
Marshal.ThrowExceptionForHR((int)hr);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace Microsoft.Plugin.Program.Programs
|
||||
{
|
||||
internal interface IPackageCatalog
|
||||
{
|
||||
event TypedEventHandler<PackageCatalog, PackageInstallingEventArgs> PackageInstalling;
|
||||
|
||||
event TypedEventHandler<PackageCatalog, PackageUninstallingEventArgs> PackageUninstalling;
|
||||
|
||||
event TypedEventHandler<PackageCatalog, PackageUpdatingEventArgs> PackageUpdating;
|
||||
}
|
||||
}
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace Microsoft.Plugin.Program.Programs
|
||||
{
|
||||
internal interface IPackageCatalog
|
||||
{
|
||||
event TypedEventHandler<PackageCatalog, PackageInstallingEventArgs> PackageInstalling;
|
||||
|
||||
event TypedEventHandler<PackageCatalog, PackageUninstallingEventArgs> PackageUninstalling;
|
||||
|
||||
event TypedEventHandler<PackageCatalog, PackageUpdatingEventArgs> PackageUpdating;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,65 +1,65 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace Microsoft.Plugin.Program.Programs
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a simple wrapper class around the PackageCatalog to facilitate unit testing.
|
||||
/// </summary>
|
||||
internal class PackageCatalogWrapper : IPackageCatalog
|
||||
{
|
||||
private PackageCatalog _packageCatalog;
|
||||
|
||||
public PackageCatalogWrapper()
|
||||
{
|
||||
// Opens the catalog of packages that is available for the current user.
|
||||
_packageCatalog = PackageCatalog.OpenForCurrentUser();
|
||||
}
|
||||
|
||||
// Summary: Indicates that an app package is installing.
|
||||
public event TypedEventHandler<PackageCatalog, PackageInstallingEventArgs> PackageInstalling
|
||||
{
|
||||
add
|
||||
{
|
||||
_packageCatalog.PackageInstalling += value;
|
||||
}
|
||||
|
||||
remove
|
||||
{
|
||||
_packageCatalog.PackageInstalling -= value;
|
||||
}
|
||||
}
|
||||
|
||||
// Summary: Indicates that an app package is uninstalling.
|
||||
public event TypedEventHandler<PackageCatalog, PackageUninstallingEventArgs> PackageUninstalling
|
||||
{
|
||||
add
|
||||
{
|
||||
_packageCatalog.PackageUninstalling += value;
|
||||
}
|
||||
|
||||
remove
|
||||
{
|
||||
_packageCatalog.PackageUninstalling -= value;
|
||||
}
|
||||
}
|
||||
|
||||
// Summary: Indicates that an app package is updating.
|
||||
public event TypedEventHandler<PackageCatalog, PackageUpdatingEventArgs> PackageUpdating
|
||||
{
|
||||
add
|
||||
{
|
||||
_packageCatalog.PackageUpdating += value;
|
||||
}
|
||||
|
||||
remove
|
||||
{
|
||||
_packageCatalog.PackageUpdating -= value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace Microsoft.Plugin.Program.Programs
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a simple wrapper class around the PackageCatalog to facilitate unit testing.
|
||||
/// </summary>
|
||||
internal class PackageCatalogWrapper : IPackageCatalog
|
||||
{
|
||||
private PackageCatalog _packageCatalog;
|
||||
|
||||
public PackageCatalogWrapper()
|
||||
{
|
||||
// Opens the catalog of packages that is available for the current user.
|
||||
_packageCatalog = PackageCatalog.OpenForCurrentUser();
|
||||
}
|
||||
|
||||
// Summary: Indicates that an app package is installing.
|
||||
public event TypedEventHandler<PackageCatalog, PackageInstallingEventArgs> PackageInstalling
|
||||
{
|
||||
add
|
||||
{
|
||||
_packageCatalog.PackageInstalling += value;
|
||||
}
|
||||
|
||||
remove
|
||||
{
|
||||
_packageCatalog.PackageInstalling -= value;
|
||||
}
|
||||
}
|
||||
|
||||
// Summary: Indicates that an app package is uninstalling.
|
||||
public event TypedEventHandler<PackageCatalog, PackageUninstallingEventArgs> PackageUninstalling
|
||||
{
|
||||
add
|
||||
{
|
||||
_packageCatalog.PackageUninstalling += value;
|
||||
}
|
||||
|
||||
remove
|
||||
{
|
||||
_packageCatalog.PackageUninstalling -= value;
|
||||
}
|
||||
}
|
||||
|
||||
// Summary: Indicates that an app package is updating.
|
||||
public event TypedEventHandler<PackageCatalog, PackageUpdatingEventArgs> PackageUpdating
|
||||
{
|
||||
add
|
||||
{
|
||||
_packageCatalog.PackageUpdating += value;
|
||||
}
|
||||
|
||||
remove
|
||||
{
|
||||
_packageCatalog.PackageUpdating -= value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Plugin.Program.Logger;
|
||||
@@ -23,9 +23,9 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
|
||||
public string InstalledLocation { get; } = string.Empty;
|
||||
|
||||
public PackageWrapper()
|
||||
{
|
||||
}
|
||||
public PackageWrapper()
|
||||
{
|
||||
}
|
||||
|
||||
public PackageWrapper(string name, string fullName, string familyName, bool isFramework, bool isDevelopmentMode, string installedLocation)
|
||||
{
|
||||
@@ -39,9 +39,9 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
|
||||
public static PackageWrapper GetWrapperFromPackage(Package package)
|
||||
{
|
||||
if (package == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(package));
|
||||
if (package == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(package));
|
||||
}
|
||||
|
||||
string path;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
@@ -24,7 +24,7 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching COM")]
|
||||
private struct WIN32_FIND_DATAW
|
||||
{
|
||||
{
|
||||
public uint dwFileAttributes;
|
||||
public long ftCreationTime;
|
||||
public long ftLastAccessTime;
|
||||
@@ -39,8 +39,8 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
public string cAlternateFileName;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Represents flags specified in IShellLink interface")]
|
||||
[Flags]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Represents flags specified in IShellLink interface")]
|
||||
public enum SLR_FLAGS
|
||||
{
|
||||
SLR_NO_UI = 0x1,
|
||||
@@ -52,71 +52,71 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
SLR_NOLINKINFO = 0x40,
|
||||
SLR_INVOKE_MSI = 0x80,
|
||||
}
|
||||
|
||||
|
||||
// Reference : http://www.pinvoke.net/default.aspx/Interfaces.IShellLinkW
|
||||
|
||||
|
||||
// The IShellLink interface allows Shell links to be created, modified, and resolved
|
||||
[ComImport]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[ComImport]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[Guid("000214F9-0000-0000-C000-000000000046")]
|
||||
private interface IShellLinkW
|
||||
{
|
||||
/// <summary>Retrieves the path and file name of a Shell link object</summary>
|
||||
void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, ref WIN32_FIND_DATAW pfd, SLGP_FLAGS fFlags);
|
||||
|
||||
|
||||
/// <summary>Retrieves the list of item identifiers for a Shell link object</summary>
|
||||
void GetIDList(out IntPtr ppidl);
|
||||
|
||||
|
||||
/// <summary>Sets the pointer to an item identifier list (PIDL) for a Shell link object.</summary>
|
||||
void SetIDList(IntPtr pidl);
|
||||
|
||||
|
||||
/// <summary>Retrieves the description string for a Shell link object</summary>
|
||||
void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName);
|
||||
|
||||
|
||||
/// <summary>Sets the description for a Shell link object. The description can be any application-defined string</summary>
|
||||
void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
|
||||
|
||||
|
||||
/// <summary>Retrieves the name of the working directory for a Shell link object</summary>
|
||||
void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath);
|
||||
|
||||
|
||||
/// <summary>Sets the name of the working directory for a Shell link object</summary>
|
||||
void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
|
||||
|
||||
|
||||
/// <summary>Retrieves the command-line arguments associated with a Shell link object</summary>
|
||||
void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath);
|
||||
|
||||
|
||||
/// <summary>Sets the command-line arguments for a Shell link object</summary>
|
||||
void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
|
||||
|
||||
|
||||
/// <summary>Retrieves the hot key for a Shell link object</summary>
|
||||
void GetHotkey(out short pwHotkey);
|
||||
|
||||
|
||||
/// <summary>Sets a hot key for a Shell link object</summary>
|
||||
void SetHotkey(short wHotkey);
|
||||
|
||||
|
||||
/// <summary>Retrieves the show command for a Shell link object</summary>
|
||||
void GetShowCmd(out int piShowCmd);
|
||||
|
||||
|
||||
/// <summary>Sets the show command for a Shell link object. The show command sets the initial show state of the window.</summary>
|
||||
void SetShowCmd(int iShowCmd);
|
||||
|
||||
|
||||
/// <summary>Retrieves the location (path and index) of the icon for a Shell link object</summary>
|
||||
void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int piIcon);
|
||||
|
||||
|
||||
/// <summary>Sets the location (path and index) of the icon for a Shell link object</summary>
|
||||
void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
|
||||
|
||||
|
||||
/// <summary>Sets the relative path to the Shell link object</summary>
|
||||
void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved);
|
||||
|
||||
|
||||
/// <summary>Attempts to find the target of a Shell link, even if it has been moved or renamed</summary>
|
||||
void Resolve(ref Accessibility._RemotableHandle hwnd, SLR_FLAGS fFlags);
|
||||
|
||||
|
||||
/// <summary>Sets the path and file name of a Shell link object</summary>
|
||||
void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[ComImport]
|
||||
[Guid("00021401-0000-0000-C000-000000000046")]
|
||||
private class ShellLink
|
||||
{
|
||||
@@ -127,7 +127,7 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
|
||||
// Contains the arguments to the app
|
||||
public string Arguments { get; set; } = string.Empty;
|
||||
|
||||
|
||||
public bool HasArguments { get; set; } = false;
|
||||
|
||||
// Retrieve the target path using Shell Link
|
||||
@@ -173,8 +173,8 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
HasArguments = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return target;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -10,20 +10,20 @@ using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Plugin.Program.Logger;
|
||||
using Microsoft.Plugin.Program.Win32;
|
||||
using Wox.Infrastructure.Logger;
|
||||
|
||||
using Microsoft.Plugin.Program.Win32;
|
||||
using Wox.Infrastructure.Logger;
|
||||
|
||||
namespace Microsoft.Plugin.Program.Programs
|
||||
{
|
||||
[Serializable]
|
||||
public partial class UWP
|
||||
{
|
||||
public string Name { get; }
|
||||
|
||||
|
||||
public string FullName { get; }
|
||||
|
||||
public string FamilyName { get; }
|
||||
|
||||
|
||||
public string FamilyName { get; }
|
||||
|
||||
public string Location { get; set; }
|
||||
|
||||
public IList<UWPApplication> Apps { get; private set; }
|
||||
@@ -33,12 +33,12 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
public static IPackageManager PackageManagerWrapper { get; set; } = new PackageManagerWrapper();
|
||||
|
||||
public UWP(IPackage package)
|
||||
{
|
||||
if (package == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(package));
|
||||
}
|
||||
|
||||
{
|
||||
if (package == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(package));
|
||||
}
|
||||
|
||||
Name = package.Name;
|
||||
FullName = package.FullName;
|
||||
FamilyName = package.FamilyName;
|
||||
@@ -58,36 +58,36 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
|
||||
if (hResult == Hresult.Ok)
|
||||
{
|
||||
var apps = new List<UWPApplication>();
|
||||
|
||||
var apps = new List<UWPApplication>();
|
||||
|
||||
List<IAppxManifestApplication> appsViaManifests = AppxPackageHelper.GetAppsFromManifest(stream);
|
||||
foreach (var appInManifest in appsViaManifests)
|
||||
{
|
||||
var app = new UWPApplication(appInManifest, this);
|
||||
apps.Add(app);
|
||||
}
|
||||
|
||||
Apps = apps.Where(a =>
|
||||
{
|
||||
var valid =
|
||||
!string.IsNullOrEmpty(a.UserModelId) &&
|
||||
!string.IsNullOrEmpty(a.DisplayName) &&
|
||||
}
|
||||
|
||||
Apps = apps.Where(a =>
|
||||
{
|
||||
var valid =
|
||||
!string.IsNullOrEmpty(a.UserModelId) &&
|
||||
!string.IsNullOrEmpty(a.DisplayName) &&
|
||||
a.AppListEntry != "none";
|
||||
|
||||
return valid;
|
||||
return valid;
|
||||
}).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
var e = Marshal.GetExceptionForHR((int)hResult);
|
||||
ProgramLogger.LogException(
|
||||
ProgramLogger.LogException(
|
||||
$"|UWP|InitializeAppInfo|{path}" +
|
||||
"|Error caused while trying to get the details of the UWP program", e);
|
||||
|
||||
Apps = new List<UWPApplication>().ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// http://www.hanselman.com/blog/GetNamespacesFromAnXMLDocumentWithXPathDocumentAndLINQToXML.aspx
|
||||
private static string[] XmlNamespaces(string path)
|
||||
{
|
||||
@@ -128,15 +128,15 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
}
|
||||
}
|
||||
|
||||
ProgramLogger.LogException(
|
||||
ProgramLogger.LogException(
|
||||
$"|UWP|XmlNamespaces|{Location}" +
|
||||
"|Trying to get the package version of the UWP program, but a unknown UWP appmanifest version "
|
||||
+ $"{FullName} from location {Location} is returned.", new FormatException());
|
||||
|
||||
Version = PackageVersion.Unknown;
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Intentially keeping the process alive.")]
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Intentially keeping the process alive.")]
|
||||
public static UWPApplication[] All()
|
||||
{
|
||||
var windows10 = new Version(10, 0);
|
||||
@@ -153,12 +153,12 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ProgramLogger.LogException(
|
||||
ProgramLogger.LogException(
|
||||
$"|UWP|All|{p.InstalledLocation}|An unexpected error occurred and "
|
||||
+ $"unable to convert Package to UWP for {p.FullName}", e);
|
||||
return Array.Empty<UWPApplication>();
|
||||
}
|
||||
|
||||
|
||||
return u.Apps;
|
||||
}).ToArray();
|
||||
|
||||
@@ -192,8 +192,8 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
{
|
||||
ProgramLogger.LogException("UWP", "CurrentUserPackages", $"id", "An unexpected error occurred and unable to verify if package is valid", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return valid;
|
||||
});
|
||||
|
||||
@@ -230,8 +230,8 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
Unknown,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1714:Flags enums should have plural names", Justification = "This name is consistent with the corresponding win32 flags: https://docs.microsoft.com/en-us/windows/win32/stg/stgm-constants ")]
|
||||
[Flags]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1714:Flags enums should have plural names", Justification = "This name is consistent with the corresponding win32 flags: https://docs.microsoft.com/en-us/windows/win32/stg/stgm-constants ")]
|
||||
public enum Stgm : long
|
||||
{
|
||||
Read = 0x00000000L,
|
||||
@@ -240,6 +240,6 @@ namespace Microsoft.Plugin.Program.Programs
|
||||
public enum Hresult : int
|
||||
{
|
||||
Ok = 0x0,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -16,481 +16,481 @@ using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Microsoft.Plugin.Program.Logger;
|
||||
using Microsoft.Plugin.Program.Win32;
|
||||
using Microsoft.Plugin.Program.Win32;
|
||||
using Wox.Infrastructure;
|
||||
using Wox.Infrastructure.Image;
|
||||
using Wox.Infrastructure.Logger;
|
||||
using Wox.Infrastructure.Image;
|
||||
using Wox.Infrastructure.Logger;
|
||||
using Wox.Plugin;
|
||||
using Wox.Plugin.SharedCommands;
|
||||
using static Microsoft.Plugin.Program.Programs.UWP;
|
||||
|
||||
namespace Microsoft.Plugin.Program.Programs
|
||||
{
|
||||
[Serializable]
|
||||
public class UWPApplication : IProgram
|
||||
{
|
||||
public string AppListEntry { get; set; }
|
||||
|
||||
public string UniqueIdentifier { get; set; }
|
||||
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
public string UserModelId { get; set; }
|
||||
|
||||
public string BackgroundColor { get; set; }
|
||||
|
||||
public string EntryPoint { get; set; }
|
||||
|
||||
public string Name => DisplayName;
|
||||
|
||||
public string Location => Package.Location;
|
||||
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
public bool CanRunElevated { get; set; }
|
||||
|
||||
public string LogoPath { get; set; }
|
||||
|
||||
public UWP Package { get; set; }
|
||||
|
||||
private string logoUri;
|
||||
|
||||
// Function to calculate the score of a result
|
||||
private int Score(string query)
|
||||
{
|
||||
var displayNameMatch = StringMatcher.FuzzySearch(query, DisplayName);
|
||||
var descriptionMatch = StringMatcher.FuzzySearch(query, Description);
|
||||
var score = new[] { displayNameMatch.Score, descriptionMatch.Score / 2 }.Max();
|
||||
return score;
|
||||
}
|
||||
|
||||
// Function to set the subtitle based on the Type of application
|
||||
private static string SetSubtitle(IPublicAPI api)
|
||||
{
|
||||
return api.GetTranslation("powertoys_run_plugin_program_packaged_application");
|
||||
}
|
||||
|
||||
public Result Result(string query, IPublicAPI api)
|
||||
{
|
||||
if (api == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(api));
|
||||
}
|
||||
|
||||
var score = Score(query);
|
||||
if (score <= 0)
|
||||
{ // no need to create result if score is 0
|
||||
return null;
|
||||
}
|
||||
|
||||
var result = new Result
|
||||
{
|
||||
SubTitle = SetSubtitle(api),
|
||||
Icon = Logo,
|
||||
Score = score,
|
||||
ContextData = this,
|
||||
Action = e =>
|
||||
{
|
||||
Launch(api);
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
// To set the title to always be the displayname of the packaged application
|
||||
result.Title = DisplayName;
|
||||
result.TitleHighlightData = StringMatcher.FuzzySearch(query, Name).MatchData;
|
||||
|
||||
var toolTipTitle = string.Format(CultureInfo.CurrentCulture, "{0}: {1}", api.GetTranslation("powertoys_run_plugin_program_file_name"), result.Title);
|
||||
var toolTipText = string.Format(CultureInfo.CurrentCulture, "{0}: {1}", api.GetTranslation("powertoys_run_plugin_program_file_path"), Package.Location);
|
||||
result.ToolTipData = new ToolTipData(toolTipTitle, toolTipText);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Intentially keeping the process alive.")]
|
||||
public List<ContextMenuResult> ContextMenus(IPublicAPI api)
|
||||
{
|
||||
if (api == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(api));
|
||||
}
|
||||
|
||||
var contextMenus = new List<ContextMenuResult>();
|
||||
|
||||
if (CanRunElevated)
|
||||
{
|
||||
contextMenus.Add(
|
||||
new ContextMenuResult
|
||||
{
|
||||
PluginName = Assembly.GetExecutingAssembly().GetName().Name,
|
||||
Title = api.GetTranslation("wox_plugin_program_run_as_administrator"),
|
||||
Glyph = "\xE7EF",
|
||||
FontFamily = "Segoe MDL2 Assets",
|
||||
AcceleratorKey = Key.Enter,
|
||||
AcceleratorModifiers = ModifierKeys.Control | ModifierKeys.Shift,
|
||||
Action = _ =>
|
||||
{
|
||||
string command = "shell:AppsFolder\\" + UniqueIdentifier;
|
||||
command = Environment.ExpandEnvironmentVariables(command.Trim());
|
||||
|
||||
var info = ShellCommand.SetProcessStartInfo(command, verb: "runas");
|
||||
info.UseShellExecute = true;
|
||||
|
||||
Process.Start(info);
|
||||
return true;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
contextMenus.Add(
|
||||
new ContextMenuResult
|
||||
{
|
||||
PluginName = Assembly.GetExecutingAssembly().GetName().Name,
|
||||
Title = api.GetTranslation("wox_plugin_program_open_containing_folder"),
|
||||
Glyph = "\xE838",
|
||||
FontFamily = "Segoe MDL2 Assets",
|
||||
AcceleratorKey = Key.E,
|
||||
AcceleratorModifiers = ModifierKeys.Control | ModifierKeys.Shift,
|
||||
Action = _ =>
|
||||
{
|
||||
Main.StartProcess(Process.Start, new ProcessStartInfo("explorer", Package.Location));
|
||||
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
contextMenus.Add(new ContextMenuResult
|
||||
{
|
||||
PluginName = Assembly.GetExecutingAssembly().GetName().Name,
|
||||
Title = api.GetTranslation("wox_plugin_program_open_in_console"),
|
||||
Glyph = "\xE756",
|
||||
FontFamily = "Segoe MDL2 Assets",
|
||||
AcceleratorKey = Key.C,
|
||||
AcceleratorModifiers = ModifierKeys.Control | ModifierKeys.Shift,
|
||||
Action = (context) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Helper.OpenInConsole(Package.Location);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Exception($"|Microsoft.Plugin.Program.UWP.ContextMenu| Failed to open {Name} in console, {e.Message}", e);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return contextMenus;
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Intentially keeping the process alive, and showing the user an error message")]
|
||||
private async void Launch(IPublicAPI api)
|
||||
{
|
||||
var appManager = new ApplicationActivationHelper.ApplicationActivationManager();
|
||||
const string noArgs = "";
|
||||
const ApplicationActivationHelper.ActivateOptions noFlags = ApplicationActivationHelper.ActivateOptions.None;
|
||||
await Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
appManager.ActivateApplication(UserModelId, noArgs, noFlags, out uint unusedPid);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
var name = "Plugin: Program";
|
||||
var message = $"Can't start UWP: {DisplayName}";
|
||||
api.ShowMsg(name, message, string.Empty);
|
||||
}
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public UWPApplication(IAppxManifestApplication manifestApp, UWP package)
|
||||
{
|
||||
if (manifestApp == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(manifestApp));
|
||||
}
|
||||
|
||||
var hr = manifestApp.GetAppUserModelId(out var tmpUserModelId);
|
||||
UserModelId = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, tmpUserModelId);
|
||||
|
||||
hr = manifestApp.GetAppUserModelId(out var tmpUniqueIdentifier);
|
||||
UniqueIdentifier = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, tmpUniqueIdentifier);
|
||||
|
||||
hr = manifestApp.GetStringValue("DisplayName", out var tmpDisplayName);
|
||||
DisplayName = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, tmpDisplayName);
|
||||
|
||||
hr = manifestApp.GetStringValue("Description", out var tmpDescription);
|
||||
Description = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, tmpDescription);
|
||||
|
||||
hr = manifestApp.GetStringValue("BackgroundColor", out var tmpBackgroundColor);
|
||||
BackgroundColor = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, tmpBackgroundColor);
|
||||
|
||||
hr = manifestApp.GetStringValue("EntryPoint", out var tmpEntryPoint);
|
||||
EntryPoint = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, tmpEntryPoint);
|
||||
using static Microsoft.Plugin.Program.Programs.UWP;
|
||||
|
||||
Package = package ?? throw new ArgumentNullException(nameof(package));
|
||||
|
||||
DisplayName = ResourceFromPri(package.FullName, DisplayName);
|
||||
Description = ResourceFromPri(package.FullName, Description);
|
||||
logoUri = LogoUriFromManifest(manifestApp);
|
||||
|
||||
Enabled = true;
|
||||
CanRunElevated = IfApplicationcanRunElevated();
|
||||
}
|
||||
|
||||
private bool IfApplicationcanRunElevated()
|
||||
{
|
||||
if (EntryPoint == "Windows.FullTrustApplication")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
var manifest = Package.Location + "\\AppxManifest.xml";
|
||||
if (File.Exists(manifest))
|
||||
{
|
||||
var file = File.ReadAllText(manifest);
|
||||
if (file.Contains("TrustLevel=\"mediumIL\"", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal string ResourceFromPri(string packageFullName, string resourceReference)
|
||||
{
|
||||
const string prefix = "ms-resource:";
|
||||
if (!string.IsNullOrWhiteSpace(resourceReference) && resourceReference.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// 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("//", StringComparison.Ordinal))
|
||||
{
|
||||
parsed = prefix + key;
|
||||
}
|
||||
else if (key.StartsWith("/", StringComparison.Ordinal))
|
||||
{
|
||||
parsed = prefix + "//" + key;
|
||||
}
|
||||
else if (key.Contains("resources", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
parsed = prefix + key;
|
||||
}
|
||||
else
|
||||
{
|
||||
parsed = prefix + "///resources/" + key;
|
||||
}
|
||||
|
||||
var outBuffer = new StringBuilder(128);
|
||||
string source = $"@{{{packageFullName}? {parsed}}}";
|
||||
var capacity = (uint)outBuffer.Capacity;
|
||||
var hResult = NativeMethods.SHLoadIndirectString(source, outBuffer, capacity, IntPtr.Zero);
|
||||
if (hResult == Hresult.Ok)
|
||||
{
|
||||
var loaded = outBuffer.ToString();
|
||||
if (!string.IsNullOrEmpty(loaded))
|
||||
{
|
||||
return loaded;
|
||||
}
|
||||
else
|
||||
{
|
||||
ProgramLogger.LogException(
|
||||
$"|UWP|ResourceFromPri|{Package.Location}|Can't load null or empty result "
|
||||
+ $"pri {source} in uwp location {Package.Location}", new NullReferenceException());
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// https://github.com/Wox-launcher/Wox/issues/964
|
||||
// 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 e = Marshal.GetExceptionForHR((int)hResult);
|
||||
ProgramLogger.LogException($"|UWP|ResourceFromPri|{Package.Location}|Load pri failed {source} with HResult {hResult} and location {Package.Location}", e);
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return resourceReference;
|
||||
}
|
||||
}
|
||||
|
||||
internal string LogoUriFromManifest(IAppxManifestApplication app)
|
||||
{
|
||||
namespace Microsoft.Plugin.Program.Programs
|
||||
{
|
||||
[Serializable]
|
||||
public class UWPApplication : IProgram
|
||||
{
|
||||
public string AppListEntry { get; set; }
|
||||
|
||||
public string UniqueIdentifier { get; set; }
|
||||
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
public string UserModelId { get; set; }
|
||||
|
||||
public string BackgroundColor { get; set; }
|
||||
|
||||
public string EntryPoint { get; set; }
|
||||
|
||||
public string Name => DisplayName;
|
||||
|
||||
public string Location => Package.Location;
|
||||
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
public bool CanRunElevated { get; set; }
|
||||
|
||||
public string LogoPath { get; set; }
|
||||
|
||||
public UWP Package { get; set; }
|
||||
|
||||
private string logoUri;
|
||||
|
||||
// Function to calculate the score of a result
|
||||
private int Score(string query)
|
||||
{
|
||||
var displayNameMatch = StringMatcher.FuzzySearch(query, DisplayName);
|
||||
var descriptionMatch = StringMatcher.FuzzySearch(query, Description);
|
||||
var score = new[] { displayNameMatch.Score, descriptionMatch.Score / 2 }.Max();
|
||||
return score;
|
||||
}
|
||||
|
||||
// Function to set the subtitle based on the Type of application
|
||||
private static string SetSubtitle(IPublicAPI api)
|
||||
{
|
||||
return api.GetTranslation("powertoys_run_plugin_program_packaged_application");
|
||||
}
|
||||
|
||||
public Result Result(string query, IPublicAPI api)
|
||||
{
|
||||
if (api == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(api));
|
||||
}
|
||||
|
||||
var score = Score(query);
|
||||
if (score <= 0)
|
||||
{ // no need to create result if score is 0
|
||||
return null;
|
||||
}
|
||||
|
||||
var result = new Result
|
||||
{
|
||||
SubTitle = SetSubtitle(api),
|
||||
Icon = Logo,
|
||||
Score = score,
|
||||
ContextData = this,
|
||||
Action = e =>
|
||||
{
|
||||
Launch(api);
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
// To set the title to always be the displayname of the packaged application
|
||||
result.Title = DisplayName;
|
||||
result.TitleHighlightData = StringMatcher.FuzzySearch(query, Name).MatchData;
|
||||
|
||||
var toolTipTitle = string.Format(CultureInfo.CurrentCulture, "{0}: {1}", api.GetTranslation("powertoys_run_plugin_program_file_name"), result.Title);
|
||||
var toolTipText = string.Format(CultureInfo.CurrentCulture, "{0}: {1}", api.GetTranslation("powertoys_run_plugin_program_file_path"), Package.Location);
|
||||
result.ToolTipData = new ToolTipData(toolTipTitle, toolTipText);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Intentially keeping the process alive.")]
|
||||
public List<ContextMenuResult> ContextMenus(IPublicAPI api)
|
||||
{
|
||||
if (api == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(api));
|
||||
}
|
||||
|
||||
var contextMenus = new List<ContextMenuResult>();
|
||||
|
||||
if (CanRunElevated)
|
||||
{
|
||||
contextMenus.Add(
|
||||
new ContextMenuResult
|
||||
{
|
||||
PluginName = Assembly.GetExecutingAssembly().GetName().Name,
|
||||
Title = api.GetTranslation("wox_plugin_program_run_as_administrator"),
|
||||
Glyph = "\xE7EF",
|
||||
FontFamily = "Segoe MDL2 Assets",
|
||||
AcceleratorKey = Key.Enter,
|
||||
AcceleratorModifiers = ModifierKeys.Control | ModifierKeys.Shift,
|
||||
Action = _ =>
|
||||
{
|
||||
string command = "shell:AppsFolder\\" + UniqueIdentifier;
|
||||
command = Environment.ExpandEnvironmentVariables(command.Trim());
|
||||
|
||||
var info = ShellCommand.SetProcessStartInfo(command, verb: "runas");
|
||||
info.UseShellExecute = true;
|
||||
|
||||
Process.Start(info);
|
||||
return true;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
contextMenus.Add(
|
||||
new ContextMenuResult
|
||||
{
|
||||
PluginName = Assembly.GetExecutingAssembly().GetName().Name,
|
||||
Title = api.GetTranslation("wox_plugin_program_open_containing_folder"),
|
||||
Glyph = "\xE838",
|
||||
FontFamily = "Segoe MDL2 Assets",
|
||||
AcceleratorKey = Key.E,
|
||||
AcceleratorModifiers = ModifierKeys.Control | ModifierKeys.Shift,
|
||||
Action = _ =>
|
||||
{
|
||||
Main.StartProcess(Process.Start, new ProcessStartInfo("explorer", Package.Location));
|
||||
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
contextMenus.Add(new ContextMenuResult
|
||||
{
|
||||
PluginName = Assembly.GetExecutingAssembly().GetName().Name,
|
||||
Title = api.GetTranslation("wox_plugin_program_open_in_console"),
|
||||
Glyph = "\xE756",
|
||||
FontFamily = "Segoe MDL2 Assets",
|
||||
AcceleratorKey = Key.C,
|
||||
AcceleratorModifiers = ModifierKeys.Control | ModifierKeys.Shift,
|
||||
Action = (context) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Helper.OpenInConsole(Package.Location);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Exception($"|Microsoft.Plugin.Program.UWP.ContextMenu| Failed to open {Name} in console, {e.Message}", e);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return contextMenus;
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Intentially keeping the process alive, and showing the user an error message")]
|
||||
private async void Launch(IPublicAPI api)
|
||||
{
|
||||
var appManager = new ApplicationActivationHelper.ApplicationActivationManager();
|
||||
const string noArgs = "";
|
||||
const ApplicationActivationHelper.ActivateOptions noFlags = ApplicationActivationHelper.ActivateOptions.None;
|
||||
await Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
appManager.ActivateApplication(UserModelId, noArgs, noFlags, out uint unusedPid);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
var name = "Plugin: Program";
|
||||
var message = $"Can't start UWP: {DisplayName}";
|
||||
api.ShowMsg(name, message, string.Empty);
|
||||
}
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public UWPApplication(IAppxManifestApplication manifestApp, UWP package)
|
||||
{
|
||||
if (manifestApp == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(manifestApp));
|
||||
}
|
||||
|
||||
var hr = manifestApp.GetAppUserModelId(out var tmpUserModelId);
|
||||
UserModelId = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, tmpUserModelId);
|
||||
|
||||
hr = manifestApp.GetAppUserModelId(out var tmpUniqueIdentifier);
|
||||
UniqueIdentifier = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, tmpUniqueIdentifier);
|
||||
|
||||
hr = manifestApp.GetStringValue("DisplayName", out var tmpDisplayName);
|
||||
DisplayName = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, tmpDisplayName);
|
||||
|
||||
hr = manifestApp.GetStringValue("Description", out var tmpDescription);
|
||||
Description = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, tmpDescription);
|
||||
|
||||
hr = manifestApp.GetStringValue("BackgroundColor", out var tmpBackgroundColor);
|
||||
BackgroundColor = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, tmpBackgroundColor);
|
||||
|
||||
hr = manifestApp.GetStringValue("EntryPoint", out var tmpEntryPoint);
|
||||
EntryPoint = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, tmpEntryPoint);
|
||||
|
||||
Package = package ?? throw new ArgumentNullException(nameof(package));
|
||||
|
||||
DisplayName = ResourceFromPri(package.FullName, DisplayName);
|
||||
Description = ResourceFromPri(package.FullName, Description);
|
||||
logoUri = LogoUriFromManifest(manifestApp);
|
||||
|
||||
Enabled = true;
|
||||
CanRunElevated = IfApplicationcanRunElevated();
|
||||
}
|
||||
|
||||
private bool IfApplicationcanRunElevated()
|
||||
{
|
||||
if (EntryPoint == "Windows.FullTrustApplication")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
var manifest = Package.Location + "\\AppxManifest.xml";
|
||||
if (File.Exists(manifest))
|
||||
{
|
||||
var file = File.ReadAllText(manifest);
|
||||
if (file.Contains("TrustLevel=\"mediumIL\"", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal string ResourceFromPri(string packageFullName, string resourceReference)
|
||||
{
|
||||
const string prefix = "ms-resource:";
|
||||
if (!string.IsNullOrWhiteSpace(resourceReference) && resourceReference.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// 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("//", StringComparison.Ordinal))
|
||||
{
|
||||
parsed = prefix + key;
|
||||
}
|
||||
else if (key.StartsWith("/", StringComparison.Ordinal))
|
||||
{
|
||||
parsed = prefix + "//" + key;
|
||||
}
|
||||
else if (key.Contains("resources", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
parsed = prefix + key;
|
||||
}
|
||||
else
|
||||
{
|
||||
parsed = prefix + "///resources/" + key;
|
||||
}
|
||||
|
||||
var outBuffer = new StringBuilder(128);
|
||||
string source = $"@{{{packageFullName}? {parsed}}}";
|
||||
var capacity = (uint)outBuffer.Capacity;
|
||||
var hResult = NativeMethods.SHLoadIndirectString(source, outBuffer, capacity, IntPtr.Zero);
|
||||
if (hResult == Hresult.Ok)
|
||||
{
|
||||
var loaded = outBuffer.ToString();
|
||||
if (!string.IsNullOrEmpty(loaded))
|
||||
{
|
||||
return loaded;
|
||||
}
|
||||
else
|
||||
{
|
||||
ProgramLogger.LogException(
|
||||
$"|UWP|ResourceFromPri|{Package.Location}|Can't load null or empty result "
|
||||
+ $"pri {source} in uwp location {Package.Location}", new NullReferenceException());
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// https://github.com/Wox-launcher/Wox/issues/964
|
||||
// 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 e = Marshal.GetExceptionForHR((int)hResult);
|
||||
ProgramLogger.LogException($"|UWP|ResourceFromPri|{Package.Location}|Load pri failed {source} with HResult {hResult} and location {Package.Location}", e);
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return resourceReference;
|
||||
}
|
||||
}
|
||||
|
||||
internal string LogoUriFromManifest(IAppxManifestApplication app)
|
||||
{
|
||||
var logoKeyFromVersion = new Dictionary<PackageVersion, string>
|
||||
{
|
||||
{ PackageVersion.Windows10, "Square44x44Logo" },
|
||||
{ PackageVersion.Windows81, "Square30x30Logo" },
|
||||
{ PackageVersion.Windows8, "SmallLogo" },
|
||||
};
|
||||
if (logoKeyFromVersion.ContainsKey(Package.Version))
|
||||
{
|
||||
var key = logoKeyFromVersion[Package.Version];
|
||||
var hr = app.GetStringValue(key, out var logoUri);
|
||||
_ = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, logoUri);
|
||||
return logoUri;
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdatePath(Theme theme)
|
||||
{
|
||||
if (theme == Theme.Light || theme == Theme.HighContrastWhite)
|
||||
{
|
||||
LogoPath = LogoPathFromUri(logoUri, "contrast-white");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogoPath = LogoPathFromUri(logoUri, "contrast-black");
|
||||
}
|
||||
}
|
||||
|
||||
internal string LogoPathFromUri(string uri, string theme)
|
||||
{
|
||||
// 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("\\", StringComparison.Ordinal))
|
||||
{
|
||||
path = Path.Combine(Package.Location, uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
// for C:\Windows\MiracastView etc
|
||||
path = Path.Combine(Package.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 };
|
||||
|
||||
};
|
||||
if (logoKeyFromVersion.ContainsKey(Package.Version))
|
||||
{
|
||||
var key = logoKeyFromVersion[Package.Version];
|
||||
var hr = app.GetStringValue(key, out var logoUri);
|
||||
_ = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, logoUri);
|
||||
return logoUri;
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdatePath(Theme theme)
|
||||
{
|
||||
if (theme == Theme.Light || theme == Theme.HighContrastWhite)
|
||||
{
|
||||
LogoPath = LogoPathFromUri(logoUri, "contrast-white");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogoPath = LogoPathFromUri(logoUri, "contrast-black");
|
||||
}
|
||||
}
|
||||
|
||||
internal string LogoPathFromUri(string uri, string theme)
|
||||
{
|
||||
// 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("\\", StringComparison.Ordinal))
|
||||
{
|
||||
path = Path.Combine(Package.Location, uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
// for C:\Windows\MiracastView etc
|
||||
path = Path.Combine(Package.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 };
|
||||
|
||||
var scaleFactors = new Dictionary<PackageVersion, List<int>>
|
||||
{
|
||||
// scale factors on win10: https://docs.microsoft.com/en-us/windows/uwp/controls-and-patterns/tiles-and-notifications-app-assets#asset-size-tables,
|
||||
{ PackageVersion.Windows10, new List<int> { 100, 125, 150, 200, 400 } },
|
||||
{ PackageVersion.Windows81, new List<int> { 100, 120, 140, 160, 180 } },
|
||||
{ PackageVersion.Windows8, new List<int> { 100 } },
|
||||
};
|
||||
|
||||
if (scaleFactors.ContainsKey(Package.Version))
|
||||
{
|
||||
foreach (var factor in scaleFactors[Package.Version])
|
||||
{
|
||||
paths.Add($"{prefix}.scale-{factor}{extension}");
|
||||
paths.Add($"{prefix}.scale-{factor}_{theme}{extension}");
|
||||
paths.Add($"{prefix}.{theme}_scale-{factor}{extension}");
|
||||
}
|
||||
}
|
||||
|
||||
paths = paths.OrderByDescending(x => x.Contains(theme, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
var selected = paths.FirstOrDefault(File.Exists);
|
||||
if (!string.IsNullOrEmpty(selected))
|
||||
{
|
||||
return selected;
|
||||
}
|
||||
else
|
||||
{
|
||||
int appIconSize = 36;
|
||||
var targetSizes = new List<int> { 16, 24, 30, 36, 44, 60, 72, 96, 128, 180, 256 }.AsParallel();
|
||||
Dictionary<string, int> pathFactorPairs = new Dictionary<string, int>();
|
||||
|
||||
foreach (var factor in targetSizes)
|
||||
{
|
||||
string simplePath = $"{prefix}.targetsize-{factor}{extension}";
|
||||
string suffixThemePath = $"{prefix}.targetsize-{factor}_{theme}{extension}";
|
||||
string prefixThemePath = $"{prefix}.{theme}_targetsize-{factor}{extension}";
|
||||
|
||||
paths.Add(simplePath);
|
||||
paths.Add(suffixThemePath);
|
||||
paths.Add(prefixThemePath);
|
||||
|
||||
pathFactorPairs.Add(simplePath, factor);
|
||||
pathFactorPairs.Add(suffixThemePath, factor);
|
||||
pathFactorPairs.Add(prefixThemePath, factor);
|
||||
}
|
||||
|
||||
paths = paths.OrderByDescending(x => x.Contains(theme, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
var selectedIconPath = paths.OrderBy(x => Math.Abs(pathFactorPairs.GetValueOrDefault(x) - appIconSize)).FirstOrDefault(File.Exists);
|
||||
if (!string.IsNullOrEmpty(selectedIconPath))
|
||||
{
|
||||
return selectedIconPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
ProgramLogger.LogException(
|
||||
$"|UWP|LogoPathFromUri|{Package.Location}" +
|
||||
$"|{UserModelId} can't find logo uri for {uri} in package location: {Package.Location}", new FileNotFoundException());
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ProgramLogger.LogException(
|
||||
$"|UWP|LogoPathFromUri|{Package.Location}" +
|
||||
$"|Unable to find extension from {uri} for {UserModelId} " +
|
||||
$"in package location {Package.Location}", new FileNotFoundException());
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public ImageSource Logo()
|
||||
{
|
||||
var logo = ImageFromPath(LogoPath);
|
||||
return logo;
|
||||
}
|
||||
|
||||
private BitmapImage ImageFromPath(string path)
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
|
||||
byte[] fileBytes = File.ReadAllBytes(path);
|
||||
memoryStream.Write(fileBytes, 0, fileBytes.Length);
|
||||
memoryStream.Position = 0;
|
||||
|
||||
var image = new BitmapImage();
|
||||
image.BeginInit();
|
||||
image.StreamSource = memoryStream;
|
||||
image.EndInit();
|
||||
return image;
|
||||
}
|
||||
else
|
||||
{
|
||||
ProgramLogger.LogException(
|
||||
$"|UWP|ImageFromPath|{path}" +
|
||||
$"|Unable to get logo for {UserModelId} from {path} and" +
|
||||
$" located in {Package.Location}", new FileNotFoundException());
|
||||
return new BitmapImage(new Uri(ImageLoader.ErrorIconPath));
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{DisplayName}: {Description}";
|
||||
}
|
||||
};
|
||||
|
||||
if (scaleFactors.ContainsKey(Package.Version))
|
||||
{
|
||||
foreach (var factor in scaleFactors[Package.Version])
|
||||
{
|
||||
paths.Add($"{prefix}.scale-{factor}{extension}");
|
||||
paths.Add($"{prefix}.scale-{factor}_{theme}{extension}");
|
||||
paths.Add($"{prefix}.{theme}_scale-{factor}{extension}");
|
||||
}
|
||||
}
|
||||
|
||||
paths = paths.OrderByDescending(x => x.Contains(theme, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
var selected = paths.FirstOrDefault(File.Exists);
|
||||
if (!string.IsNullOrEmpty(selected))
|
||||
{
|
||||
return selected;
|
||||
}
|
||||
else
|
||||
{
|
||||
int appIconSize = 36;
|
||||
var targetSizes = new List<int> { 16, 24, 30, 36, 44, 60, 72, 96, 128, 180, 256 }.AsParallel();
|
||||
Dictionary<string, int> pathFactorPairs = new Dictionary<string, int>();
|
||||
|
||||
foreach (var factor in targetSizes)
|
||||
{
|
||||
string simplePath = $"{prefix}.targetsize-{factor}{extension}";
|
||||
string suffixThemePath = $"{prefix}.targetsize-{factor}_{theme}{extension}";
|
||||
string prefixThemePath = $"{prefix}.{theme}_targetsize-{factor}{extension}";
|
||||
|
||||
paths.Add(simplePath);
|
||||
paths.Add(suffixThemePath);
|
||||
paths.Add(prefixThemePath);
|
||||
|
||||
pathFactorPairs.Add(simplePath, factor);
|
||||
pathFactorPairs.Add(suffixThemePath, factor);
|
||||
pathFactorPairs.Add(prefixThemePath, factor);
|
||||
}
|
||||
|
||||
paths = paths.OrderByDescending(x => x.Contains(theme, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
var selectedIconPath = paths.OrderBy(x => Math.Abs(pathFactorPairs.GetValueOrDefault(x) - appIconSize)).FirstOrDefault(File.Exists);
|
||||
if (!string.IsNullOrEmpty(selectedIconPath))
|
||||
{
|
||||
return selectedIconPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
ProgramLogger.LogException(
|
||||
$"|UWP|LogoPathFromUri|{Package.Location}" +
|
||||
$"|{UserModelId} can't find logo uri for {uri} in package location: {Package.Location}", new FileNotFoundException());
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ProgramLogger.LogException(
|
||||
$"|UWP|LogoPathFromUri|{Package.Location}" +
|
||||
$"|Unable to find extension from {uri} for {UserModelId} " +
|
||||
$"in package location {Package.Location}", new FileNotFoundException());
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public ImageSource Logo()
|
||||
{
|
||||
var logo = ImageFromPath(LogoPath);
|
||||
return logo;
|
||||
}
|
||||
|
||||
private BitmapImage ImageFromPath(string path)
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
|
||||
byte[] fileBytes = File.ReadAllBytes(path);
|
||||
memoryStream.Write(fileBytes, 0, fileBytes.Length);
|
||||
memoryStream.Position = 0;
|
||||
|
||||
var image = new BitmapImage();
|
||||
image.BeginInit();
|
||||
image.StreamSource = memoryStream;
|
||||
image.EndInit();
|
||||
return image;
|
||||
}
|
||||
else
|
||||
{
|
||||
ProgramLogger.LogException(
|
||||
$"|UWP|ImageFromPath|{path}" +
|
||||
$"|Unable to get logo for {UserModelId} from {path} and" +
|
||||
$" located in {Package.Location}", new FileNotFoundException());
|
||||
return new BitmapImage(new Uri(ImageLoader.ErrorIconPath));
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{DisplayName}: {Description}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user