C# WPF开发中如何正确获取系统UWP应用包的Logo图标
UWP应用图标加载失败、程序闪退问题解决方案
问题根因
Package.Logo属性返回的是UWP生态专属的ms-resource/ms-appx协议URI,不属于WPF默认支持的本地文件/HTTP URI格式,直接传入BitmapImage构造函数无法解析,会触发路径不存在异常。DisplayInfo.GetLogo()方法返回的是WinRT原生的IRandomAccessStream类型,WPF的BitmapImage仅能识别托管Stream类型,未做流转换直接使用会触发类型不兼容异常;传入new Size(1,1)只会返回1x1像素的占位资源,本身也无法作为正常图标使用。- 程序闪退有两个核心诱因:一是桌面程序默认未声明调用
PackageManager所需的packageQuery能力,调用相关API时会触发权限异常;二是UWP包按用户上下文隔离注册,以管理员身份运行时程序处于高完整性的系统上下文,无法读取当前标准用户下安装的UWP包数据,枚举过程中抛出的未捕获异常会直接导致程序崩溃。
实现步骤
1. 项目前置配置
- 右键项目选择「编辑项目文件」,配置目标Windows SDK版本,确保目标平台版本不低于Windows 10 1809(10.0.17763.0),添加如下配置:
<PropertyGroup> <TargetPlatformVersion>10.0.19041.0</TargetPlatformVersion> <SupportedOSPlatformVersion>10.0.17763.0</SupportedOSPlatformVersion> </PropertyGroup>
- 给项目添加应用程序清单文件(app.manifest),在清单中添加包查询所需的能力声明:
<application xmlns="urn:schemas-microsoft-com:asm.v3"> <windowsSettings> <packageQuery xmlns="http://schemas.microsoft.com/SMI/2020/WindowsSettings">true</packageQuery> </windowsSettings> </application>
- 禁止配置程序默认以管理员身份启动,必须在当前登录的标准用户上下文下运行,否则无法正常枚举用户安装的UWP应用。
2. 图标加载核心代码
引入以下必要命名空间:
using System.Diagnostics; using System.Windows.Media.Imaging; using Windows.ApplicationModel; using Windows.Management.Deployment; using Windows.Storage.Streams; using System.Security.Principal; using System.Runtime.InteropServices.WindowsRuntime;
枚举包并加载图标的实现:
string currentUserSid = WindowsIdentity.GetCurrent().User.Value; PackageManager pm = new PackageManager(); List<Package> packages = new List<Package>(pm.FindPackagesForUserWithPackageTypes(currentUserSid, PackageTypes.Main)); // 过滤无有效入口的包 packages.RemoveAll(p => p.GetAppListEntries().Count == 0); foreach (Package pkg in packages) { foreach (AppListEntry entry in pkg.GetAppListEntries()) { try { // 按实际UI需求传入图标尺寸,这里以开始菜单常用的48x48为例 using IRandomAccessStream rawStream = entry.DisplayInfo.GetLogo(new Windows.Foundation.Size(48, 48)); // 转换为WPF支持的托管流 using Stream managedStream = rawStream.AsStreamForRead(); BitmapImage icon = new BitmapImage(); icon.BeginInit(); icon.CacheOption = BitmapCacheOption.OnLoad; icon.StreamSource = managedStream; icon.EndInit(); icon.Freeze(); // 冻结对象避免跨线程访问异常,同时提升渲染性能 // 此处将icon绑定到对应UI元素即可 } catch (Exception ex) { // 部分系统内置预留包无公开有效图标,直接跳过 Debug.WriteLine($"加载应用{entry.DisplayInfo.DisplayName}图标失败: {ex.Message}"); continue; } } }
3. 注意事项
- 流转换方法
AsStreamForRead()依赖System.Runtime.WindowsRuntime程序集,VS2022中配置完目标Windows平台版本后会自动引入该引用,无需手动添加。 - 不要传入过小的尺寸参数(如1x1),系统会返回最低分辨率的占位图,显示效果完全不可用,建议根据UI实际渲染尺寸传入对应值,系统会自动适配当前系统缩放比例返回最清晰的图标资源。
- 所有文件流、WinRT流都要加
using释放,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Yudong Liu
相关产品推荐
相关产品推荐

