2019-10-27 16:04:10 +08:00
using System ;
2016-08-18 08:16:40 +08:00
using System.Collections.Generic ;
2016-08-22 09:21:22 +08:00
using System.Diagnostics ;
2016-08-18 08:16:40 +08:00
using System.IO ;
using System.Linq ;
using System.Runtime.InteropServices ;
using System.Security.Principal ;
2016-11-29 09:18:38 +08:00
using System.Text ;
using System.Threading.Tasks ;
2016-08-18 08:56:26 +08:00
using System.Windows.Media ;
2016-08-18 08:16:40 +08:00
using System.Windows.Media.Imaging ;
2016-11-29 09:18:38 +08:00
using System.Xml.Linq ;
2016-08-18 08:16:40 +08:00
using Windows.ApplicationModel ;
2016-08-20 06:24:21 +08:00
using Windows.Management.Deployment ;
2016-08-18 08:16:40 +08:00
using AppxPackaing ;
using Shell ;
2016-08-20 08:17:28 +08:00
using Wox.Infrastructure ;
2019-10-25 10:11:52 +08:00
using Wox.Plugin.Program.Logger ;
2016-08-18 08:16:40 +08:00
using IStream = AppxPackaing . IStream ;
2016-08-20 06:24:21 +08:00
using Rect = System . Windows . Rect ;
2016-08-18 08:16:40 +08:00
2016-08-20 08:17:28 +08:00
namespace Wox.Plugin.Program.Programs
2016-08-18 08:16:40 +08:00
{
2017-01-13 09:21:00 +08:00
[Serializable]
2016-08-18 08:56:26 +08:00
public class UWP
2016-08-18 08:16:40 +08:00
{
public string Name { get ; }
public string FullName { get ; }
public string FamilyName { get ; }
public string Location { get ; set ; }
public Application [ ] Apps { get ; set ; }
2016-11-29 09:18:38 +08:00
public PackageVersion Version { get ; set ; }
2016-08-18 08:56:26 +08:00
public UWP ( Package package )
2016-08-18 08:16:40 +08:00
{
2017-01-13 09:21:00 +08:00
Location = package . InstalledLocation . Path ;
Name = package . Id . Name ;
FullName = package . Id . FullName ;
FamilyName = package . Id . FamilyName ;
2016-11-29 09:18:38 +08:00
InitializeAppInfo ( ) ;
Apps = Apps . Where ( a = >
{
var valid =
! string . IsNullOrEmpty ( a . UserModelId ) & &
! string . IsNullOrEmpty ( a . DisplayName ) ;
return valid ;
} ) . ToArray ( ) ;
2016-08-18 08:16:40 +08:00
}
2016-11-29 09:18:38 +08:00
private void InitializeAppInfo ( )
2016-08-18 08:16:40 +08:00
{
2016-08-19 10:00:52 +08:00
var path = Path . Combine ( Location , "AppxManifest.xml" ) ;
2016-11-29 09:18:38 +08:00
var namespaces = XmlNamespaces ( path ) ;
InitPackageVersion ( namespaces ) ;
var appxFactory = new AppxFactory ( ) ;
2016-08-19 10:00:52 +08:00
IStream stream ;
const uint noAttribute = 0x80 ;
const Stgm exclusiveRead = Stgm . Read | Stgm . ShareExclusive ;
2016-11-29 09:55:25 +08:00
var hResult = SHCreateStreamOnFileEx ( path , exclusiveRead , noAttribute , false , null , out stream ) ;
2016-08-18 08:16:40 +08:00
2016-11-29 09:55:25 +08:00
if ( hResult = = Hresult . Ok )
2016-08-18 08:16:40 +08:00
{
2016-11-29 09:18:38 +08:00
var reader = appxFactory . CreateManifestReader ( stream ) ;
var manifestApps = reader . GetApplications ( ) ;
var apps = new List < Application > ( ) ;
while ( manifestApps . GetHasCurrent ( ) ! = 0 )
2016-08-18 08:16:40 +08:00
{
2016-11-29 09:18:38 +08:00
var manifestApp = manifestApps . GetCurrent ( ) ;
var appListEntry = manifestApp . GetStringValue ( "AppListEntry" ) ;
2016-09-06 04:58:40 +08:00
if ( appListEntry ! = "none" )
2016-08-21 02:19:33 +08:00
{
2016-11-29 09:46:29 +08:00
var app = new Application ( manifestApp , this ) ;
2016-11-29 09:18:38 +08:00
apps . Add ( app ) ;
2016-08-21 02:19:33 +08:00
}
2016-11-29 09:18:38 +08:00
manifestApps . MoveNext ( ) ;
}
Apps = apps . Where ( a = > a . AppListEntry ! = "none" ) . ToArray ( ) ;
}
2016-11-29 09:55:25 +08:00
else
{
2017-01-24 08:24:20 +08:00
var e = Marshal . GetExceptionForHR ( ( int ) hResult ) ;
2019-10-25 10:11:52 +08:00
ProgramLogger . LogException ( $"|UWP|InitializeAppInfo|{path}" +
"|Error caused while trying to get the details of the UWP program" , e ) ;
2019-10-27 16:04:10 +08:00
Apps = new List < Application > ( ) . ToArray ( ) ;
2016-11-29 09:55:25 +08:00
}
2016-11-29 09:18:38 +08:00
}
2016-11-29 09:46:29 +08:00
2016-11-29 09:18:38 +08:00
/// http://www.hanselman.com/blog/GetNamespacesFromAnXMLDocumentWithXPathDocumentAndLINQToXML.aspx
2016-11-29 09:46:29 +08:00
private string [ ] XmlNamespaces ( string path )
2016-11-29 09:18:38 +08:00
{
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
{
2019-10-25 10:11:52 +08:00
ProgramLogger . LogException ( $"|UWP|XmlNamespaces|{path}" +
$"|Error occured while trying to get the XML from {path}" , new ArgumentNullException ( ) ) ;
2016-11-29 09:46:29 +08:00
return new string [ ] { } ;
2016-11-29 09:18:38 +08:00
}
}
private void InitPackageVersion ( string [ ] namespaces )
{
var versionFromNamespace = new Dictionary < string , PackageVersion >
{
{ "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 )
{
if ( namespaces . Contains ( n ) )
{
Version = versionFromNamespace [ n ] ;
return ;
2016-08-18 08:16:40 +08:00
}
2016-11-29 09:18:38 +08:00
}
2019-10-25 10:11:52 +08:00
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 ( ) ) ;
2016-11-29 09:18:38 +08:00
Version = PackageVersion . Unknown ;
}
2016-09-06 04:58:40 +08:00
2016-08-21 01:25:55 +08:00
public static Application [ ] All ( )
2016-08-18 08:16:40 +08:00
{
2016-08-20 08:17:28 +08:00
var windows10 = new Version ( 10 , 0 ) ;
var support = Environment . OSVersion . Version . Major > = windows10 . Major ;
if ( support )
2016-08-18 08:16:40 +08:00
{
2017-04-02 02:15:23 +08:00
var applications = CurrentUserPackages ( ) . AsParallel ( ) . SelectMany ( p = >
{
UWP u ;
try
{
u = new UWP ( p ) ;
}
2019-10-25 10:11:52 +08:00
#if ! DEBUG
2017-04-02 02:15:23 +08:00
catch ( Exception e )
{
2019-11-07 04:40:04 +08:00
ProgramLogger . LogException ( $"|UWP|All|{p.InstalledLocation}|An unexpected error occured and "
2019-10-25 10:11:52 +08:00
+ $"unable to convert Package to UWP for {p.Id.FullName}" , e ) ;
2017-04-02 02:15:23 +08:00
return new Application [ ] { } ;
}
2019-10-25 10:11:52 +08:00
#endif
#if DEBUG //make developer aware and implement handling
2019-11-16 08:37:01 +08:00
catch
2019-10-25 10:11:52 +08:00
{
2019-11-16 08:37:01 +08:00
throw ;
2019-10-25 10:11:52 +08:00
}
#endif
2017-04-02 02:15:23 +08:00
return u . Apps ;
} ) . ToArray ( ) ;
2019-09-10 05:57:03 +08:00
var updatedListWithoutDisabledApps = applications
2019-10-15 17:20:55 +08:00
. Where ( t1 = > ! Main . _settings . DisabledProgramSources
. Any ( x = > x . UniqueIdentifier = = t1 . UniqueIdentifier ) )
2019-09-10 05:57:03 +08:00
. Select ( x = > x ) ;
return updatedListWithoutDisabledApps . ToArray ( ) ;
2016-08-20 08:17:28 +08:00
}
else
{
2016-11-29 09:46:29 +08:00
return new Application [ ] { } ;
2016-08-20 08:17:28 +08:00
}
2016-08-18 08:16:40 +08:00
}
private static IEnumerable < Package > CurrentUserPackages ( )
{
2017-04-02 02:15:23 +08:00
var u = WindowsIdentity . GetCurrent ( ) . User ;
2016-08-18 08:16:40 +08:00
2017-04-02 02:15:23 +08:00
if ( u ! = null )
2016-08-18 08:16:40 +08:00
{
2017-04-02 02:15:23 +08:00
var id = u . Value ;
var m = new PackageManager ( ) ;
var ps = m . FindPackagesForUser ( id ) ;
ps = ps . Where ( p = >
{
bool valid ;
2019-11-02 03:44:55 +08:00
try
{
var f = p . IsFramework ;
var d = p . IsDevelopmentMode ;
var path = p . InstalledLocation . Path ;
valid = ! f & & ! d & & ! string . IsNullOrEmpty ( path ) ;
}
catch ( Exception e )
{
2019-11-16 06:57:30 +08:00
ProgramLogger . LogException ( "UWP" , "CurrentUserPackages" , $"id" , "An unexpected error occured and "
2019-11-02 03:44:55 +08:00
+ $"unable to verify if package is valid" , e ) ;
return false ;
}
2019-10-25 10:11:52 +08:00
2017-04-02 02:15:23 +08:00
return valid ;
} ) ;
return ps ;
2016-08-18 08:16:40 +08:00
}
else
{
2016-11-29 09:46:29 +08:00
return new Package [ ] { } ;
2016-08-18 08:16:40 +08:00
}
}
public override string ToString ( )
{
return FamilyName ;
}
public override bool Equals ( object obj )
{
2019-11-16 08:37:01 +08:00
if ( obj is UWP uwp )
2016-08-18 08:16:40 +08:00
{
return FamilyName . Equals ( uwp . FamilyName ) ;
}
else
{
return false ;
}
}
public override int GetHashCode ( )
{
return FamilyName . GetHashCode ( ) ;
}
2017-01-13 09:21:00 +08:00
[Serializable]
2016-08-22 09:21:22 +08:00
public class Application : IProgram
2016-08-18 08:16:40 +08:00
{
2016-11-29 09:18:38 +08:00
public string AppListEntry { get ; set ; }
2019-09-10 05:57:03 +08:00
public string UniqueIdentifier { get ; set ; }
2016-08-18 08:16:40 +08:00
public string DisplayName { get ; set ; }
public string Description { get ; set ; }
public string UserModelId { get ; set ; }
2016-08-18 08:56:26 +08:00
public string BackgroundColor { get ; set ; }
2016-08-21 01:50:14 +08:00
2019-10-17 19:47:00 +08:00
public string Name = > DisplayName ;
public string Location = > Package . Location ;
2019-09-08 20:18:55 +08:00
public bool Enabled { get ; set ; }
2016-11-29 09:18:38 +08:00
public string LogoUri { get ; set ; }
public string LogoPath { get ; set ; }
2016-11-29 09:46:29 +08:00
public UWP Package { get ; set ; }
2016-08-21 01:50:14 +08:00
2016-08-22 09:21:22 +08:00
private int Score ( string query )
{
2019-12-03 22:25:19 +08:00
var displayNameMatch = StringMatcher . FuzzySearch ( query , DisplayName ) ;
var descriptionMatch = StringMatcher . FuzzySearch ( query , Description ) ;
var score = new [ ] { displayNameMatch . Score , descriptionMatch . Score } . Max ( ) ;
2016-08-22 09:21:22 +08:00
return score ;
}
2016-08-18 08:16:40 +08:00
2016-08-22 09:21:22 +08:00
public Result Result ( string query , IPublicAPI api )
2016-08-18 08:16:40 +08:00
{
2019-11-29 07:38:50 +08:00
var score = Score ( query ) ;
if ( score < = 0 )
{ // no need to create result if score is 0
return null ;
}
2016-08-22 09:21:22 +08:00
var result = new Result
{
2016-11-29 09:55:11 +08:00
SubTitle = Package . Location ,
2016-08-22 09:21:22 +08:00
Icon = Logo ,
2019-11-29 07:38:50 +08:00
Score = score ,
2016-08-22 09:21:22 +08:00
ContextData = this ,
Action = e = >
{
Launch ( api ) ;
return true ;
}
} ;
if ( Description . Length > = DisplayName . Length & &
Description . Substring ( 0 , DisplayName . Length ) = = DisplayName )
{
result . Title = Description ;
2019-12-03 22:25:19 +08:00
result . TitleHighlightData = StringMatcher . FuzzySearch ( query , Description ) . MatchData ;
2016-08-22 09:21:22 +08:00
}
else if ( ! string . IsNullOrEmpty ( Description ) )
{
2019-12-12 02:08:52 +08:00
var title = $"{DisplayName}: {Description}" ;
result . Title = title ;
result . TitleHighlightData = StringMatcher . FuzzySearch ( query , title ) . MatchData ;
2016-08-22 09:21:22 +08:00
}
else
{
result . Title = DisplayName ;
2019-12-03 22:25:19 +08:00
result . TitleHighlightData = StringMatcher . FuzzySearch ( query , DisplayName ) . MatchData ;
2016-08-22 09:21:22 +08:00
}
return result ;
}
public List < Result > ContextMenus ( IPublicAPI api )
{
var contextMenus = new List < Result >
{
new Result
{
Title = api . GetTranslation ( "wox_plugin_program_open_containing_folder" ) ,
Action = _ = >
{
2019-12-10 19:01:12 +08:00
var hide = Main . StartProcess ( Process . Start , new ProcessStartInfo ( Package . Location ) ) ;
2016-08-22 09:21:22 +08:00
return hide ;
} ,
IcoPath = "Images/folder.png"
}
} ;
return contextMenus ;
}
2016-11-29 09:18:38 +08:00
private async void Launch ( IPublicAPI api )
2016-08-22 09:21:22 +08:00
{
2016-11-29 09:18:38 +08:00
var appManager = new ApplicationActivationManager ( ) ;
uint unusedPid ;
const string noArgs = "" ;
const ACTIVATEOPTIONS noFlags = ACTIVATEOPTIONS . AO_NONE ;
await Task . Run ( ( ) = >
2016-08-22 09:21:22 +08:00
{
2016-11-29 09:18:38 +08:00
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 ) ;
}
} ) ;
2016-08-18 08:16:40 +08:00
}
2016-11-29 09:46:29 +08:00
public Application ( IAppxManifestApplication manifestApp , UWP package )
{
UserModelId = manifestApp . GetAppUserModelId ( ) ;
2019-09-10 05:57:03 +08:00
UniqueIdentifier = manifestApp . GetAppUserModelId ( ) ;
2016-11-29 09:46:29 +08:00
DisplayName = manifestApp . GetStringValue ( "DisplayName" ) ;
Description = manifestApp . GetStringValue ( "Description" ) ;
BackgroundColor = manifestApp . GetStringValue ( "BackgroundColor" ) ;
Package = package ;
2016-11-29 09:55:11 +08:00
2016-11-29 09:46:29 +08:00
DisplayName = ResourceFromPri ( package . FullName , DisplayName ) ;
Description = ResourceFromPri ( package . FullName , Description ) ;
LogoUri = LogoUriFromManifest ( manifestApp ) ;
LogoPath = LogoPathFromUri ( LogoUri ) ;
2019-09-08 20:18:55 +08:00
Enabled = true ;
2016-11-29 09:46:29 +08:00
}
internal 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 + "///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 ) )
{
return loaded ;
}
else
{
2019-10-25 10:11:52 +08:00
ProgramLogger . LogException ( $"|UWP|ResourceFromPri|{Package.Location}|Can't load null or empty result "
+ $"pri {source} in uwp location {Package.Location}" , new NullReferenceException ( ) ) ;
2016-11-29 09:46:29 +08:00
return string . Empty ;
}
}
else
{
2017-02-13 01:56:39 +08:00
// https://github.com/Wox-launcher/Wox/issues/964
2016-11-29 09:46:29 +08:00
// 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
2016-11-30 08:30:42 +08:00
var e = Marshal . GetExceptionForHR ( ( int ) hResult ) ;
2019-10-25 10:11:52 +08:00
ProgramLogger . LogException ( $"|UWP|ResourceFromPri|{Package.Location}|Load pri failed {source} with HResult {hResult} and location {Package.Location}" , e ) ;
2016-11-29 09:46:29 +08:00
return string . Empty ;
}
}
else
{
return resourceReference ;
}
}
internal string LogoUriFromManifest ( IAppxManifestApplication app )
{
var logoKeyFromVersion = new Dictionary < PackageVersion , string >
2018-07-15 11:32:21 +08:00
{
{ PackageVersion . Windows10 , "Square44x44Logo" } ,
{ PackageVersion . Windows81 , "Square30x30Logo" } ,
{ PackageVersion . Windows8 , "SmallLogo" } ,
} ;
2016-11-29 09:46:29 +08:00
if ( logoKeyFromVersion . ContainsKey ( Package . Version ) )
{
var key = logoKeyFromVersion [ Package . Version ] ;
var logoUri = app . GetStringValue ( key ) ;
return logoUri ;
}
else
{
return string . Empty ;
}
}
internal 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 ( "\\" ) )
{
2016-11-29 09:55:11 +08:00
path = Path . Combine ( Package . Location , uri ) ;
2016-11-29 09:46:29 +08:00
}
else
{
// for C:\Windows\MiracastView etc
2016-11-29 09:55:11 +08:00
path = Path . Combine ( Package . Location , "Assets" , uri ) ;
2016-11-29 09:46:29 +08:00
}
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 } ;
2018-07-15 11:32:21 +08:00
var scaleFactors = new Dictionary < PackageVersion , List < int > >
2016-11-29 09:46:29 +08:00
{
2018-07-15 11:32:21 +08:00
// 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 ) )
2016-11-29 09:46:29 +08:00
{
2018-07-15 11:32:21 +08:00
foreach ( var factor in scaleFactors [ Package . Version ] )
{
paths . Add ( $"{prefix}.scale-{factor}{extension}" ) ;
}
2016-11-29 09:46:29 +08:00
}
var selected = paths . FirstOrDefault ( File . Exists ) ;
if ( ! string . IsNullOrEmpty ( selected ) )
{
return selected ;
}
else
{
2019-10-25 10:11:52 +08:00
ProgramLogger . LogException ( $"|UWP|LogoPathFromUri|{Package.Location}" +
$"|{UserModelId} can't find logo uri for {uri} in package location: {Package.Location}" , new FileNotFoundException ( ) ) ;
2016-11-29 09:46:29 +08:00
return string . Empty ;
}
}
else
{
2019-10-25 10:11:52 +08:00
ProgramLogger . LogException ( $"|UWP|LogoPathFromUri|{Package.Location}" +
$"|Unable to find extension from {uri} for {UserModelId} " +
$"in package location {Package.Location}" , new FileNotFoundException ( ) ) ;
2016-11-29 09:46:29 +08:00
return string . Empty ;
}
}
2016-08-18 08:16:40 +08:00
2016-08-18 08:56:26 +08:00
public ImageSource Logo ( )
2016-08-18 08:16:40 +08:00
{
2016-11-29 09:18:38 +08:00
var logo = ImageFromPath ( LogoPath ) ;
var plated = PlatedImage ( logo ) ;
2016-08-18 08:56:26 +08:00
2016-08-19 10:00:52 +08:00
// todo magic! temp fix for cross thread object
plated . Freeze ( ) ;
return plated ;
}
2016-09-06 03:33:31 +08:00
2016-11-29 09:18:38 +08:00
private BitmapImage ImageFromPath ( string path )
2016-08-19 10:00:52 +08:00
{
2016-11-29 09:18:38 +08:00
if ( File . Exists ( path ) )
2016-08-20 06:15:40 +08:00
{
2016-11-29 09:18:38 +08:00
var image = new BitmapImage ( new Uri ( path ) ) ;
return image ;
2016-09-06 03:33:31 +08:00
}
else
{
2019-10-25 10:11:52 +08:00
ProgramLogger . LogException ( $"|UWP|ImageFromPath|{path}" +
$"|Unable to get logo for {UserModelId} from {path} and" +
$" located in {Package.Location}" , new FileNotFoundException ( ) ) ;
2016-11-29 09:18:38 +08:00
return new BitmapImage ( new Uri ( Constant . ErrorIcon ) ) ;
2016-09-06 03:33:31 +08:00
}
}
2016-11-29 09:18:38 +08:00
private ImageSource PlatedImage ( BitmapImage image )
2016-09-06 03:33:31 +08:00
{
2016-11-29 09:18:38 +08:00
if ( ! string . IsNullOrEmpty ( BackgroundColor ) & & BackgroundColor ! = "transparent" )
2016-09-06 03:33:31 +08:00
{
2016-11-29 09:18:38 +08:00
var width = image . Width ;
var height = image . Height ;
var x = 0 ;
var y = 0 ;
var group = new DrawingGroup ( ) ;
2016-09-06 03:33:31 +08:00
2016-11-29 09:18:38 +08:00
var converted = ColorConverter . ConvertFromString ( BackgroundColor ) ;
if ( converted ! = null )
2016-09-06 00:45:29 +08:00
{
2016-11-29 09:46:29 +08:00
var color = ( Color ) converted ;
2016-11-29 09:18:38 +08:00
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 ;
2016-09-06 00:45:29 +08:00
}
else
{
2019-10-25 10:11:52 +08:00
ProgramLogger . LogException ( $"|UWP|PlatedImage|{Package.Location}" +
$"|Unable to convert background string {BackgroundColor} " +
$"to color for {Package.Location}" , new InvalidOperationException ( ) ) ;
2016-09-06 00:45:29 +08:00
return new BitmapImage ( new Uri ( Constant . ErrorIcon ) ) ;
}
2016-08-20 06:15:40 +08:00
}
else
{
2016-11-29 09:18:38 +08:00
// todo use windows theme as background
2016-09-06 00:45:29 +08:00
return image ;
2016-08-20 06:15:40 +08:00
}
2016-08-19 10:00:52 +08:00
}
2016-08-18 08:16:40 +08:00
public override string ToString ( )
{
return $"{DisplayName}: {Description}" ;
}
}
2016-11-29 09:18:38 +08:00
public enum PackageVersion
{
Windows10 ,
Windows81 ,
Windows8 ,
Unknown
}
2016-08-18 08:16:40 +08:00
[Flags]
private enum Stgm : uint
{
Read = 0x0 ,
2016-11-29 09:18:38 +08:00
ShareExclusive = 0x10 ,
2016-08-18 08:16:40 +08:00
}
private enum Hresult : uint
{
2016-11-29 09:18:38 +08:00
Ok = 0x0000 ,
2016-08-18 08:16:40 +08:00
}
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
2016-11-29 09:18:38 +08:00
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 ) ;
2016-08-18 08:16:40 +08:00
}
2016-11-29 09:18:38 +08:00
}