// 下列 ifdef 块是创建使从 DLL 导出更简单的
// 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 PKGREAD_EXPORTS
// 符号编译的。在使用此 DLL 的
// 任何其他项目上不应定义此符号。这样，源文件中包含此文件的任何其他项目都会将
// PKGREAD_API 函数视为是从 DLL 导入的，而此 DLL 则将用此宏定义的
// 符号视为是被导出的。
#ifndef _APPX_PACKAGE_READER_H_
#define _APPX_PACKAGE_READER_H_
#ifdef PKGREAD_EXPORTS
#define PKGREAD_API __declspec(dllexport)
#else
#define PKGREAD_API __declspec(dllimport)
#endif

#ifdef __cplusplus
#define _DEFAULT_INIT_VALUE_(_init_value_) = _init_value_
#ifndef PKGREAD_EXPORTS
#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_) = _init_value_
#else 
#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_)
#endif
#else
#define _DEFAULT_INIT_VALUE_(_init_value_)
#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_)
#endif

#if defined (__cplusplus) && defined (PKGREAD_EXPORTS)
#include <iostream>
#endif

#ifndef _TYPE_STRUCT_VERSION_
#define _TYPE_STRUCT_VERSION_
typedef struct _VERSION
{
	UINT16 major _DEFAULT_INIT_VALUE_ (0),
		minor _DEFAULT_INIT_VALUE_ (0),
		build _DEFAULT_INIT_VALUE_ (0),
		revision _DEFAULT_INIT_VALUE_ (0);
#if defined (__cplusplus) && defined (PKGREAD_EXPORTS)
	_VERSION (UINT16 major = 0, UINT16 minor = 0, UINT16 build = 0, UINT16 revision = 0):
		major (major), minor (minor), build (build), revision (revision) {}
	friend std::ostream &operator << (std::ostream &o, const _VERSION &v)
	{
		return o << v.major << "." << v.minor << "." << v.build << "." << v.revision;
	}
	friend std::wostream &operator << (std::wostream &o, const _VERSION &v)
	{
		return o << v.major << L"." << v.minor << L"." << v.build << L"." << v.revision;
	}
#endif
} VERSION;
#endif

#ifdef __cplusplus
extern "C"
{
#endif

#ifndef _TYPE_STRUCT_LIST_PVOID_
#define _TYPE_STRUCT_LIST_PVOID_
	typedef struct _LIST_PVOID
	{
		DWORD dwSize _DEFAULT_INIT_VALUE_ (0);
		LPVOID alpVoid [1] _DEFAULT_INIT_VALUE_ ({NULL});
	} LIST_PVOID, *HLIST_PVOID;
#endif

#ifndef _TYPE_STRUCT_PAIR_PVOID_
#define _TYPE_STRUCT_PAIR_PVOID_
	typedef struct _PAIR_PVOID_
	{
		LPVOID lpKey _DEFAULT_INIT_VALUE_ (NULL);
		LPVOID lpValue _DEFAULT_INIT_VALUE_ (NULL);
	} PAIR_PVOID, *HPAIR_PVOID;
#endif

#define TEMPLATE_STRUCT(_typename_) typedef struct _typename_##__ _typename_
	TEMPLATE_STRUCT (PKGREADER);
	typedef PKGREADER *HPKGREAD;
	TEMPLATE_STRUCT (APPENUMERATOR);
	typedef APPENUMERATOR *HAPPENUMERATOR;

#define PKGTYPE_UNKNOWN   0
#define PKGTYPE_APPX      1
#define PKGTYPE_BUNDLE    2
#define PKGROLE_UNKNOWN       0
#define PKGROLE_APPLICATION   1
#define PKGROLE_FRAMEWORK     2
#define PKGROLE_RESOURCE      3
	// 创建包读取器
	PKGREAD_API HPKGREAD CreatePackageReader ();
	// 通过包读取器打开包
	PKGREAD_API BOOL LoadPackageFromFile (_In_ HPKGREAD hReader, _In_ LPCWSTR lpFilePath);
	// 销毁包读取器（必须）
	PKGREAD_API void DestroyPackageReader (_In_ HPKGREAD hReader);
	// 获取包的类型：Appx 包还是 AppxBundle 包。返回 PKGTYPE_* 宏 
	PKGREAD_API WORD GetPackageType (_In_ HPKGREAD hReader);
	// 返回包是否有效。无效的包会返回假。
	PKGREAD_API BOOL IsPackageValid (_In_ HPKGREAD hReader);
	// 获取包的类型：是应用包、框架包还是资源包。
	// 对于 AppxBundle 包永远返回是资源包（因为框架包无法打包成 AppxBundle，资源包必须与应用包一同打包进 AppxBundle）。
	// 返回 PKGROLE_* 宏。
	PKGREAD_API WORD GetPackageRole (_In_ HPKGREAD hReader);

	// Identity
	// 对于 AppxBundle 包来说，AppxBundle 包与储存的 Appx 的包的身份信息并不一致（不一致在版本号和处理器架构上）
#define PKG_IDENTITY_BUNDLE_GETAPPXINFO ((PKGTYPE_BUNDLE && 0xFFFF) << 16)
#define PKG_IDENTITY_NAME 0
#define PKG_IDENTITY_PUBLISHER 1
#define PKG_IDENTITY_PACKAGEFAMILYNAME 2
#define PKG_IDENTITY_PACKAGEFULLNAME 3
#define PKG_IDENTITY_RESOURCEID 4
#define PKG_ARCHITECTURE_UNKNOWN 0x0
#define PKG_ARCHITECTURE_X86 0x1
#define PKG_ARCHITECTURE_X64 0x2
#define PKG_ARCHITECTURE_ARM 0x4
#define PKG_ARCHITECTURE_ARM64 0x8
#define PKG_ARCHITECTURE_NEUTRAL 0xF
	// 获取身份信息能获取文本值的项。支持 PKG_IDENTITY_* 前缀的宏 NAME, PUBLISHER, PACKAGEFAMILYNAME, PACKAGEFULLNAME, RESOURCEID。
	// 当与 PKG_IDENTITY_BUNDLE_GETAPPXINFO 通过位或结合时，则获取 AppxBundle 中某一个应用包。
	PKGREAD_API LPWSTR GetPackageIdentityStringValue (_In_ HPKGREAD hReader, _In_ DWORD dwName);
#define GetPackageIdentityName(_In_hReader_) GetPackageIdentityStringValue (_In_hReader_, PKG_IDENTITY_NAME)
#define GetPackageIdentityPublisher(_In_hReader_) GetPackageIdentityStringValue (_In_hReader_, PKG_IDENTITY_PUBLISHER)
#define GetPackageIdentityPackageFamilyName(_In_hReader_) GetPackageIdentityStringValue (_In_hReader_, PKG_IDENTITY_PACKAGEFAMILYNAME)
#define GetPackageIdentityPackageFullName(_In_hReader_) GetPackageIdentityStringValue (_In_hReader_, PKG_IDENTITY_PACKAGEFULLNAME)
#define GetPackageIdentityResourceId(_In_hReader_) GetPackageIdentityStringValue (_In_hReader_, PKG_IDENTITY_RESOURCEID)
	// 获取身份信息。当 bGetSubPkgVer 为真，且打开的包为 AppxBundle 包，返回 AppxBundle 包中的某个应用包的版本号。
	PKGREAD_API BOOL GetPackageIdentityVersion (_In_ HPKGREAD hReader, _Out_ VERSION *pVersion, _In_ BOOL bGetSubPkgVer _DEFAULT_INIT_VALUE_FORFUNC_ (0));
	// 对于 AppxBundle 包，当传入的值有 PKG_IDENTITY_BUNDLE_GETAPPXINFO，则返回一个按位值，如 0b0011，则意味着支持 x86 和 x64
	PKGREAD_API BOOL GetPackageIdentityArchitecture (_In_ HPKGREAD hReader, _Out_ DWORD *pdwArchi);

	// Properties
	// 获取字符串值
#define PKG_PROPERTIES_DISPLAYNAME L"DisplayName"
#define PKG_PROPERTIES_DESCRIPTION L"Description"
#define PKG_PROPERTIES_LOGO L"Logo"
#define PKG_PROPERTIES_PUBLISHER L"PublisherDisplayName"
// 获取逻辑型值
#define PKG_PROPERTIES_FRAMEWORD L"Framework"
#define PKG_PROPERTIES_IS_RESOURCE L"ResourcePackage"
	// 传入参数参考：https://learn.microsoft.com/en-us/windows/win32/api/appxpackaging/nf-appxpackaging-iappxmanifestproperties-getstringvalue
	// 可以使用宏 PKG_PROPERTIES_* 前缀的 DISPLAYNAME, DESCRIPTION, LOGO, PUBLISHER
	PKGREAD_API LPWSTR GetPackagePropertiesStringValue (_In_ HPKGREAD hReader, _In_ LPCWSTR lpName);
#define GetPackagePropertiesDisplayName(_In_hReader_) GetPackagePropertiesStringValue (_In_hReader_, PKG_PROPERTIES_DISPLAYNAME)
#define GetPackagePropertiesDescription(_In_hReader_) GetPackagePropertiesStringValue (_In_hReader_, PKG_PROPERTIES_DESCRIPTION)
#define GetPackagePropertiesLogo(_In_hReader_) GetPackagePropertiesStringValue (_In_hReader_, PKG_PROPERTIES_LOGO)
#define GetPackagePropertiesPublisher(_In_hReader_) GetPackagePropertiesStringValue (_In_hReader_, PKG_PROPERTIES_PUBLISHER)
	// 传入参数参考：https://learn.microsoft.com/zh-cn/windows/win32/api/appxpackaging/nf-appxpackaging-iappxmanifestproperties-getboolvalue
	// 可以使用宏 PKG_PROPERTIES_* 前缀的 FRAMEWORD, IS_RESOURCE (Windows 8.1 支持)
	PKGREAD_API HRESULT GetPackagePropertiesBoolValue (_In_ HPKGREAD hReader, _In_ LPCWSTR lpName, _Outptr_ BOOL *pRet);
#define GetPackagePropertiesIsFramework(_In_hReader_, _Outptr_pRetValue_) GetPackagePropertiesBoolValue (_In_hReader_, PKG_PROPERTIES_FRAMEWORD, _Outptr_pRetValue_)
#define GetPackagePropertiesIsResourcePackage(_In_hReader_, _Outptr_pRetValue_) GetPackagePropertiesBoolValue (_In_hReader_, PKG_PROPERTIES_IS_RESOURCE, _Outptr_pRetValue_)
//  Applications
	// 注意：由于读取 Application 在官方 API 中是枚举类型，只能枚举一次。
	// 所以请预先安排好需要的信息，并在枚举时进行缓存。
	// 添加和删除的请参考这些：https://learn.microsoft.com/en-us/windows/win32/api/appxpackaging/nf-appxpackaging-iappxmanifestapplication-getstringvalue
	// DLL 本身支持：Id, DisplayName, BackgroundColor, ForegroundText, ShortName, Square44x44Logo
	// 注：一定会保留项：AppUserModelID。这是必须项。
	PKGREAD_API BOOL AddPackageApplicationItemGetName (_In_ LPCWSTR lpName);
	// 移除不需要的信息项名。
	PKGREAD_API BOOL RemovePackageApplicationItemGetName (_In_ LPCWSTR lpName);
	// 获取现在有的信息项名。读取时将指针数组的成员转换为 LPCWSTR 读取，且不能修改。
	// 注意：返回的 HLIST_PVOID 要经过 DestroyApplicationItemsName 销毁。
	PKGREAD_API HLIST_PVOID GetAllApplicationItemsName ();
	// 通过 GetAllApplicationItemsName 获取的 HLIST_PVOID 由 DestroyApplicationItemsName 销毁。
	PKGREAD_API void DestroyApplicationItemsName (_In_ HLIST_PVOID hList);
	// 获取到 Application 信息枚举器。在自己缓存完信息前不要销毁，直到再也不需要后才销毁。
	// 通过 GetPackageApplications 获取的 HAPPENUMERATOR 由 DestroyApplicationsMap 销毁
	PKGREAD_API HAPPENUMERATOR GetPackageApplications (_In_ HPKGREAD hReader);
	// 从 Application 枚举器转换成 HLIST_PVOID { HLIST_PVOID {HPAIR_PVOID} } （类似于多个映射组成的数组）。
	// 读取最深层的指针成员转换为 LPCWSTR 读取。其 LPCWSTR 周期随着 HAPPENUMERATOR 的周期而决定。
	PKGREAD_API HLIST_PVOID ApplicationsToMap (_In_ HAPPENUMERATOR hEnumerator);
	// 通过 ApplicationsToMap 获取的 HLIST_PVOID 由 DestroyApplicationsMap 销毁
	PKGREAD_API void DestroyApplicationsMap (_In_ HLIST_PVOID hEnumerator);
	// 通过 GetPackageApplications 获取的 HAPPENUMERATOR 由 DestroyApplicationsMap 销毁
	PKGREAD_API void DestroyPackageApplications (_In_ HAPPENUMERATOR hEnumerator);

	// Resources
#ifndef _TYPE_STRUCT_LIST_LCID_
#define _TYPE_STRUCT_LIST_LCID_
	typedef struct _LIST_LCID
	{
		DWORD dwSize _DEFAULT_INIT_VALUE_ (0);
		LCID aLcid [1] _DEFAULT_INIT_VALUE_ ({0});
	} LIST_LCID, *HLIST_LCID;
#endif
#ifndef _TYPE_STRUCT_LIST_UINT32_
#define _TYPE_STRUCT_LIST_UINT32_
	typedef struct _LIST_UINT32
	{
		DWORD dwSize _DEFAULT_INIT_VALUE_ (0);
		LCID aUI32 [1] _DEFAULT_INIT_VALUE_ ({0});
	} LIST_UINT32, *HLIST_UINT32;
#endif
	// 返回区域代码 (Locale Code) 数组。以 LPWSTR 读取。注：一定要通过 DestroyResourcesLanguagesList 释放
	PKGREAD_API HLIST_PVOID GetResourcesLanguages (_In_ HPKGREAD hReader);
	// 返回将区域代码转换成 LCID（如 en-US 为 1033，zh-CN 为 2052） 后的数组。以 UINT32 读取。
	// 注：一定要通过 DestroyResourcesLanguagesLcidList 释放
	PKGREAD_API HLIST_LCID GetResourcesLanguagesToLcid (_In_ HPKGREAD hReader);
	// 返回 DPI 支持（如 100，125） 的数组。
	// 注：一定要通过 DestroyResourcesScalesList 宏（或 DestroyUInt32List 函数）释放
	PKGREAD_API HLIST_UINT32 GetResourcesScales (_In_ HPKGREAD hReader);
#define PKG_RESOURCES_DXFEATURE_LEVEL9		0x1
#define PKG_RESOURCES_DXFEATURE_LEVEL10		0x2
#define PKG_RESOURCES_DXFEATURE_LEVEL11		0x4
#define PKG_RESOURCES_DXFEATURE_LEVEL12		0x8
#define PKG_RESOURCES_DXFEATURE_UNSPECIFIED	0
	// 返回一个 DWORD 值。通过按位与来获取支持的 DirectX 功能支持。如果等于 0 则意味着都不支持。该值不必释放。
	PKGREAD_API DWORD GetResourcesDxFeatureLevels (_In_ HPKGREAD hReader);
	// 销毁 GetResourcesLanguages 获取的数组
	PKGREAD_API void DestroyResourcesLanguagesList (_In_ HLIST_PVOID hList);
	// 销毁 GetResourcesLanguagesToLcid 获取的数组
	PKGREAD_API void DestroyResourcesLanguagesLcidList (_In_ HLIST_LCID hList);
	PKGREAD_API void DestroyUInt32List (_In_ HLIST_UINT32 hList);
	// 销毁 GetResourcesScales 获取的数组
#define DestroyResourcesScalesList DestroyUInt32List

	// Dependencies
#ifndef _TYPE_STRUCT_DEPENDENCY_
#define _TYPE_STRUCT_DEPENDENCY_
	typedef struct _DEPENDENCY_INFO
	{
		VERSION verMin;
		LPWSTR lpName _DEFAULT_INIT_VALUE_ (NULL);
		LPWSTR lpPublisher _DEFAULT_INIT_VALUE_ (NULL);
	} DEPENDENCY_INFO;
#endif
#ifndef _TYPE_STRUCT_DEPENDENCY_LIST_
#define _TYPE_STRUCT_DEPENDENCY_LIST_
	typedef struct _LIST_DEPINFO
	{
		DWORD dwSize _DEFAULT_INIT_VALUE_ (0);
		DEPENDENCY_INFO aDepInfo [1];
	} LIST_DEPINFO, *HLIST_DEPINFO;
#endif
	// 获取依赖项信息数组，返回 HLIST_DEPINFO。必须由 DestroyDependencesInfoList 销毁
	PKGREAD_API HLIST_DEPINFO GetDependencesInfoList (_In_ HPKGREAD hReader);
	// 通过 GetDependencesInfoList 返回的指针由此销毁
	PKGREAD_API void DestroyDependencesInfoList (_In_ HLIST_DEPINFO hList);

	// Capabilities
	PKGREAD_API HLIST_PVOID GetCapabilitiesList (_In_ HPKGREAD hReader);
	PKGREAD_API HLIST_PVOID GetDeviceCapabilitiesList (_In_ HPKGREAD hReader);
	PKGREAD_API void DestroyWStringList (_In_ HLIST_PVOID hList);
#define DestroyCapabilitiesList DestroyWStringList
#define DestroyDeviceCapabilitiesList DestroyWStringList

	// Prerequisite
#define PKG_PREREQUISITE_OS_MIN_VERSION L"OSMinVersion"
#define PKG_PREREQUISITE_OS_MAX_VERSION_TESTED L"OSMaxVersionTested"
	PKGREAD_API BOOL GetPackagePrerequisite (_In_ HPKGREAD hReader, _In_ LPCWSTR lpName, _Outptr_ VERSION *pVerRet);
#define GetPackagePrerequisiteOsMinVersion(_In_hReader_, _Outptr_pVerRet_) GetPackagePrerequisite (_In_hReader_, PKG_PREREQUISITE_OS_MIN_VERSION, _Outptr_pVerRet_)
#define GetPackagePrerequisiteOsMaxVersionTested(_In_hReader_, _Outptr_pVerRet_) GetPackagePrerequisite (_In_hReader_, PKG_PREREQUISITE_OS_MAX_VERSION_TESTED, _Outptr_pVerRet_)
	PKGREAD_API LPWSTR GetPackagePrerequistieSystemVersionName (_In_ HPKGREAD hReader, _In_ LPCWSTR lpName);

	// File Stream
	// 从 Appx 包中获取 Appx 中的文件的文件流。
	// 注：只提取 Payloads 文件。不可提供 Footprint 文件。
	// 对于 AppxBundle 包，则随机从一个应用包中提取文件。
	PKGREAD_API HANDLE GetAppxFileFromAppxPackage (_In_ HPKGREAD hReader, _In_ LPCWSTR lpFileName);
	// 从 AppxBundle 包中获取 Appx 子包的文件流。
	PKGREAD_API HANDLE GetAppxBundlePayloadPackageFile (_In_ HPKGREAD hReader, _In_ LPCWSTR lpFileName);
	// 从 Appx 包中获取 Appx 的 Pri 文件流
	// 对于 AppxBundle 包，则随机从一个应用包中提取 Pri 文件。
	PKGREAD_API HANDLE GetAppxPriFileStream (_In_ HPKGREAD hReader);
	// 从 AppxBundle 包中获取的子包的文件流中提取包中的文件
	// 注：只提取 Payloads 文件。不可提供 Footprint 文件。
	PKGREAD_API HANDLE GetFileFromPayloadPackage (_In_ HANDLE hPackageStream, _In_ LPCWSTR lpFileName);
	// 从 AppxBundle 包中获取的子包的文件流中提取 Pri 文件流
	PKGREAD_API HANDLE GetPriFileFromPayloadPackage (_In_ HANDLE hPackageStream);
	// 从 AppxBundle 包中获取合适的包，合适指的是资源合适。
	// 第一个用于返回的参数指的是返回的语言合适的选项，第二个用于返回的参数是返回的缩放资源。
	// 如果指向的都是同一个包，那么两个参数返回的都是同一个指针。
	// 对于 Appx 文件直接返回假。
	PKGREAD_API BOOL GetSuitablePackageFromBundle (_In_ HPKGREAD hReader, _Outptr_ HANDLE *pStreamForLang, _Outptr_ HANDLE *pStreamForScale);
	// 文件流必须通过此来释放。
	PKGREAD_API ULONG DestroyAppxFileStream (_In_ HANDLE hFileStream);
	// 转换：文件流转换到 Data URL。这样转换后浏览器可以使用图片。
	// 注意：dwCharCount 指的是 lpMimeBuf 的可容纳字符数，如 WCHAR lpMimeBuf [dwCharCount]，不是实际可容纳字节数。
	// 返回的非空指针需要通过 free 释放。lpBase64Head 返回的是 Base64 编码后的数据，为返回指针指向的部分。
	// 如字符串为 data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D
	// 那么：						    ↑ lpBase64Head 指向于“base64,”后的第一个字符。
	PKGREAD_API LPWSTR StreamToBase64W (_In_ HANDLE hFileStream, _Out_writes_ (dwCharCount) LPWSTR lpMimeBuf, _In_ DWORD dwCharCount, _Outptr_ LPWSTR *lpBase64Head);
	// 获取 AppxBundle 包中的应用包文件流。最后通过 DestroyAppxFileStream 销毁。
	PKGREAD_API HANDLE GetAppxBundleApplicationPackageFile (_In_ HPKGREAD hReader);
	// 获取功能名的显示名，如 internetClient 对应“访问您的 Internet 连接”。返回的是适应于系统区域语言的文本。
	// 注意：返回的字符串一定要通过 free 释放。
	PKGREAD_API LPWSTR GetPackageCapabilityDisplayName (LPCWSTR lpCapabilityName);
	// 释放从本库中返回的字符串
	// 其实通过 free 释放即可，但考虑到环境问题，那么另写了个函数
	PKGREAD_API void PackageReaderFreeString (LPWSTR lpStrFromThisDll);

	// ========= 以下是针对于应用清单的读取器，一些常量和类型等是复用的 =========

	TEMPLATE_STRUCT (PKGMANIFESTREAD);
	typedef PKGMANIFESTREAD *HPKGMANIFESTREAD;
	// 创建 Manifest 读取器。
	// 返回一个 Manifest Reader 句柄，初始状态未加载任何文件。
	PKGREAD_API HPKGMANIFESTREAD CreateManifestReader ();
	// 从文件加载 Manifest。
	// 支持的输入：
	//  - AppxManifest.xml
	//  - .appx / .msix
	//  - .appxbundle / .msixbundle
	// 加载成功后，读取器会自动识别 Manifest 类型。
	PKGREAD_API BOOL LoadManifestFromFile (_In_ HPKGMANIFESTREAD hReader, _In_ LPCWSTR lpFilePath);
	// 从文件加载 Manifest。
	// 支持的输入：
	//  - AppxManifest.xml
	//  - .appx / .msix
	//  - .appxbundle / .msixbundle
	// 加载成功后，读取器会自动识别 Manifest 类型。
	PKGREAD_API BOOL LoadManifestFromFile (_In_ HPKGMANIFESTREAD hReader, _In_ LPCWSTR lpFilePath);
	// 销毁 Manifest 读取器（必须调用）。
	// 释放内部所有资源，句柄在此之后不可再使用。
	PKGREAD_API void DestroyManifestReader (_In_ HPKGMANIFESTREAD hReader);
	// 获取 Manifest 的类型。
	// 返回值：
	//  - PKGTYPE_APPX      ：单一 Appx / Msix 包
	//  - PKGTYPE_BUNDLE    ：AppxBundle / MsixBundle
	//  - PKGTYPE_UNKNOWN   ：未知或未加载
	PKGREAD_API WORD GetManifestType (_In_ HPKGMANIFESTREAD hReader);
	// 获取 Manifest 的类型。
	// 返回值：
	//  - PKGTYPE_APPX      ：单一 Appx / Msix 包
	//  - PKGTYPE_BUNDLE    ：AppxBundle / MsixBundle
	//  - PKGTYPE_UNKNOWN   ：未知或未加载
	PKGREAD_API WORD GetManifestType (_In_ HPKGMANIFESTREAD hReader);
	// 判断 Manifest 是否有效。
	// 如果 Manifest 解析失败、结构非法或未加载，返回 FALSE。
	PKGREAD_API BOOL IsManifestValid (_In_ HPKGMANIFESTREAD hReader);
	// 获取 Manifest 所表示包的角色。
	// 返回值：
	//  - PKGROLE_APPLICATION ：应用包
	//  - PKGROLE_FRAMEWORK   ：框架包
	//  - PKGROLE_RESOURCE    ：资源包
	//  - PKGROLE_UNKNOWN     ：未知
	//
	// 说明：
	//  - 对于 AppxBundle，永远返回 PKGROLE_APPLICATION。
	PKGREAD_API WORD GetManifestRole (_In_ HPKGMANIFESTREAD hReader);
	// 获取 Identity 的字符串字段。
	// dwName 可取值：
	//  - PKG_IDENTITY_NAME
	//  - PKG_IDENTITY_PUBLISHER
	//  - PKG_IDENTITY_PACKAGEFAMILYNAME
	//  - PKG_IDENTITY_PACKAGEFULLNAME
	//  - PKG_IDENTITY_RESOURCEID
	//
	// 返回值：
	//  - 成功：返回新分配的字符串（调用者负责释放）
	//  - 失败：返回 NULL
	PKGREAD_API LPWSTR GetManifestIdentityStringValue (_In_ HPKGMANIFESTREAD hReader, _In_ DWORD dwName);
#define GetManifestIdentityName(_In_hReader_) GetManifestIdentityStringValue (_In_hReader_, PKG_IDENTITY_NAME)
#define GetManifestIdentityPublisher(_In_hReader_) GetManifestIdentityStringValue (_In_hReader_, PKG_IDENTITY_PUBLISHER)
#define GetManifestIdentityPackageFamilyName(_In_hReader_) GetManifestIdentityStringValue (_In_hReader_, PKG_IDENTITY_PACKAGEFAMILYNAME)
#define GetManifestIdentityPackageFullName(_In_hReader_) GetManifestIdentityStringValue (_In_hReader_, PKG_IDENTITY_PACKAGEFULLNAME)
#define GetManifestIdentityResourceId(_In_hReader_) GetManifestIdentityStringValue (_In_hReader_, PKG_IDENTITY_RESOURCEID)
	// 获取 Identity 的版本号。
	//
	// pVersion 返回格式化后的 VERSION 结构。
	// 返回值：
	//  - TRUE  ：成功
	//  - FALSE ：失败或版本不存在
	PKGREAD_API BOOL GetManifestIdentityVersion (_In_ HPKGMANIFESTREAD hReader, _Out_ VERSION *pVersion);
	// 获取包支持的架构信息。
	// 对于单一 Appx 包，返回单一架构；
	// 对于 Bundle，返回所有子包架构的组合（按位或）。
	//
	// 返回值通过 pdwArchi 输出，取值为 PKG_ARCHITECTURE_* 宏。
	PKGREAD_API BOOL GetManifestIdentityArchitecture (_In_ HPKGMANIFESTREAD hReader, _Out_ DWORD *pdwArchi);
	// 获取 Properties 中的字符串值。
	// lpName 为属性名（如 "DisplayName"）。
	// 返回值：
	//  - 成功：返回新分配的字符串（调用者负责释放）
	//  - 失败：返回 NULL
	//
	// 说明：
	//  - 仅适用于单一 Appx 包。
	PKGREAD_API LPWSTR GetManifestPropertiesStringValue (_In_ HPKGMANIFESTREAD hReader, _In_ LPCWSTR lpName);
	// 获取 Properties 中的布尔值。
	//
	// pRet 返回布尔结果。
	// 返回 HRESULT，便于区分失败原因。
	//
	// 说明：
	//  - 仅适用于单一 Appx 包。
	PKGREAD_API HRESULT GetManifestPropertiesBoolValue (_In_ HPKGMANIFESTREAD hReader, _In_ LPCWSTR lpName, _Outptr_ BOOL *pRet);
	// 向应用枚举器中添加需要读取的 Application 属性名。
	// 返回 FALSE 表示属性名非法或重复。
	PKGREAD_API BOOL AddManifestApplicationItemGetName (_In_ LPCWSTR lpName);
	// 从应用枚举器中移除指定的 Application 属性名。
	PKGREAD_API BOOL RemoveManifestApplicationItemGetName (_In_ LPCWSTR lpName);
	// 获取 Applications 枚举器。
	// 返回一个应用枚举器句柄，调用者需手动销毁。
	//
	// 说明：
	//  - 仅适用于单一 Appx 包。
	PKGREAD_API HAPPENUMERATOR GetManifestApplications (_In_ HPKGMANIFESTREAD hReader);
	// 销毁 Applications 枚举器。
	PKGREAD_API void DestroyManifestApplications (_In_ HAPPENUMERATOR hEnumerator);
	// 获取资源支持的语言列表（字符串形式）。
	// 返回 HLIST_PVOID，内部元素为 LPWSTR。
	PKGREAD_API HLIST_PVOID GetManifestResourcesLanguages (_In_ HPKGMANIFESTREAD hReader);
	// 获取资源支持的语言列表（LCID 形式）。
	// 返回 HLIST_LCID。
	PKGREAD_API HLIST_LCID GetManifestResourcesLanguagesToLcid (_In_ HPKGMANIFESTREAD hReader);
	// 获取资源支持的缩放比例（Scale）。
	// 返回 HLIST_UINT32。
	PKGREAD_API HLIST_UINT32 GetManifestResourcesScales (_In_ HPKGMANIFESTREAD hReader);
	// 获取资源支持的 DirectX Feature Level。
	// 返回值为 PKG_RESOURCES_DXFEATURE_LEVEL* 位掩码组合。
	PKGREAD_API DWORD GetManifestResourcesDxFeatureLevels (_In_ HPKGMANIFESTREAD hReader);
	// 获取依赖包信息列表。
	// 返回 HLIST_DEPINFO，其中包含名称、发布者及最低版本。
	//
	// 说明：
	//  - 仅适用于单一 Appx 包。
	PKGREAD_API HLIST_DEPINFO GetManifestDependencesInfoList (_In_ HPKGMANIFESTREAD hReader);
	// 获取 Capability 列表（Capability）。
	// 返回的列表元素为 LPWSTR。
	//
	// 说明：
	//  - 仅适用于单一 Appx 包。
	PKGREAD_API HLIST_PVOID GetManifestCapabilitiesList (_In_ HPKGMANIFESTREAD hReader);
	// 获取 Device Capability 列表。
	// 返回的列表元素为 LPWSTR。
	//
	// 说明：
	//  - 仅适用于单一 Appx 包。
	PKGREAD_API HLIST_PVOID GetManifestDeviceCapabilitiesList (_In_ HPKGMANIFESTREAD hReader);
	// 获取指定前置条件的最低版本要求。
	// lpName 为前置组件名称。
	// pVerRet 返回版本结构。
	// 返回 TRUE 表示存在该前置条件。
	PKGREAD_API BOOL GetManifestPrerequisite (_In_ HPKGMANIFESTREAD hReader, _In_ LPCWSTR lpName, _Outptr_ VERSION *pVerRet);

	PKGREAD_API LPWSTR GetManifestPrerequistieSystemVersionName (_In_ HPKGMANIFESTREAD hReader, _In_ LPCWSTR lpName);

	PKGREAD_API BOOL PackageReaderGetFileRoot (_In_ LPWSTR lpFilePath);

	PKGREAD_API LPWSTR PackageReaderCombinePath (_In_ LPCWSTR lpLeft, _In_ LPCWSTR lpRight, _Outptr_ LPWSTR lpBuf);

	PKGREAD_API HANDLE PackageReaderGetFileStream (LPCWSTR lpFilePath);

	PKGREAD_API void PackageReaderDestroyFileStream (HANDLE hStream);

#ifdef _DEFAULT_INIT_VALUE_
#undef _DEFAULT_INIT_VALUE_
#endif
#ifdef _DEFAULT_INIT_VALUE_FORFUNC_
#undef _DEFAULT_INIT_VALUE_FORFUNC_
#endif
#ifdef __cplusplus
}
#endif

#if defined (__cplusplus)
#include <cstdlib>
#include <string>
#include <map>
#include <vector>
#include <functional>
#include <cstring>
#include <Shlwapi.h>
#include <algorithm>
//#include "..\priformatcli\priformatcli.h"
const std::vector <std::wstring> g_filepathitems =
{
	L"LockScreenLogo",
	L"Logo",
	L"SmallLogo",
	L"Square150x150Logo",
	L"Square30x30Logo",
	L"Square310x310Logo",
	L"Square44x44Logo",
	L"Square70x70Logo",
	L"Square71x71Logo",
	L"StartPage",
	L"Tall150x310Logo",
	L"VisualGroup",
	L"WideLogo",
	L"Wide310x150Logo",
	L"Executable"
};
std::map <std::wstring, std::wstring> g_capnamemap;
std::wstring GetPackageCapabilityDisplayName (const std::wstring &capname)
{
	try
	{
		if (g_capnamemap.find (capname) != g_capnamemap.end () && !g_capnamemap.at (capname).empty ()) return g_capnamemap.at (capname);
		else
		{
			LPWSTR lpstr = GetPackageCapabilityDisplayName (capname.c_str ());
			std::wstring ret = L"";
			ret += lpstr ? lpstr : L"";
			if (lpstr) free (lpstr);
			lpstr = nullptr;
			g_capnamemap [capname] = ret;
			return ret;
		}
	}
	catch (...)
	{
		LPWSTR lpstr = GetPackageCapabilityDisplayName (capname.c_str ());
		std::wstring ret = L"";
		ret += lpstr ? lpstr : L"";
		if (lpstr) free (lpstr);
		lpstr = nullptr;
		g_capnamemap [capname] = ret;
		return ret;
	}
	return L"";
}
class package_reader
{
	private:
	HPKGREAD hReader = nullptr;
	std::wstring filepath = L"";
	bool usepri = false;
	bool resswitch = false;
#ifdef _PRI_READER_CLI_HEADER_
	prifilebundle pribundlereader;
	std::vector <IStream *> prifilestreams;
#endif

	void initpri ()
	{
	#ifdef _PRI_READER_CLI_HEADER_
		pribundlereader.destroy ();
		for (auto &it : prifilestreams)
		{
			if (it != nullptr)
			{
				DestroyAppxFileStream (it);
				it = nullptr;
			}
		}
		prifilestreams.clear ();
		switch (this->package_type ())
		{
			case PKGTYPE_APPX: {
				IStream *pristream = (IStream *)GetAppxPriFileStream (hReader);
				if (pristream)
				{
					prifilestreams.push_back (pristream);
					pribundlereader.set (3, pristream);
				}
			} break;
			case PKGTYPE_BUNDLE: {
				HANDLE hls = nullptr, hss = nullptr;
				destruct rel1 ([&hls, &hss] () {
					if (hls == hss) hss = nullptr;
					if (hls) DestroyAppxFileStream (hls);
					if (hss) DestroyAppxFileStream (hss);
				});
				GetSuitablePackageFromBundle (hReader, &hls, &hss);
				HANDLE hlpri = GetPriFileFromPayloadPackage (hls),
					hspri = GetPriFileFromPayloadPackage (hss);
				IStream *ls = (IStream *)hls, *ss = (IStream *)hss;
				switch ((bool)ls << 1 | (bool)ss)
				{
					case 0b01:
					case 0b10: {
						if (hlpri) pribundlereader.set (1, (IStream *)hlpri);
						if (hspri) pribundlereader.set (2, (IStream *)hspri);
						if (hlpri) prifilestreams.push_back ((IStream *)hlpri);
						if (hspri) prifilestreams.push_back ((IStream *)hspri);
						HANDLE hd = GetAppxBundleApplicationPackageFile (hReader);
						destruct relthd ([&hd] () {
							if (hd) DestroyAppxFileStream (hd);
						});
						HANDLE hdpri = GetPriFileFromPayloadPackage (hd);
						if (hd) pribundlereader.set (3, (IStream *)hd);
						if (hd) prifilestreams.push_back ((IStream *)hdpri);
					} break;
					case 0b11: {
						if (ls) pribundlereader.set (1, (IStream *)hlpri);
						if (ss) pribundlereader.set (2, (IStream *)hspri);
						if (ls && hlpri) prifilestreams.push_back ((IStream *)hlpri);
						if (ss && hspri) prifilestreams.push_back ((IStream *)hspri);
					} break;
					default:
					case 0b00: {
						IStream *pkgstream = (IStream *)GetAppxBundleApplicationPackageFile (hReader);
						destruct relthd ([&pkgstream] () {
							if (pkgstream) DestroyAppxFileStream (pkgstream);
						});
						IStream *pristream = (IStream *)GetPriFileFromPayloadPackage (pkgstream);
						if (pristream)
						{
							prifilestreams.push_back (pristream);
							pribundlereader.set (3, pristream);
						}
					} break;
				}
			} break;
		}
		std::sort (prifilestreams.begin (), prifilestreams.end ());
		auto last = std::unique (prifilestreams.begin (), prifilestreams.end ());
		prifilestreams.erase (last, prifilestreams.end ());
		bool lastvalue = resswitch;
		resswitch = false;
		try
		{
			std::vector <std::wstring> resnames;
			{
				auto prop = get_properties ();
				std::wstring temp = prop.description ();
				if (IsMsResourcePrefix (temp.c_str ())) resnames.push_back (temp);
				temp = prop.display_name ();
				if (IsMsResourcePrefix (temp.c_str ())) resnames.push_back (temp);
				temp = prop.publisher_display_name ();
				if (IsMsResourcePrefix (temp.c_str ())) resnames.push_back (temp);
				resnames.push_back (prop.logo ());
			}
			{
				auto app = get_applications ();
				std::vector <application> apps;
				app.get (apps);
				for (auto &it_map : apps)
				{
					for (auto &it_item : it_map)
					{
						if (std::find (g_filepathitems.begin (), g_filepathitems.end (), it_item.first) != g_filepathitems.end () && !it_item.second.empty ())
							resnames.push_back (it_item.second);
						else if (IsMsResourcePrefix (it_item.second.c_str ())) resnames.push_back (it_item.second);
					}
				}
			}
			pribundlereader.add_search (resnames);
		}
		catch (const std::exception &e) {}
		resswitch = lastvalue;
	#endif
	}
	typedef struct deconstr
	{
		std::function <void ()> endtask = nullptr;
		deconstr (std::function <void ()> pf): endtask (pf) {}
		~deconstr () { if (endtask) endtask (); }
	} destruct;
	public:
	class base_subitems
	{
		protected:
		HPKGREAD &hReader;
		public:
		base_subitems (HPKGREAD &hReader): hReader (hReader) {}
	};
	class identity: public base_subitems
	{
		using base = base_subitems;
		public:
		using base::base;
		std::wstring string_value (DWORD dwName) const
		{
			LPWSTR lpstr = nullptr;
			deconstr rel ([&lpstr] () {
				if (lpstr) free (lpstr);
				lpstr = nullptr;
			});
			lpstr = GetPackageIdentityStringValue (hReader, dwName);
			return lpstr ? lpstr : L"";
		}
		std::wstring name () const { return string_value (PKG_IDENTITY_NAME); }
		std::wstring publisher () const { return string_value (PKG_IDENTITY_PUBLISHER); }
		std::wstring package_family_name () const { return string_value (PKG_IDENTITY_PACKAGEFAMILYNAME); }
		std::wstring package_full_name () const { return string_value (PKG_IDENTITY_PACKAGEFULLNAME); }
		std::wstring resource_id () const { return string_value (PKG_IDENTITY_RESOURCEID); }
		VERSION version (bool read_subpkg_ver = false) const { VERSION ver; GetPackageIdentityVersion (hReader, &ver, read_subpkg_ver); return ver; }
		DWORD architecture () const { DWORD dw = 0; GetPackageIdentityArchitecture (hReader, &dw); return dw; }
	};
	class properties: public base_subitems
	{
		using base = base_subitems;
		public:
		using base::base;
		std::wstring string_value (const std::wstring &swName) const
		{
			LPWSTR lpstr = nullptr;
			deconstr rel ([&lpstr] () {
				if (lpstr) free (lpstr);
				lpstr = nullptr;
			});
			lpstr = GetPackagePropertiesStringValue (hReader, swName.c_str ());
			return lpstr ? lpstr : L"";
		}
		bool bool_value (const std::wstring &swName, bool bRetWhenFailed = false) const
		{
			BOOL ret = FALSE;
			HRESULT hr = GetPackagePropertiesBoolValue (hReader, swName.c_str (), &ret);
			if (FAILED (hr)) return bRetWhenFailed;
			else return ret != FALSE;
		}
		std::wstring display_name (bool toprires = true) 
		{ 
			std::wstring ret = string_value (PKG_PROPERTIES_DISPLAYNAME);
			if (!toprires) return ret;
			if (!enable_pri ()) return ret;
		#ifdef _PRI_READER_CLI_HEADER_
			else
			{
				if (!IsMsResourcePrefix (ret.c_str ())) return ret;
				std::wstring privalue = pri_get_res (ret);
				if (privalue.empty ()) return ret;
				return privalue;
			}
		#endif
			return ret;
		}
		std::wstring publisher_display_name (bool toprires = true) 
		{ 
			std::wstring ret = string_value (PKG_PROPERTIES_PUBLISHER);
			if (!toprires) return ret;
			if (!enable_pri ()) return ret;
		#ifdef _PRI_READER_CLI_HEADER_
			else
			{
				if (!IsMsResourcePrefix (ret.c_str ())) return ret;
				std::wstring privalue = pri_get_res (ret);
				if (privalue.empty ()) return ret;
				return privalue;
			}
		#endif
			return ret;
		}
		std::wstring description (bool toprires = true) 
		{ 
			std::wstring ret = string_value (PKG_PROPERTIES_DESCRIPTION);
			if (!toprires) return ret;
			if (!enable_pri ()) return ret;
		#ifdef _PRI_READER_CLI_HEADER_
			else
			{
				if (!IsMsResourcePrefix (ret.c_str ())) return ret;
				std::wstring privalue = pri_get_res (ret);
				if (privalue.empty ()) return ret;
				return privalue;
			}
		#endif
			return ret;
		}
		std::wstring logo (bool toprires = true)
		{ 
			std::wstring ret = string_value (PKG_PROPERTIES_LOGO);
			if (!toprires) return ret;
			if (!enable_pri ()) return ret;
		#ifdef _PRI_READER_CLI_HEADER_
			else
			{
				std::wstring privalue = pri_get_res (ret);
				if (privalue.empty ()) return ret;
				return privalue;
			}
		#endif
			return ret;
		}
		std::wstring logo_base64 ()
		{
			switch (GetPackageType (hReader))
			{
				case PKGTYPE_APPX: {
					HANDLE pic = GetAppxFileFromAppxPackage (hReader, logo ().c_str ());
					destruct relp ([&pic] () {
						if (pic) DestroyAppxFileStream (pic);
						pic = nullptr;
					});
					LPWSTR lpstr = nullptr;
					destruct rel ([&lpstr] () {
						if (lpstr) free (lpstr);
						lpstr = nullptr;
					});
					lpstr = StreamToBase64W (pic, nullptr, 0, nullptr);
					return lpstr ? lpstr : L"";
				} break;
				case PKGTYPE_BUNDLE: {
					HANDLE pkg = nullptr, pic = nullptr;
					destruct relp ([&pic, &pkg] () {
						if (pic == pkg) pkg = nullptr; // 虽然来说这个代码永远无法达到，但是保险起见
						if (pic) DestroyAppxFileStream (pic);
						if (pkg) DestroyAppxFileStream (pkg);
						pkg = nullptr;
						pic = nullptr;
					});
					GetSuitablePackageFromBundle (hReader, nullptr, &pkg);
					pic = GetFileFromPayloadPackage (pkg, logo ().c_str ());
					LPWSTR lpstr = nullptr;
					destruct rel ([&lpstr] () {
						if (lpstr) free (lpstr);
						lpstr = nullptr;
					});
					lpstr = StreamToBase64W (pic, nullptr, 0, nullptr);
					if (!(lpstr && *lpstr))
					{
						if (lpstr) free (lpstr);
						HANDLE pkg1 = nullptr, pic1 = nullptr;
						destruct relp1 ([&pic1, &pkg1] () {
							if (pic1 == pkg1) pkg1 = nullptr; // 虽然来说这个代码永远无法达到，但是保险起见
							if (pic1) DestroyAppxFileStream (pic1);
							if (pkg1) DestroyAppxFileStream (pkg1);
							pkg1 = nullptr;
							pic1 = nullptr;
						});
						pkg1 = GetAppxBundleApplicationPackageFile (hReader);
						if (pkg1 == pkg) pkg = nullptr;
						if (pkg1)
						{
							pic1 = GetFileFromPayloadPackage (pkg1, logo ().c_str ());
							lpstr = StreamToBase64W (pic1, nullptr, 0, nullptr);
						}
					}
					return lpstr ? lpstr : L"";
				} break;
			}
			return L"";
		}
		bool framework () const { return bool_value (PKG_PROPERTIES_FRAMEWORD); }
		bool resource_package () const { return bool_value (PKG_PROPERTIES_IS_RESOURCE); }
	#ifdef _PRI_READER_CLI_HEADER_
		prifilebundle *pbreader = nullptr;
		bool *usepri = nullptr;
		bool *resconvert = nullptr;
	#endif
		bool enable_pri () const
		{
		#ifdef _PRI_READER_CLI_HEADER_
			if (!pbreader) return false;
			if (!usepri || !*usepri) return false;
			if (!resconvert) return false;
			return *resconvert;
		#else
			return false;
		#endif
		}
		std::wstring pri_get_res (const std::wstring &resname)
		{
		#ifdef _PRI_READER_CLI_HEADER_
			if (resname.empty ()) return L"";
			if (!pbreader) return L"";
			return pbreader->resource (resname);
		#else
			return L"";
		#endif
		}
	#ifdef _PRI_READER_CLI_HEADER_
		properties (HPKGREAD &hReader, prifilebundle *pri, bool *up, bool *resc):
			base (hReader), pbreader (pri), usepri (up), resconvert (resc) {}
	#endif
	};
	class application: public std::map <std::wstring, std::wstring>
	{
		using base = std::map <std::wstring, std::wstring>;
		public:
		using base::base;
		application () = default;
		std::wstring user_model_id () { return this->at (L"AppUserModelID"); }
		friend bool operator == (application &a1, application &a2) { return !_wcsicmp (a1.user_model_id ().c_str (), a2.user_model_id ().c_str ()); }
		friend bool operator != (application &a1, application &a2) { return _wcsicmp (a1.user_model_id ().c_str (), a2.user_model_id ().c_str ()); }
		explicit operator bool () { return this->user_model_id ().empty (); }
		std::wstring &operator [] (const std::wstring &key)
		{
			auto it = this->find (key);
			if (it == this->end ())
			{
				it = this->insert (std::make_pair (key, L"")).first;
			}
			if (!enable_pri ()) return it->second;
		#ifdef _PRI_READER_CLI_HEADER_
			if (IsMsResourcePrefix (it->second.c_str ()))
			{
				std::wstring privalue = pri_get_res (it->second);
				if (!privalue.empty ()) return privalue;
				return it->second;
			}
			else if (std::find (g_filepathitems.begin (), g_filepathitems.end (), it->first) != g_filepathitems.end () && !it->second.empty ())
			{
				std::wstring privalue = pri_get_res (it->second);
				if (!privalue.empty ()) return privalue;
				return it->second;
			}
		#endif
			return it->second;
		}
		typename base::iterator find_case_insensitive (const std::wstring &key)
		{
			for (auto it = this->begin (); it != this->end (); ++it)
			{
				if (_wcsicmp (it->first.c_str (), key.c_str ()) == 0)
					return it;
			}
			return this->end ();
		}
		typename base::const_iterator find_case_insensitive (const std::wstring &key) const
		{
			for (auto it = this->begin (); it != this->end (); ++ it)
			{
				if (_wcsicmp (it->first.c_str (), key.c_str ()) == 0)
					return it;
			}
			return this->end ();
		}
		std::wstring at (const std::wstring &key)
		{
			auto it = this->find_case_insensitive (key);
			if (it == this->end ()) throw std::out_of_range ("application::at: key not found");
			if (!enable_pri ()) return it->second;
		#ifdef _PRI_READER_CLI_HEADER_
			if (IsMsResourcePrefix (it->second.c_str ()))
			{
				std::wstring privalue = pri_get_res (it->second);
				if (!privalue.empty ()) return privalue;
			}
		#endif
			return it->second;
		}
		std::wstring newat (const std::wstring &key, bool to_pri_string = true)
		{
			auto it = this->find (key);
			if (it == this->end ())
			{
				it = this->insert (std::make_pair (key, L"")).first;
			}
			if (!enable_pri () && to_pri_string) return it->second;
		#ifdef _PRI_READER_CLI_HEADER_
			if (IsMsResourcePrefix (it->second.c_str ()))
			{
				std::wstring privalue = pri_get_res (it->second);
				if (!privalue.empty ()) return privalue;
				return it->second;
			}
			else if (std::find (g_filepathitems.begin (), g_filepathitems.end (), it->first) != g_filepathitems.end () && !it->second.empty ())
			{
				std::wstring privalue = pri_get_res (it->second);
				if (!privalue.empty ()) return privalue;
				return it->second;
			}
		#endif
			return it->second;
		}
		// 仅支持文件
		std::wstring newat_base64 (const std::wstring &key)
		{
		#ifdef _PRI_READER_CLI_HEADER_
			std::wstring value = newat (key);
			if (std::find (g_filepathitems.begin (), g_filepathitems.end (), key) != g_filepathitems.end () && !value.empty ())
			{
				switch (GetPackageType (hReader))
				{
					case PKGTYPE_APPX: {
						HANDLE pic = GetAppxFileFromAppxPackage (hReader, value.c_str ());
						destruct relp ([&pic] () {
							if (pic) DestroyAppxFileStream (pic);
							pic = nullptr;
						});
						LPWSTR lpstr = nullptr;
						destruct rel ([&lpstr] () {
							if (lpstr) free (lpstr);
							lpstr = nullptr;
						});
						lpstr = StreamToBase64W (pic, nullptr, 0, nullptr);
						return lpstr ? lpstr : L"";
					} break;
					case PKGTYPE_BUNDLE: {
						HANDLE pkg = nullptr, pic = nullptr;
						destruct relp ([&pic, &pkg] () {
							if (pic == pkg) pkg = nullptr; // 虽然来说这个代码永远无法达到，但是保险起见
							if (pic) DestroyAppxFileStream (pic);
							if (pkg) DestroyAppxFileStream (pkg);
							pkg = nullptr;
							pic = nullptr;
						});
						GetSuitablePackageFromBundle (hReader, nullptr, &pkg);
						pic = GetFileFromPayloadPackage (pkg, value.c_str ());
						LPWSTR lpstr = nullptr;
						destruct rel ([&lpstr] () {
							if (lpstr) free (lpstr);
							lpstr = nullptr;
						});
						lpstr = StreamToBase64W (pic, nullptr, 0, nullptr);
						return lpstr ? lpstr : L"";
					} break;
				}
				return L"";
			}
			else return L"";
		#else
			return L"";
		#endif
		}
	#ifdef _PRI_READER_CLI_HEADER_
		HPKGREAD hReader = nullptr;
		prifilebundle *pbreader = nullptr;
		bool *usepri = nullptr;
		bool *resconvert = nullptr;
	#endif
		bool enable_pri () const
		{
		#ifdef _PRI_READER_CLI_HEADER_
			if (!pbreader) return false;
			if (!usepri || !*usepri) return false;
			if (!resconvert) return false;
			return *resconvert;
		#else
			return false;
		#endif
		}
		std::wstring pri_get_res (const std::wstring &resname)
		{
		#ifdef _PRI_READER_CLI_HEADER_
			if (resname.empty ()) return L"";
			if (!pbreader) return L"";
			return pbreader->resource (resname);
		#else
			return L"";
		#endif
		}
	#ifdef _PRI_READER_CLI_HEADER_
		application (HPKGREAD hReader, prifilebundle *pri, bool *up, bool *resc):
			hReader (hReader), pbreader (pri), usepri (up), resconvert (resc) {}
	#endif
	};
	class applications
	{
		private:
		HPKGREAD &hReader;
		HAPPENUMERATOR hList = nullptr;
		public:
		applications (HPKGREAD &hReader): hReader (hReader)
		{
			hList = GetPackageApplications (hReader);
		}
		~applications ()
		{
			if (hList) DestroyPackageApplications (hList);
			hList = nullptr;
		}
		size_t get (std::vector <application> &apps)
		{
			apps.clear ();
			if (!hList) return 0;
			HLIST_PVOID hMapList = ApplicationsToMap (hList);
			deconstr endt ([&hMapList] {
				if (hMapList) DestroyApplicationsMap (hMapList);
				hMapList = nullptr;
			});
			if (!hMapList) return 0;
			for (size_t i = 0; i < hMapList->dwSize; i ++)
			{
				HLIST_PVOID &hKeyValues = ((HLIST_PVOID *)hMapList->alpVoid) [i];
			#ifdef _PRI_READER_CLI_HEADER_
				application app (hReader, pbreader, usepri, resconvert);
			#else
				application app;
			#endif
				for (size_t j = 0; j < hKeyValues->dwSize; j ++)
				{
					HPAIR_PVOID &hPair = ((HPAIR_PVOID *)hKeyValues->alpVoid) [j];
					LPWSTR lpKey = (LPWSTR)hPair->lpKey;
					LPWSTR lpValue = (LPWSTR)hPair->lpValue;
					if (!lpKey || !*lpKey) continue;
					app [lpKey] = lpValue ? lpValue : L"";
				}
				apps.push_back (app);
			}
			return apps.size ();
		}
	#ifdef _PRI_READER_CLI_HEADER_
		prifilebundle *pbreader = nullptr;
		bool *usepri = nullptr;
		bool *resconvert = nullptr;
		applications (HPKGREAD &hReader, prifilebundle *pri, bool *up, bool *resc):
			hReader (hReader), pbreader (pri), usepri (up), resconvert (resc) { hList = GetPackageApplications (hReader); }
	#endif
	};
	class capabilities: public base_subitems
	{
		using base = base_subitems;
		public:
		using base::base;
		size_t capabilities_name (std::vector <std::wstring> &output) const
		{
			output.clear ();
			HLIST_PVOID hList = GetCapabilitiesList (hReader);
			deconstr endt ([&hList] () {
				if (hList) DestroyCapabilitiesList (hList);
				hList = nullptr;
			});
			if (!hList) return 0;
			for (size_t i = 0; i < hList->dwSize; i ++)
			{
				LPWSTR lpstr = (LPWSTR)hList->alpVoid [i];
				if (!lpstr) continue;
				output.push_back (lpstr);
			}
			return output.size ();
		}
		size_t device_capabilities (std::vector <std::wstring> &output) const
		{
			output.clear ();
			HLIST_PVOID hList = GetDeviceCapabilitiesList (hReader);
			deconstr endt ([&hList] () {
				if (hList) DestroyDeviceCapabilitiesList (hList);
				hList = nullptr;
			});
			if (!hList) return 0;
			for (size_t i = 0; i < hList->dwSize; i ++)
			{
				LPWSTR lpstr = (LPWSTR)hList->alpVoid [i];
				if (!lpstr) continue;
				output.push_back (lpstr);
			}
			return output.size ();
		}
	};
	struct dependency
	{
		std::wstring name, publisher;
		VERSION vermin;
		dependency (const std::wstring &name = L"", const std::wstring &pub = L"", const VERSION &ver = VERSION ()):
			name (name), publisher (pub), vermin (ver) {}
	};
	class dependencies: public base_subitems
	{
		using base = base_subitems;
		public:
		using base::base;
		size_t get (std::vector <dependency> &output) const
		{
			auto hList = GetDependencesInfoList (hReader);
			deconstr rel ([&hList] () {
				DestroyDependencesInfoList (hList);
			});
			if (!hList) return 0;
			for (size_t i = 0; i < hList->dwSize; i ++)
			{
				DEPENDENCY_INFO &depinf = ((DEPENDENCY_INFO *)hList->aDepInfo) [i];
				if (!depinf.lpName || !*depinf.lpName) continue;
				output.push_back (dependency (depinf.lpName, depinf.lpPublisher ? depinf.lpPublisher : L"", depinf.verMin));
			}
			return output.size ();
		}
	};
	class resources: public base_subitems
	{
		using base = base_subitems;
		public:
		using base::base;
		size_t languages (std::vector <std::wstring> &langs) const
		{
			langs.clear ();
			auto hList = GetResourcesLanguages (hReader);
			deconstr rel ([&hList] () {
				if (hList) DestroyResourcesLanguagesList (hList);
				hList = nullptr;
			});
			if (!hList) return 0;
			for (size_t i = 0; i < hList->dwSize; i ++)
			{
				LPWSTR lpstr = ((LPWSTR *)hList->alpVoid) [i];
				if (lpstr && *lpstr) langs.push_back (std::wstring (lpstr));
			}
			return langs.size ();
		}
		size_t languages (std::vector <LCID> &langs) const
		{
			langs.clear ();
			auto hList = GetResourcesLanguagesToLcid (hReader);
			deconstr rel ([&hList] () {
				if (hList) DestroyResourcesLanguagesLcidList (hList);
				hList = nullptr;
			});
			if (!hList) return 0;
			for (size_t i = 0; i < hList->dwSize; i ++)
			{
				if (hList->aLcid [i]) langs.push_back (hList->aLcid [i]);
			}
			return langs.size ();
		}
		size_t scales (std::vector <UINT32> &output) const
		{
			output.clear ();
			auto hList = GetResourcesScales (hReader);
			deconstr rel ([&hList] () {
				if (hList) DestroyResourcesScalesList (hList);
			});
			if (!hList) return 0;
			for (size_t i = 0; i < hList->dwSize; i ++)
			{
				UINT32 s = hList->aUI32 [i];
				if (s) output.push_back (s);
			}
			return output.size ();
		}
		DWORD dx_feature_level () const { return GetResourcesDxFeatureLevels (hReader); }
		// 向数组添加的是以 PKG_RESOURCES_DXFEATURE_* 前缀的常量
		size_t dx_feature_level (std::vector <DWORD> &ret)
		{
			DWORD dx = dx_feature_level ();
			if (dx & PKG_RESOURCES_DXFEATURE_LEVEL9) ret.push_back (PKG_RESOURCES_DXFEATURE_LEVEL9);
			else if (dx & PKG_RESOURCES_DXFEATURE_LEVEL10) ret.push_back (PKG_RESOURCES_DXFEATURE_LEVEL10);
			else if (dx & PKG_RESOURCES_DXFEATURE_LEVEL11) ret.push_back (PKG_RESOURCES_DXFEATURE_LEVEL11);
			else if (dx & PKG_RESOURCES_DXFEATURE_LEVEL12) ret.push_back (PKG_RESOURCES_DXFEATURE_LEVEL12);
			return ret.size ();
		}
	};
	class prerequisites: public base_subitems
	{
		using base = base_subitems;
		public:
		using base::base;
		VERSION get_version (const std::wstring &name) const
		{
			VERSION ver;
			GetPackagePrerequisite (hReader, name.c_str (), &ver);
			return ver;
		}
		VERSION os_min_version () const { return get_version (PKG_PREREQUISITE_OS_MIN_VERSION); }
		VERSION os_max_version_tested () const { return get_version (PKG_PREREQUISITE_OS_MAX_VERSION_TESTED); }
		std::wstring get_description (const std::wstring &name) const
		{
			LPWSTR lpstr = GetPackagePrerequistieSystemVersionName (hReader, name.c_str ());
			deconstr relt ([&lpstr] () {
				if (lpstr) free (lpstr);
				lpstr = nullptr;
			});
			return lpstr ? lpstr : L"";
		}
		std::wstring os_min_version_description () const { return get_description (PKG_PREREQUISITE_OS_MIN_VERSION); }
		std::wstring os_max_version_tested_description () const { return get_description (PKG_PREREQUISITE_OS_MAX_VERSION_TESTED); }
	};
	package_reader (): hReader (CreatePackageReader ()) {}
	package_reader (const std::wstring &fpath): hReader (CreatePackageReader ())
	{
		file (fpath);
	}
	~package_reader () 
	{ 
		DestroyPackageReader (hReader); 
		hReader = nullptr;
	#ifdef _PRI_READER_CLI_HEADER_
		pribundlereader.destroy ();
		for (auto &it : prifilestreams) if (it != nullptr) DestroyAppxFileStream (it);
		prifilestreams.clear ();
	#endif
	}
	std::wstring file () const { return filepath; }
	bool file (const std::wstring &path)
	{
		return LoadPackageFromFile (hReader, (filepath = path).c_str ());
	}
	// PKGTYPE_* 前缀常量
	WORD package_type () const { return GetPackageType (hReader); }
	bool valid () const { return hReader && IsPackageValid (hReader); }
	// PKGROLE_* 前缀常量
	WORD package_role () const { return GetPackageRole (hReader); }
	identity get_identity () { return identity (hReader); }
	properties get_properties () 
	{
		return properties (hReader
		#ifdef _PRI_READER_CLI_HEADER_
			,
			&pribundlereader,
			&usepri,
			&resswitch
		#endif
		); 
	}
	applications get_applications () 
	{ 
		return applications (hReader
		#ifdef _PRI_READER_CLI_HEADER_
			,
			&pribundlereader,
			&usepri,
			&resswitch
		#endif
		); 
	}
	capabilities get_capabilities () { return capabilities (hReader); }
	dependencies get_dependencies () { return dependencies (hReader); }
	resources get_resources () { return resources (hReader); }
	prerequisites get_prerequisites () { return prerequisites (hReader); }
	// 是否允许使用 PRI
	bool use_pri () const 
	{ 
	#ifdef _PRI_READER_CLI_HEADER_
		return usepri;
	#else
		return false;
	#endif
	}
	// 是否允许使用 PRI
	bool use_pri (bool value)
	{
	#ifdef _PRI_READER_CLI_HEADER_
		bool laststatus = usepri;
		usepri = value;
		if (laststatus ^ usepri) initpri ();
		return usepri;
	#else
		return usepri = false;
	#endif
	}
	// 是否自动从 PRI 中提取资源
	bool enable_pri_convert () const { return resswitch; }
	// 是否自动从 PRI 中提取资源
	bool enable_pri_convert (bool value) 
	{
	#ifdef _PRI_READER_CLI_HEADER_
		return resswitch = value;
	#else
		return resswitch = false;
	#endif
	}
};
class manifest_reader
{
	private:
	HPKGMANIFESTREAD hReader = nullptr;
	std::wstring filepath = L"";
	bool usepri = false;
	bool resswitch = false;
#ifdef _PRI_READER_CLI_HEADER_
	prifile prireader;
#endif
	std::wstring get_fileroot ()
	{
		std::vector <wchar_t> root (filepath.capacity ());
		wcscpy (root.data (), filepath.c_str ());
		PackageReaderGetFileRoot (root.data ());
		return root.data ();
	}
	static std::wstring path_combine (const std::wstring &l, const std::wstring &r)
	{
		std::vector <wchar_t> buffer (l.length () + r.length () + 10);
		PackageReaderCombinePath (l.c_str (), r.c_str (), buffer.data ());
		return buffer.data ();
	}
	void initpri ()
	{
	#ifdef _PRI_READER_CLI_HEADER_
		prireader.destroy ();
		switch (this->package_type ())
		{
			case PKGTYPE_APPX: {
				prireader.create (path_combine (get_fileroot (), L"resources.pri"));
			} break;
		}
		bool lastvalue = resswitch;
		resswitch = false;
		try
		{
			std::vector <std::wstring> resnames;
			{
				auto prop = get_properties ();
				std::wstring temp = prop.description ();
				if (IsMsResourcePrefix (temp.c_str ())) resnames.push_back (temp);
				temp = prop.display_name ();
				if (IsMsResourcePrefix (temp.c_str ())) resnames.push_back (temp);
				temp = prop.publisher_display_name ();
				if (IsMsResourcePrefix (temp.c_str ())) resnames.push_back (temp);
				resnames.push_back (prop.logo ());
			}
			{
				auto app = get_applications ();
				std::vector <application> apps;
				app.get (apps);
				for (auto &it_map : apps)
				{
					for (auto &it_item : it_map)
					{
						if (std::find (g_filepathitems.begin (), g_filepathitems.end (), it_item.first) != g_filepathitems.end () && !it_item.second.empty ())
							resnames.push_back (it_item.second);
						else if (IsMsResourcePrefix (it_item.second.c_str ())) resnames.push_back (it_item.second);
					}
				}
			}
			prireader.add_search (resnames);
		}
		catch (const std::exception &e) {}
		resswitch = lastvalue;
	#endif
	}
	typedef struct deconstr
	{
		std::function <void ()> endtask = nullptr;
		deconstr (std::function <void ()> pf): endtask (pf) {}
		~deconstr () { if (endtask) endtask (); }
	} destruct;
	public:
	class base_subitems
	{
		protected:
		HPKGMANIFESTREAD &hReader;
		public:
		base_subitems (HPKGMANIFESTREAD &hReader): hReader (hReader) {}
	};
	class identity: public base_subitems
	{
		using base = base_subitems;
		public:
		using base::base;
		std::wstring string_value (DWORD dwName) const
		{
			LPWSTR lpstr = nullptr;
			deconstr rel ([&lpstr] () {
				if (lpstr) free (lpstr);
				lpstr = nullptr;
			});
			lpstr = GetManifestIdentityStringValue (hReader, dwName);
			return lpstr ? lpstr : L"";
		}
		std::wstring name () const { return string_value (PKG_IDENTITY_NAME); }
		std::wstring publisher () const { return string_value (PKG_IDENTITY_PUBLISHER); }
		std::wstring package_family_name () const { return string_value (PKG_IDENTITY_PACKAGEFAMILYNAME); }
		std::wstring package_full_name () const { return string_value (PKG_IDENTITY_PACKAGEFULLNAME); }
		std::wstring resource_id () const { return string_value (PKG_IDENTITY_RESOURCEID); }
		VERSION version (bool read_subpkg_ver = false) const { VERSION ver; GetManifestIdentityVersion (hReader, &ver); return ver; }
		DWORD architecture () const { DWORD dw = 0; GetManifestIdentityArchitecture (hReader, &dw); return dw; }
	};
	class properties: public base_subitems
	{
		using base = base_subitems;
		std::wstring root = L"";
		public:
		using base::base;
		std::wstring string_value (const std::wstring &swName) const
		{
			LPWSTR lpstr = nullptr;
			deconstr rel ([&lpstr] () {
				if (lpstr) free (lpstr);
				lpstr = nullptr;
			});
			lpstr = GetManifestPropertiesStringValue (hReader, swName.c_str ());
			return lpstr ? lpstr : L"";
		}
		bool bool_value (const std::wstring &swName, bool bRetWhenFailed = false) const
		{
			BOOL ret = FALSE;
			HRESULT hr = GetManifestPropertiesBoolValue (hReader, swName.c_str (), &ret);
			if (FAILED (hr)) return bRetWhenFailed;
			else return ret != FALSE;
		}
		std::wstring display_name (bool toprires = true)
		{
			std::wstring ret = string_value (PKG_PROPERTIES_DISPLAYNAME);
			if (!toprires) return ret;
			if (!enable_pri ()) return ret;
		#ifdef _PRI_READER_CLI_HEADER_
			else
			{
				if (!IsMsResourcePrefix (ret.c_str ())) return ret;
				std::wstring privalue = pri_get_res (ret);
				if (privalue.empty ()) return ret;
				return privalue;
			}
		#endif
			return ret;
		}
		std::wstring publisher_display_name (bool toprires = true)
		{
			std::wstring ret = string_value (PKG_PROPERTIES_PUBLISHER);
			if (!toprires) return ret;
			if (!enable_pri ()) return ret;
		#ifdef _PRI_READER_CLI_HEADER_
			else
			{
				if (!IsMsResourcePrefix (ret.c_str ())) return ret;
				std::wstring privalue = pri_get_res (ret);
				if (privalue.empty ()) return ret;
				return privalue;
			}
		#endif
			return ret;
		}
		std::wstring description (bool toprires = true)
		{
			std::wstring ret = string_value (PKG_PROPERTIES_DESCRIPTION);
			if (!toprires) return ret;
			if (!enable_pri ()) return ret;
		#ifdef _PRI_READER_CLI_HEADER_
			else
			{
				if (!IsMsResourcePrefix (ret.c_str ())) return ret;
				std::wstring privalue = pri_get_res (ret);
				if (privalue.empty ()) return ret;
				return privalue;
			}
		#endif
			return ret;
		}
		std::wstring logo (bool toprires = true)
		{
			std::wstring ret = string_value (PKG_PROPERTIES_LOGO);
			if (!toprires) return ret;
			if (!enable_pri ()) return ret;
		#ifdef _PRI_READER_CLI_HEADER_
			else
			{
				std::wstring privalue = pri_get_res (ret);
				if (privalue.empty ()) return ret;
				return privalue;
			}
		#endif
			return ret;
		}
		std::wstring logo_base64 ()
		{
			switch (GetManifestType (hReader))
			{
				case PKGTYPE_APPX: {
					auto path = path_combine (root, logo ());
					HANDLE pic = PackageReaderGetFileStream (path.c_str ());
					destruct relp ([&pic] () {
						if (pic) PackageReaderDestroyFileStream (pic);
						pic = nullptr;
					});
					LPWSTR lpstr = nullptr;
					destruct rel ([&lpstr] () {
						if (lpstr) free (lpstr);
						lpstr = nullptr;
					});
					lpstr = StreamToBase64W (pic, nullptr, 0, nullptr);
					return lpstr ? lpstr : L"";
				} break;
			}
			return L"";
		}
		bool framework () const { return bool_value (PKG_PROPERTIES_FRAMEWORD); }
		bool resource_package () const { return bool_value (PKG_PROPERTIES_IS_RESOURCE); }
	#ifdef _PRI_READER_CLI_HEADER_
		prifile *pbreader = nullptr;
		bool *usepri = nullptr;
		bool *resconvert = nullptr;
	#endif
		bool enable_pri () const
		{
		#ifdef _PRI_READER_CLI_HEADER_
			if (!pbreader) return false;
			if (!usepri || !*usepri) return false;
			if (!resconvert) return false;
			return *resconvert;
		#else
			return false;
		#endif
		}
		std::wstring pri_get_res (const std::wstring &resname)
		{
		#ifdef _PRI_READER_CLI_HEADER_
			if (resname.empty ()) return L"";
			if (!pbreader) return L"";
			return pbreader->resource (resname);
		#else
			return L"";
		#endif
		}
	#ifdef _PRI_READER_CLI_HEADER_
		properties (HPKGMANIFESTREAD &hReader, prifile *pri, bool *up, bool *resc, const std::wstring &pathroot):
			base (hReader), pbreader (pri), usepri (up), resconvert (resc), root (pathroot) {}
	#endif
	};
	class application: public std::map <std::wstring, std::wstring>
	{
		using base = std::map <std::wstring, std::wstring>;
		std::wstring root = L"";
		public:
		using base::base;
		application () = default;
		std::wstring user_model_id () { return this->at (L"AppUserModelID"); }
		friend bool operator == (application &a1, application &a2) { return !_wcsicmp (a1.user_model_id ().c_str (), a2.user_model_id ().c_str ()); }
		friend bool operator != (application &a1, application &a2) { return _wcsicmp (a1.user_model_id ().c_str (), a2.user_model_id ().c_str ()); }
		explicit operator bool () { return this->user_model_id ().empty (); }
		std::wstring &operator [] (const std::wstring &key)
		{
			auto it = this->find (key);
			if (it == this->end ())
			{
				it = this->insert (std::make_pair (key, L"")).first;
			}
			if (!enable_pri ()) return it->second;
		#ifdef _PRI_READER_CLI_HEADER_
			if (IsMsResourcePrefix (it->second.c_str ()))
			{
				std::wstring privalue = pri_get_res (it->second);
				if (!privalue.empty ()) return privalue;
				return it->second;
			}
			else if (std::find (g_filepathitems.begin (), g_filepathitems.end (), it->first) != g_filepathitems.end () && !it->second.empty ())
			{
				std::wstring privalue = pri_get_res (it->second);
				if (!privalue.empty ()) return privalue;
				return it->second;
			}
		#endif
			return it->second;
		}
		typename base::iterator find_case_insensitive (const std::wstring &key)
		{
			for (auto it = this->begin (); it != this->end (); ++it)
			{
				if (_wcsicmp (it->first.c_str (), key.c_str ()) == 0)
					return it;
			}
			return this->end ();
		}
		typename base::const_iterator find_case_insensitive (const std::wstring &key) const
		{
			for (auto it = this->begin (); it != this->end (); ++ it)
			{
				if (_wcsicmp (it->first.c_str (), key.c_str ()) == 0)
					return it;
			}
			return this->end ();
		}
		std::wstring at (const std::wstring &key)
		{
			auto it = this->find_case_insensitive (key);
			if (it == this->end ()) throw std::out_of_range ("application::at: key not found");
			if (!enable_pri ()) return it->second;
		#ifdef _PRI_READER_CLI_HEADER_
			if (IsMsResourcePrefix (it->second.c_str ()))
			{
				std::wstring privalue = pri_get_res (it->second);
				if (!privalue.empty ()) return privalue;
			}
		#endif
			return it->second;
		}
		std::wstring newat (const std::wstring &key, bool to_pri_string = true)
		{
			auto it = this->find (key);
			if (it == this->end ())
			{
				it = this->insert (std::make_pair (key, L"")).first;
			}
			if (!enable_pri () && to_pri_string) return it->second;
		#ifdef _PRI_READER_CLI_HEADER_
			if (IsMsResourcePrefix (it->second.c_str ()))
			{
				std::wstring privalue = pri_get_res (it->second);
				if (!privalue.empty ()) return privalue;
				return it->second;
			}
			else if (std::find (g_filepathitems.begin (), g_filepathitems.end (), it->first) != g_filepathitems.end () && !it->second.empty ())
			{
				std::wstring privalue = pri_get_res (it->second);
				if (!privalue.empty ()) return privalue;
				return it->second;
			}
		#endif
			return it->second;
		}
		// 仅支持文件
		std::wstring newat_base64 (const std::wstring &key)
		{
		#ifdef _PRI_READER_CLI_HEADER_
			std::wstring value = newat (key);
			if (std::find (g_filepathitems.begin (), g_filepathitems.end (), key) != g_filepathitems.end () && !value.empty ())
			{
				switch (GetManifestType (hReader))
				{
					case PKGTYPE_APPX: {
						auto filepath = path_combine (root, value);
						HANDLE pic = PackageReaderGetFileStream (filepath.c_str ());
						destruct relp ([&pic] () {
							if (pic) PackageReaderDestroyFileStream (pic);
							pic = nullptr;
						});
						LPWSTR lpstr = nullptr;
						destruct rel ([&lpstr] () {
							if (lpstr) free (lpstr);
							lpstr = nullptr;
						});
						lpstr = StreamToBase64W (pic, nullptr, 0, nullptr);
						return lpstr ? lpstr : L"";
					} break;
				}
				return L"";
			}
			else return L"";
		#else
			return L"";
		#endif
		}
	#ifdef _PRI_READER_CLI_HEADER_
		HPKGMANIFESTREAD hReader = nullptr;
		prifile *pbreader = nullptr;
		bool *usepri = nullptr;
		bool *resconvert = nullptr;
	#endif
		bool enable_pri () const
		{
		#ifdef _PRI_READER_CLI_HEADER_
			if (!pbreader) return false;
			if (!usepri || !*usepri) return false;
			if (!resconvert) return false;
			return *resconvert;
		#else
			return false;
		#endif
		}
		std::wstring pri_get_res (const std::wstring &resname)
		{
		#ifdef _PRI_READER_CLI_HEADER_
			if (resname.empty ()) return L"";
			if (!pbreader) return L"";
			return pbreader->resource (resname);
		#else
			return L"";
		#endif
		}
	#ifdef _PRI_READER_CLI_HEADER_
		application (HPKGMANIFESTREAD hReader, prifile *pri, bool *up, bool *resc, const std::wstring &pathroot):
			hReader (hReader), pbreader (pri), usepri (up), resconvert (resc), root (pathroot) {}
	#endif
	};
	class applications
	{
		private:
		HPKGMANIFESTREAD &hReader;
		HAPPENUMERATOR hList = nullptr;
		std::wstring root = L"";
		public:
		applications (HPKGMANIFESTREAD &hReader): hReader (hReader)
		{
			hList = GetManifestApplications (hReader);
		}
		~applications ()
		{
			if (hList) DestroyPackageApplications (hList);
			hList = nullptr;
		}
		size_t get (std::vector <application> &apps)
		{
			apps.clear ();
			if (!hList) return 0;
			HLIST_PVOID hMapList = ApplicationsToMap (hList);
			deconstr endt ([&hMapList] {
				if (hMapList) DestroyApplicationsMap (hMapList);
				hMapList = nullptr;
			});
			if (!hMapList) return 0;
			for (size_t i = 0; i < hMapList->dwSize; i ++)
			{
				HLIST_PVOID &hKeyValues = ((HLIST_PVOID *)hMapList->alpVoid) [i];
			#ifdef _PRI_READER_CLI_HEADER_
				application app (hReader, pbreader, usepri, resconvert, root);
			#else
				application app;
			#endif
				for (size_t j = 0; j < hKeyValues->dwSize; j ++)
				{
					HPAIR_PVOID &hPair = ((HPAIR_PVOID *)hKeyValues->alpVoid) [j];
					LPWSTR lpKey = (LPWSTR)hPair->lpKey;
					LPWSTR lpValue = (LPWSTR)hPair->lpValue;
					if (!lpKey || !*lpKey) continue;
					app [lpKey] = lpValue ? lpValue : L"";
				}
				apps.push_back (app);
			}
			return apps.size ();
		}
	#ifdef _PRI_READER_CLI_HEADER_
		prifile *pbreader = nullptr;
		bool *usepri = nullptr;
		bool *resconvert = nullptr;
		applications (HPKGMANIFESTREAD &hReader, prifile *pri, bool *up, bool *resc, const std::wstring &pathroot):
			hReader (hReader), pbreader (pri), usepri (up), resconvert (resc), root (pathroot) { hList = GetManifestApplications (hReader); }
	#endif
	};
	class capabilities: public base_subitems
	{
		using base = base_subitems;
		public:
		using base::base;
		size_t capabilities_name (std::vector <std::wstring> &output) const
		{
			output.clear ();
			HLIST_PVOID hList = GetManifestCapabilitiesList (hReader);
			deconstr endt ([&hList] () {
				if (hList) DestroyCapabilitiesList (hList);
				hList = nullptr;
			});
			if (!hList) return 0;
			for (size_t i = 0; i < hList->dwSize; i ++)
			{
				LPWSTR lpstr = (LPWSTR)hList->alpVoid [i];
				if (!lpstr) continue;
				output.push_back (lpstr);
			}
			return output.size ();
		}
		size_t device_capabilities (std::vector <std::wstring> &output) const
		{
			output.clear ();
			HLIST_PVOID hList = GetManifestDeviceCapabilitiesList (hReader);
			deconstr endt ([&hList] () {
				if (hList) DestroyDeviceCapabilitiesList (hList);
				hList = nullptr;
			});
			if (!hList) return 0;
			for (size_t i = 0; i < hList->dwSize; i ++)
			{
				LPWSTR lpstr = (LPWSTR)hList->alpVoid [i];
				if (!lpstr) continue;
				output.push_back (lpstr);
			}
			return output.size ();
		}
	};
	struct dependency
	{
		std::wstring name, publisher;
		VERSION vermin;
		dependency (const std::wstring &name = L"", const std::wstring &pub = L"", const VERSION &ver = VERSION ()):
			name (name), publisher (pub), vermin (ver) {}
	};
	class dependencies: public base_subitems
	{
		using base = base_subitems;
		public:
		using base::base;
		size_t get (std::vector <dependency> &output) const
		{
			auto hList = GetManifestDependencesInfoList (hReader);
			deconstr rel ([&hList] () {
				DestroyDependencesInfoList (hList);
			});
			if (!hList) return 0;
			for (size_t i = 0; i < hList->dwSize; i ++)
			{
				DEPENDENCY_INFO &depinf = ((DEPENDENCY_INFO *)hList->aDepInfo) [i];
				if (!depinf.lpName || !*depinf.lpName) continue;
				output.push_back (dependency (depinf.lpName, depinf.lpPublisher ? depinf.lpPublisher : L"", depinf.verMin));
			}
			return output.size ();
		}
	};
	class resources: public base_subitems
	{
		using base = base_subitems;
		public:
		using base::base;
		size_t languages (std::vector <std::wstring> &langs) const
		{
			langs.clear ();
			auto hList = GetManifestResourcesLanguages (hReader);
			deconstr rel ([&hList] () {
				if (hList) DestroyResourcesLanguagesList (hList);
				hList = nullptr;
			});
			if (!hList) return 0;
			for (size_t i = 0; i < hList->dwSize; i ++)
			{
				LPWSTR lpstr = ((LPWSTR *)hList->alpVoid) [i];
				if (lpstr && *lpstr) langs.push_back (std::wstring (lpstr));
			}
			return langs.size ();
		}
		size_t languages (std::vector <LCID> &langs) const
		{
			langs.clear ();
			auto hList = GetManifestResourcesLanguagesToLcid (hReader);
			deconstr rel ([&hList] () {
				if (hList) DestroyResourcesLanguagesLcidList (hList);
				hList = nullptr;
			});
			if (!hList) return 0;
			for (size_t i = 0; i < hList->dwSize; i ++)
			{
				if (hList->aLcid [i]) langs.push_back (hList->aLcid [i]);
			}
			return langs.size ();
		}
		size_t scales (std::vector <UINT32> &output) const
		{
			output.clear ();
			auto hList = GetManifestResourcesScales (hReader);
			deconstr rel ([&hList] () {
				if (hList) DestroyResourcesScalesList (hList);
			});
			if (!hList) return 0;
			for (size_t i = 0; i < hList->dwSize; i ++)
			{
				UINT32 s = hList->aUI32 [i];
				if (s) output.push_back (s);
			}
			return output.size ();
		}
		DWORD dx_feature_level () const { return GetManifestResourcesDxFeatureLevels (hReader); }
		// 向数组添加的是以 PKG_RESOURCES_DXFEATURE_* 前缀的常量
		size_t dx_feature_level (std::vector <DWORD> &ret)
		{
			DWORD dx = dx_feature_level ();
			if (dx & PKG_RESOURCES_DXFEATURE_LEVEL9) ret.push_back (PKG_RESOURCES_DXFEATURE_LEVEL9);
			else if (dx & PKG_RESOURCES_DXFEATURE_LEVEL10) ret.push_back (PKG_RESOURCES_DXFEATURE_LEVEL10);
			else if (dx & PKG_RESOURCES_DXFEATURE_LEVEL11) ret.push_back (PKG_RESOURCES_DXFEATURE_LEVEL11);
			else if (dx & PKG_RESOURCES_DXFEATURE_LEVEL12) ret.push_back (PKG_RESOURCES_DXFEATURE_LEVEL12);
			return ret.size ();
		}
	};
	class prerequisites: public base_subitems
	{
		using base = base_subitems;
		public:
		using base::base;
		VERSION get_version (const std::wstring &name) const
		{
			VERSION ver;
			GetManifestPrerequisite (hReader, name.c_str (), &ver);
			return ver;
		}
		VERSION os_min_version () const { return get_version (PKG_PREREQUISITE_OS_MIN_VERSION); }
		VERSION os_max_version_tested () const { return get_version (PKG_PREREQUISITE_OS_MAX_VERSION_TESTED); }
		std::wstring get_description (const std::wstring &name) const
		{
			LPWSTR lpstr = GetManifestPrerequistieSystemVersionName (hReader, name.c_str ());
			deconstr relt ([&lpstr] () {
				if (lpstr) free (lpstr);
				lpstr = nullptr;
			});
			return lpstr ? lpstr : L"";
		}
		std::wstring os_min_version_description () const { return get_description (PKG_PREREQUISITE_OS_MIN_VERSION); }
		std::wstring os_max_version_tested_description () const { return get_description (PKG_PREREQUISITE_OS_MAX_VERSION_TESTED); }
	};
	manifest_reader (): hReader (CreateManifestReader ()) {}
	manifest_reader (const std::wstring &fpath): hReader (CreateManifestReader ())
	{
		file (fpath);
	}
	~manifest_reader ()
	{
		DestroyManifestReader (hReader);
		hReader = nullptr;
	#ifdef _PRI_READER_CLI_HEADER_
		prireader.destroy ();
	#endif
	}
	std::wstring file () const { return filepath; }
	bool file (const std::wstring &path)
	{
		return LoadManifestFromFile (hReader, (filepath = path).c_str ());
	}
	// PKGTYPE_* 前缀常量
	WORD package_type () const { return GetManifestType (hReader); }
	bool valid () const { return hReader && IsManifestValid (hReader); }
	// PKGROLE_* 前缀常量
	WORD package_role () const { return GetManifestRole (hReader); }
	identity get_identity () { return identity (hReader); }
	properties get_properties ()
	{
		return properties (hReader
		#ifdef _PRI_READER_CLI_HEADER_
			,
			&prireader,
			&usepri,
			&resswitch,
			get_fileroot ()
		#endif
		);
	}
	applications get_applications ()
	{
		return applications (hReader
		#ifdef _PRI_READER_CLI_HEADER_
			,
			&prireader,
			&usepri,
			&resswitch,
			get_fileroot ()
		#endif
		);
	}
	capabilities get_capabilities () { return capabilities (hReader); }
	dependencies get_dependencies () { return dependencies (hReader); }
	resources get_resources () { return resources (hReader); }
	prerequisites get_prerequisites () { return prerequisites (hReader); }
	// 是否允许使用 PRI
	bool use_pri () const
	{
	#ifdef _PRI_READER_CLI_HEADER_
		return usepri;
	#else
		return false;
	#endif
	}
	// 是否允许使用 PRI
	bool use_pri (bool value)
	{
	#ifdef _PRI_READER_CLI_HEADER_
		bool laststatus = usepri;
		usepri = value;
		if (laststatus ^ usepri) initpri ();
		return usepri;
	#else
		return usepri = false;
	#endif
	}
	// 是否自动从 PRI 中提取资源
	bool enable_pri_convert () const { return resswitch; }
	// 是否自动从 PRI 中提取资源
	bool enable_pri_convert (bool value)
	{
	#ifdef _PRI_READER_CLI_HEADER_
		return resswitch = value;
	#else
		return resswitch = false;
	#endif
	}
};
#endif

#endif
