mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-06-07 09:28:03 +08:00
[PT Run] Improve the UWP Program Indexing speed (#11683)
* Improve UWP Indexing speed * Optimize Linq usage Added static readonly vars * Optimzie GetAppsFromManifest * LogoUriFromManifest uses logoUri which is also an instance variable * Add IsPackageDotInstallationPathAvailable * Dispose FileStream * Fix InstalledPath after testing in build 1903 * Fix typo
This commit is contained in:
parent
b2cff5cbd3
commit
5b804a1ff6
@ -11,12 +11,12 @@ namespace Microsoft.Plugin.Program.Programs
|
|||||||
{
|
{
|
||||||
public static class AppxPackageHelper
|
public static class AppxPackageHelper
|
||||||
{
|
{
|
||||||
|
private static readonly IAppxFactory AppxFactory = (IAppxFactory)new AppxFactory();
|
||||||
|
|
||||||
// This function returns a list of attributes of applications
|
// This function returns a list of attributes of applications
|
||||||
public static List<IAppxManifestApplication> GetAppsFromManifest(IStream stream)
|
public static IEnumerable<IAppxManifestApplication> GetAppsFromManifest(IStream stream)
|
||||||
{
|
{
|
||||||
List<IAppxManifestApplication> apps = new List<IAppxManifestApplication>();
|
var reader = AppxFactory.CreateManifestReader(stream);
|
||||||
var appxFactory = new AppxFactory();
|
|
||||||
var reader = ((IAppxFactory)appxFactory).CreateManifestReader(stream);
|
|
||||||
var manifestApps = reader.GetApplications();
|
var manifestApps = reader.GetApplications();
|
||||||
|
|
||||||
while (manifestApps.GetHasCurrent())
|
while (manifestApps.GetHasCurrent())
|
||||||
@ -26,13 +26,11 @@ namespace Microsoft.Plugin.Program.Programs
|
|||||||
_ = CheckHRAndReturnOrThrow(hr, appListEntry);
|
_ = CheckHRAndReturnOrThrow(hr, appListEntry);
|
||||||
if (appListEntry != "none")
|
if (appListEntry != "none")
|
||||||
{
|
{
|
||||||
apps.Add(manifestApp);
|
yield return manifestApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
manifestApps.MoveNext();
|
manifestApps.MoveNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
return apps;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T CheckHRAndReturnOrThrow<T>(Hresult hr, T result)
|
public static T CheckHRAndReturnOrThrow<T>(Hresult hr, T result)
|
||||||
|
@ -6,6 +6,7 @@ using System;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.Plugin.Program.Logger;
|
using Microsoft.Plugin.Program.Logger;
|
||||||
|
using Windows.Foundation.Metadata;
|
||||||
using Package = Windows.ApplicationModel.Package;
|
using Package = Windows.ApplicationModel.Package;
|
||||||
|
|
||||||
namespace Microsoft.Plugin.Program.Programs
|
namespace Microsoft.Plugin.Program.Programs
|
||||||
@ -38,6 +39,9 @@ namespace Microsoft.Plugin.Program.Programs
|
|||||||
InstalledLocation = installedLocation;
|
InstalledLocation = installedLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly Lazy<bool> IsPackageDotInstallationPathAvailable = new Lazy<bool>(() =>
|
||||||
|
ApiInformation.IsPropertyPresent(typeof(Package).FullName, nameof(Package.InstalledPath)));
|
||||||
|
|
||||||
public static PackageWrapper GetWrapperFromPackage(Package package)
|
public static PackageWrapper GetWrapperFromPackage(Package package)
|
||||||
{
|
{
|
||||||
if (package == null)
|
if (package == null)
|
||||||
@ -48,7 +52,7 @@ namespace Microsoft.Plugin.Program.Programs
|
|||||||
string path;
|
string path;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
path = package.InstalledLocation.Path;
|
path = IsPackageDotInstallationPathAvailable.Value ? GetInstalledPath(package) : package.InstalledLocation.Path;
|
||||||
}
|
}
|
||||||
catch (Exception e) when (e is ArgumentException || e is FileNotFoundException || e is DirectoryNotFoundException)
|
catch (Exception e) when (e is ArgumentException || e is FileNotFoundException || e is DirectoryNotFoundException)
|
||||||
{
|
{
|
||||||
@ -70,5 +74,9 @@ namespace Microsoft.Plugin.Program.Programs
|
|||||||
package.IsDevelopmentMode,
|
package.IsDevelopmentMode,
|
||||||
path);
|
path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is a separate method so the reference to .InstalledPath won't be loaded in API versions which do not support this API (e.g. older then Build 19041)
|
||||||
|
private static string GetInstalledPath(Package package)
|
||||||
|
=> package.InstalledPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using Windows.Management.Deployment;
|
using Windows.Management.Deployment;
|
||||||
using Wox.Plugin.Logger;
|
using Wox.Plugin.Logger;
|
||||||
@ -20,30 +21,28 @@ namespace Microsoft.Plugin.Program.Programs
|
|||||||
_packageManager = new PackageManager();
|
_packageManager = new PackageManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to catch all exception to prevent error in a program from affecting loading of program plugin.")]
|
|
||||||
public IEnumerable<IPackage> FindPackagesForCurrentUser()
|
public IEnumerable<IPackage> FindPackagesForCurrentUser()
|
||||||
{
|
{
|
||||||
List<PackageWrapper> packages = new List<PackageWrapper>();
|
|
||||||
var user = WindowsIdentity.GetCurrent().User;
|
var user = WindowsIdentity.GetCurrent().User;
|
||||||
|
|
||||||
if (user != null)
|
return user != null
|
||||||
|
? _packageManager.FindPackagesForUser(user.Value).Select(TryGetWrapperFromPackage).Where(package => package != null)
|
||||||
|
: Enumerable.Empty<IPackage>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to catch all exception to prevent error in a program from affecting loading of program plugin.")]
|
||||||
|
private static PackageWrapper TryGetWrapperFromPackage(Package package)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
var id = user.Value;
|
return PackageWrapper.GetWrapperFromPackage(package);
|
||||||
var m = _packageManager.FindPackagesForUser(id);
|
}
|
||||||
foreach (Package p in m)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
try
|
Log.Error(e.Message, typeof(PackageManagerWrapper));
|
||||||
{
|
|
||||||
packages.Add(PackageWrapper.GetWrapperFromPackage(p));
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Log.Error(e.Message, GetType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return packages;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) Microsoft Corporation
|
// Copyright (c) Microsoft Corporation
|
||||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
@ -21,6 +21,13 @@ namespace Microsoft.Plugin.Program.Programs
|
|||||||
{
|
{
|
||||||
private static readonly IPath Path = new FileSystem().Path;
|
private static readonly IPath Path = new FileSystem().Path;
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, PackageVersion> _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 },
|
||||||
|
};
|
||||||
|
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
public string FullName { get; }
|
public string FullName { get; }
|
||||||
@ -61,16 +68,7 @@ namespace Microsoft.Plugin.Program.Programs
|
|||||||
|
|
||||||
if (hResult == Hresult.Ok)
|
if (hResult == Hresult.Ok)
|
||||||
{
|
{
|
||||||
var apps = new List<UWPApplication>();
|
Apps = AppxPackageHelper.GetAppsFromManifest(stream).Select(appInManifest => new UWPApplication(appInManifest, this)).Where(a =>
|
||||||
|
|
||||||
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 =
|
var valid =
|
||||||
!string.IsNullOrEmpty(a.UserModelId) &&
|
!string.IsNullOrEmpty(a.UserModelId) &&
|
||||||
@ -78,7 +76,7 @@ namespace Microsoft.Plugin.Program.Programs
|
|||||||
a.AppListEntry != "none";
|
a.AppListEntry != "none";
|
||||||
|
|
||||||
return valid;
|
return valid;
|
||||||
}).ToArray();
|
}).ToList();
|
||||||
|
|
||||||
if (Marshal.ReleaseComObject(stream) > 0)
|
if (Marshal.ReleaseComObject(stream) > 0)
|
||||||
{
|
{
|
||||||
@ -90,7 +88,7 @@ namespace Microsoft.Plugin.Program.Programs
|
|||||||
var e = Marshal.GetExceptionForHR((int)hResult);
|
var e = Marshal.GetExceptionForHR((int)hResult);
|
||||||
ProgramLogger.Exception("Error caused while trying to get the details of the UWP program", e, GetType(), path);
|
ProgramLogger.Exception("Error caused while trying to get the details of the UWP program", e, GetType(), path);
|
||||||
|
|
||||||
Apps = new List<UWPApplication>().ToArray();
|
Apps = Array.Empty<UWPApplication>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,20 +116,10 @@ namespace Microsoft.Plugin.Program.Programs
|
|||||||
|
|
||||||
private void InitPackageVersion(string[] namespaces)
|
private void InitPackageVersion(string[] namespaces)
|
||||||
{
|
{
|
||||||
var versionFromNamespace = new Dictionary<string, PackageVersion>
|
foreach (var n in _versionFromNamespace.Keys.Where(namespaces.Contains))
|
||||||
{
|
{
|
||||||
{ "http://schemas.microsoft.com/appx/manifest/foundation/windows10", PackageVersion.Windows10 },
|
Version = _versionFromNamespace[n];
|
||||||
{ "http://schemas.microsoft.com/appx/2013/manifest", PackageVersion.Windows81 },
|
return;
|
||||||
{ "http://schemas.microsoft.com/appx/2010/manifest", PackageVersion.Windows8 },
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (var n in versionFromNamespace.Keys)
|
|
||||||
{
|
|
||||||
if (namespaces.Contains(n))
|
|
||||||
{
|
|
||||||
Version = versionFromNamespace[n];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgramLogger.Exception($"|Trying to get the package version of the UWP program, but a unknown UWP appmanifest version {FullName} from location {Location} is returned.", new FormatException(), GetType(), Location);
|
ProgramLogger.Exception($"|Trying to get the package version of the UWP program, but a unknown UWP appmanifest version {FullName} from location {Location} is returned.", new FormatException(), GetType(), Location);
|
||||||
@ -162,11 +150,10 @@ namespace Microsoft.Plugin.Program.Programs
|
|||||||
}
|
}
|
||||||
|
|
||||||
return u.Apps;
|
return u.Apps;
|
||||||
}).ToArray();
|
});
|
||||||
|
|
||||||
var updatedListWithoutDisabledApps = applications
|
var updatedListWithoutDisabledApps = applications
|
||||||
.Where(t1 => !Main.Settings.DisabledProgramSources
|
.Where(t1 => Main.Settings.DisabledProgramSources.All(x => x.UniqueIdentifier != t1.UniqueIdentifier))
|
||||||
.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
|
|
||||||
.Select(x => x);
|
.Select(x => x);
|
||||||
|
|
||||||
return updatedListWithoutDisabledApps.ToArray();
|
return updatedListWithoutDisabledApps.ToArray();
|
||||||
@ -180,26 +167,20 @@ namespace Microsoft.Plugin.Program.Programs
|
|||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Intentionally keeping the process alive.")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Intentionally keeping the process alive.")]
|
||||||
private static IEnumerable<IPackage> CurrentUserPackages()
|
private static IEnumerable<IPackage> CurrentUserPackages()
|
||||||
{
|
{
|
||||||
var ps = PackageManagerWrapper.FindPackagesForCurrentUser();
|
return PackageManagerWrapper.FindPackagesForCurrentUser().Where(p =>
|
||||||
ps = ps.Where(p =>
|
|
||||||
{
|
{
|
||||||
bool valid;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var f = p.IsFramework;
|
var f = p.IsFramework;
|
||||||
var path = p.InstalledLocation;
|
var path = p.InstalledLocation;
|
||||||
valid = !f && !string.IsNullOrEmpty(path);
|
return !f && !string.IsNullOrEmpty(path);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ProgramLogger.Exception("An unexpected error occurred and unable to verify if package is valid", e, MethodBase.GetCurrentMethod().DeclaringType, "id");
|
ProgramLogger.Exception("An unexpected error occurred and unable to verify if package is valid", e, MethodBase.GetCurrentMethod().DeclaringType, "id");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return valid;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return ps;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
@ -349,20 +349,20 @@ namespace Microsoft.Plugin.Program.Programs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly Dictionary<PackageVersion, string> _logoKeyFromVersion = new Dictionary<PackageVersion, string>
|
||||||
|
{
|
||||||
|
{ PackageVersion.Windows10, "Square44x44Logo" },
|
||||||
|
{ PackageVersion.Windows81, "Square30x30Logo" },
|
||||||
|
{ PackageVersion.Windows8, "SmallLogo" },
|
||||||
|
};
|
||||||
|
|
||||||
internal string LogoUriFromManifest(IAppxManifestApplication app)
|
internal string LogoUriFromManifest(IAppxManifestApplication app)
|
||||||
{
|
{
|
||||||
var logoKeyFromVersion = new Dictionary<PackageVersion, string>
|
if (_logoKeyFromVersion.TryGetValue(Package.Version, out var key))
|
||||||
{
|
|
||||||
{ 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 logoUriFromApp);
|
||||||
var hr = app.GetStringValue(key, out var logoUri);
|
_ = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, logoUriFromApp);
|
||||||
_ = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, logoUri);
|
return logoUriFromApp;
|
||||||
return logoUri;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -372,9 +372,17 @@ namespace Microsoft.Plugin.Program.Programs
|
|||||||
|
|
||||||
public void UpdatePath(Theme theme)
|
public void UpdatePath(Theme theme)
|
||||||
{
|
{
|
||||||
LogoPathFromUri(this.logoUri, theme);
|
LogoPathFromUri(logoUri, theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// scale factors on win10: https://docs.microsoft.com/en-us/windows/uwp/controls-and-patterns/tiles-and-notifications-app-assets#asset-size-tables,
|
||||||
|
private static readonly Dictionary<PackageVersion, List<int>> _scaleFactors = new Dictionary<PackageVersion, List<int>>
|
||||||
|
{
|
||||||
|
{ 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 } },
|
||||||
|
};
|
||||||
|
|
||||||
private bool SetScaleIcons(string path, string colorscheme, bool highContrast = false)
|
private bool SetScaleIcons(string path, string colorscheme, bool highContrast = false)
|
||||||
{
|
{
|
||||||
var extension = Path.GetExtension(path);
|
var extension = Path.GetExtension(path);
|
||||||
@ -383,22 +391,15 @@ namespace Microsoft.Plugin.Program.Programs
|
|||||||
var end = path.Length - extension.Length;
|
var end = path.Length - extension.Length;
|
||||||
var prefix = path.Substring(0, end);
|
var prefix = path.Substring(0, end);
|
||||||
var paths = new List<string> { };
|
var paths = new List<string> { };
|
||||||
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 (!highContrast)
|
if (!highContrast)
|
||||||
{
|
{
|
||||||
paths.Add(path);
|
paths.Add(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scaleFactors.ContainsKey(Package.Version))
|
if (_scaleFactors.ContainsKey(Package.Version))
|
||||||
{
|
{
|
||||||
foreach (var factor in scaleFactors[Package.Version])
|
foreach (var factor in _scaleFactors[Package.Version])
|
||||||
{
|
{
|
||||||
if (highContrast)
|
if (highContrast)
|
||||||
{
|
{
|
||||||
@ -440,7 +441,7 @@ namespace Microsoft.Plugin.Program.Programs
|
|||||||
var end = path.Length - extension.Length;
|
var end = path.Length - extension.Length;
|
||||||
var prefix = path.Substring(0, end);
|
var prefix = path.Substring(0, end);
|
||||||
var paths = new List<string> { };
|
var paths = new List<string> { };
|
||||||
int appIconSize = 36;
|
const int appIconSize = 36;
|
||||||
var targetSizes = new List<int> { 16, 24, 30, 36, 44, 60, 72, 96, 128, 180, 256 }.AsParallel();
|
var targetSizes = new List<int> { 16, 24, 30, 36, 44, 60, 72, 96, 128, 180, 256 }.AsParallel();
|
||||||
var pathFactorPairs = new Dictionary<string, int>();
|
var pathFactorPairs = new Dictionary<string, int>();
|
||||||
|
|
||||||
@ -564,21 +565,22 @@ namespace Microsoft.Plugin.Program.Programs
|
|||||||
path = Path.Combine(Package.Location, "Assets", uri);
|
path = Path.Combine(Package.Location, "Assets", uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theme == Theme.HighContrastBlack || theme == Theme.HighContrastOne || theme == Theme.HighContrastTwo)
|
switch (theme)
|
||||||
{
|
{
|
||||||
isLogoUriSet = SetHighContrastIcon(path, ContrastBlack);
|
case Theme.HighContrastBlack:
|
||||||
}
|
case Theme.HighContrastOne:
|
||||||
else if (theme == Theme.HighContrastWhite)
|
case Theme.HighContrastTwo:
|
||||||
{
|
isLogoUriSet = SetHighContrastIcon(path, ContrastBlack);
|
||||||
isLogoUriSet = SetHighContrastIcon(path, ContrastWhite);
|
break;
|
||||||
}
|
case Theme.HighContrastWhite:
|
||||||
else if (theme == Theme.Light)
|
isLogoUriSet = SetHighContrastIcon(path, ContrastWhite);
|
||||||
{
|
break;
|
||||||
isLogoUriSet = SetColoredIcon(path, ContrastWhite);
|
case Theme.Light:
|
||||||
}
|
isLogoUriSet = SetColoredIcon(path, ContrastWhite);
|
||||||
else
|
break;
|
||||||
{
|
default:
|
||||||
isLogoUriSet = SetColoredIcon(path, ContrastBlack);
|
isLogoUriSet = SetColoredIcon(path, ContrastBlack);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isLogoUriSet)
|
if (!isLogoUriSet)
|
||||||
@ -677,17 +679,18 @@ namespace Microsoft.Plugin.Program.Programs
|
|||||||
{
|
{
|
||||||
if (File.Exists(path))
|
if (File.Exists(path))
|
||||||
{
|
{
|
||||||
MemoryStream memoryStream = new MemoryStream();
|
var memoryStream = new MemoryStream();
|
||||||
|
using (var fileStream = File.OpenRead(path))
|
||||||
|
{
|
||||||
|
fileStream.CopyTo(memoryStream);
|
||||||
|
memoryStream.Position = 0;
|
||||||
|
|
||||||
byte[] fileBytes = File.ReadAllBytes(path);
|
var image = new BitmapImage();
|
||||||
memoryStream.Write(fileBytes, 0, fileBytes.Length);
|
image.BeginInit();
|
||||||
memoryStream.Position = 0;
|
image.StreamSource = memoryStream;
|
||||||
|
image.EndInit();
|
||||||
var image = new BitmapImage();
|
return image;
|
||||||
image.BeginInit();
|
}
|
||||||
image.StreamSource = memoryStream;
|
|
||||||
image.EndInit();
|
|
||||||
return image;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user