mirror of
https://github.com/modernw/App-Installer-For-Windows-8.x-Reset.git
synced 2026-04-11 17:57:19 +10:00
Updated manager and added appx manifest reader.
This commit is contained in:
@@ -1213,4 +1213,544 @@ LPWSTR GetPackageCapabilityDisplayName (LPCWSTR lpCapabilityName)
|
||||
std::wstring ret = GetCapabilityDisplayName (capname);
|
||||
if (IsNormalizeStringEmpty (ret)) return nullptr;
|
||||
else return _wcsdup (ret.c_str ());
|
||||
}
|
||||
}
|
||||
|
||||
void PackageReaderFreeString (LPWSTR lpStrFromThisDll)
|
||||
{
|
||||
if (!lpStrFromThisDll) return;
|
||||
free (lpStrFromThisDll);
|
||||
}
|
||||
|
||||
// ========== 以下是对清单文件的读取 ==========
|
||||
#define ToHandleMRead(_cpp_ptr_) reinterpret_cast <HPKGMANIFESTREAD> (_cpp_ptr_)
|
||||
#define ToPtrManifest(_cpp_ptr_) reinterpret_cast <manifest *> (_cpp_ptr_)
|
||||
HPKGMANIFESTREAD CreateManifestReader () { return ToHandleMRead (new manifest ()); }
|
||||
BOOL LoadManifestFromFile (_In_ HPKGMANIFESTREAD hReader, _In_ LPCWSTR lpFilePath)
|
||||
{
|
||||
auto ptr = ToPtrManifest (hReader);
|
||||
if (!ptr) return false;
|
||||
return ptr->create (lpFilePath);
|
||||
}
|
||||
void DestroyManifestReader (_In_ HPKGMANIFESTREAD hReader)
|
||||
{
|
||||
auto ptr = ToPtrManifest (hReader);
|
||||
if (!ptr) return;
|
||||
return delete ptr;
|
||||
}
|
||||
WORD GetManifestType (_In_ HPKGMANIFESTREAD hReader)
|
||||
{
|
||||
auto ptr = ToPtrManifest (hReader);
|
||||
if (!ptr) return PKGTYPE_UNKNOWN;
|
||||
switch (ptr->type ())
|
||||
{
|
||||
case PackageType::unknown: return PKGTYPE_UNKNOWN;
|
||||
case PackageType::single: return PKGTYPE_APPX;
|
||||
case PackageType::bundle: return PKGTYPE_BUNDLE;
|
||||
}
|
||||
return PKGTYPE_UNKNOWN;
|
||||
}
|
||||
BOOL IsManifestValid (_In_ HPKGMANIFESTREAD hReader)
|
||||
{
|
||||
auto ptr = ToPtrManifest (hReader);
|
||||
if (!ptr) return false;
|
||||
return ptr->valid ();
|
||||
}
|
||||
WORD GetManifestRole (_In_ HPKGMANIFESTREAD hReader)
|
||||
{
|
||||
auto ptr = ToPtrManifest (hReader);
|
||||
if (!ptr) return PKGROLE_UNKNOWN;
|
||||
switch (ptr->type ())
|
||||
{
|
||||
case PackageType::unknown: return PKGROLE_UNKNOWN;
|
||||
case PackageType::bundle: return PKGROLE_APPLICATION;
|
||||
case PackageType::single: {
|
||||
auto ar = ptr->appx_reader ();
|
||||
switch (ar.package_role ())
|
||||
{
|
||||
case PackageRole::unknown: return PKGROLE_UNKNOWN;
|
||||
case PackageRole::application: return PKGROLE_APPLICATION;
|
||||
case PackageRole::framework: return PKGROLE_FRAMEWORK;
|
||||
case PackageRole::resource: return PKGROLE_RESOURCE;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
return PKGROLE_UNKNOWN;
|
||||
}
|
||||
// Identity
|
||||
LPWSTR GetManifestIdentityStringValue (_In_ HPKGMANIFESTREAD hReader, _In_ DWORD dwName)
|
||||
{
|
||||
auto ptr = ToPtrManifest (hReader);
|
||||
if (!ptr) return nullptr;
|
||||
switch (ptr->type ())
|
||||
{
|
||||
case PackageType::single: {
|
||||
auto reader = ptr->appx_reader ();
|
||||
auto id = reader.identity ();
|
||||
switch (LOWORD (dwName))
|
||||
{
|
||||
case PKG_IDENTITY_NAME: return _wcsdup (id.name ().c_str ());
|
||||
case PKG_IDENTITY_PUBLISHER: return _wcsdup (id.publisher ().c_str ());
|
||||
case PKG_IDENTITY_PACKAGEFAMILYNAME: return _wcsdup (id.package_family_name ().c_str ());
|
||||
case PKG_IDENTITY_PACKAGEFULLNAME: return _wcsdup (id.package_full_name ().c_str ());
|
||||
case PKG_IDENTITY_RESOURCEID: return _wcsdup (id.resource_id ().c_str ());
|
||||
}
|
||||
} break;
|
||||
case PackageType::bundle: {
|
||||
auto reader = ptr->bundle_reader ();
|
||||
auto id = reader.identity ();
|
||||
{
|
||||
switch (LOWORD (dwName))
|
||||
{
|
||||
case PKG_IDENTITY_NAME: return _wcsdup (id.name ().c_str ());
|
||||
case PKG_IDENTITY_PUBLISHER: return _wcsdup (id.publisher ().c_str ());
|
||||
case PKG_IDENTITY_PACKAGEFAMILYNAME: return _wcsdup (id.package_family_name ().c_str ());
|
||||
case PKG_IDENTITY_PACKAGEFULLNAME: return _wcsdup (id.package_full_name ().c_str ());
|
||||
case PKG_IDENTITY_RESOURCEID: return _wcsdup (id.resource_id ().c_str ());
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
BOOL GetManifestIdentityVersion (_In_ HPKGMANIFESTREAD hReader, _Out_ VERSION *pVersion)
|
||||
{
|
||||
auto ptr = ToPtrManifest (hReader);
|
||||
if (!ptr) return FALSE;
|
||||
if (!pVersion) return FALSE;
|
||||
switch (ptr->type ())
|
||||
{
|
||||
case PackageType::single: {
|
||||
auto reader = ptr->appx_reader ();
|
||||
auto id = reader.identity ();
|
||||
auto ver = id.version ();
|
||||
*pVersion = VersionClassToStruct (ver);
|
||||
return !ver.empty ();
|
||||
} break;
|
||||
case PackageType::bundle: {
|
||||
auto reader = ptr->bundle_reader ();
|
||||
auto id = reader.identity ();
|
||||
{
|
||||
auto ver = id.version ();
|
||||
*pVersion = VersionClassToStruct (ver);
|
||||
return !ver.empty ();
|
||||
}
|
||||
} break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
BOOL GetManifestIdentityArchitecture (_In_ HPKGMANIFESTREAD hReader, _Out_ DWORD *pdwArchi)
|
||||
{
|
||||
auto ptr = ToPtrManifest (hReader);
|
||||
if (!ptr) return FALSE;
|
||||
if (!pdwArchi) return FALSE;
|
||||
switch (ptr->type ())
|
||||
{
|
||||
case PackageType::single: {
|
||||
auto reader = ptr->appx_reader ();
|
||||
auto id = reader.identity ();
|
||||
auto archi = id.architecture ();
|
||||
DWORD ret = 0;
|
||||
switch (archi)
|
||||
{
|
||||
case APPX_PACKAGE_ARCHITECTURE::APPX_PACKAGE_ARCHITECTURE_X86:
|
||||
ret = PKG_ARCHITECTURE_X86; break;
|
||||
case APPX_PACKAGE_ARCHITECTURE::APPX_PACKAGE_ARCHITECTURE_ARM:
|
||||
ret = PKG_ARCHITECTURE_ARM; break;
|
||||
case APPX_PACKAGE_ARCHITECTURE::APPX_PACKAGE_ARCHITECTURE_X64:
|
||||
ret = PKG_ARCHITECTURE_X64; break;
|
||||
case APPX_PACKAGE_ARCHITECTURE::APPX_PACKAGE_ARCHITECTURE_NEUTRAL:
|
||||
ret = PKG_ARCHITECTURE_NEUTRAL; break;
|
||||
case (APPX_PACKAGE_ARCHITECTURE)12: // ARM64
|
||||
ret = PKG_ARCHITECTURE_ARM64; break;
|
||||
}
|
||||
*pdwArchi = ret;
|
||||
return ret != PKG_ARCHITECTURE_UNKNOWN;
|
||||
} break;
|
||||
case PackageType::bundle: {
|
||||
auto reader = ptr->bundle_reader ();
|
||||
auto ids = reader.package_id_items ();
|
||||
std::vector <appx_info::appx_iditem> apps;
|
||||
ids.application_packages (apps);
|
||||
DWORD ret = 0;
|
||||
for (auto &it : apps)
|
||||
{
|
||||
auto id = it.identity ();
|
||||
auto archi = id.architecture ();
|
||||
switch (archi)
|
||||
{
|
||||
case APPX_PACKAGE_ARCHITECTURE::APPX_PACKAGE_ARCHITECTURE_X86:
|
||||
ret |= PKG_ARCHITECTURE_X86; break;
|
||||
case APPX_PACKAGE_ARCHITECTURE::APPX_PACKAGE_ARCHITECTURE_ARM:
|
||||
ret |= PKG_ARCHITECTURE_ARM; break;
|
||||
case APPX_PACKAGE_ARCHITECTURE::APPX_PACKAGE_ARCHITECTURE_X64:
|
||||
ret |= PKG_ARCHITECTURE_X64; break;
|
||||
case APPX_PACKAGE_ARCHITECTURE::APPX_PACKAGE_ARCHITECTURE_NEUTRAL:
|
||||
ret |= PKG_ARCHITECTURE_NEUTRAL; break;
|
||||
case (APPX_PACKAGE_ARCHITECTURE)12: // ARM64
|
||||
ret |= PKG_ARCHITECTURE_ARM64; break;
|
||||
}
|
||||
}
|
||||
*pdwArchi = ret;
|
||||
return ret != PKG_ARCHITECTURE_UNKNOWN;
|
||||
} break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
// Properties
|
||||
LPWSTR GetManifestPropertiesStringValue (_In_ HPKGMANIFESTREAD hReader, _In_ LPCWSTR lpName)
|
||||
{
|
||||
auto ptr = ToPtrManifest (hReader);
|
||||
if (!ptr) return nullptr;
|
||||
switch (ptr->type ())
|
||||
{
|
||||
case PackageType::single: {
|
||||
auto reader = ptr->appx_reader ();
|
||||
auto prop = reader.properties ();
|
||||
return _wcsdup (prop.string_value (lpName ? lpName : L"").c_str ());
|
||||
} break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
HRESULT GetManifestPropertiesBoolValue (_In_ HPKGMANIFESTREAD hReader, _In_ LPCWSTR lpName, _Outptr_ BOOL *pRet)
|
||||
{
|
||||
auto ptr = ToPtrManifest (hReader);
|
||||
if (!ptr) return E_INVALIDARG;
|
||||
if (!pRet) return E_INVALIDARG;
|
||||
*pRet = FALSE;
|
||||
switch (ptr->type ())
|
||||
{
|
||||
case PackageType::single: {
|
||||
auto reader = ptr->appx_reader ();
|
||||
IAppxManifestReader *m = reader.manifest ();
|
||||
if (!m) return E_FAIL;
|
||||
CComPtr <IAppxManifestProperties> p;
|
||||
HRESULT hr = m->GetProperties (&p);
|
||||
if (FAILED (hr)) return hr;
|
||||
return p->GetBoolValue (lpName, pRet);
|
||||
} break;
|
||||
}
|
||||
return E_FAIL;
|
||||
}
|
||||
// Applications
|
||||
BOOL AddManifestApplicationItemGetName (_In_ LPCWSTR lpName)
|
||||
{
|
||||
if (std::wnstring (lpName ? lpName : L"").empty ()) return FALSE;
|
||||
return PushApplicationAttributeItem (lpName);
|
||||
}
|
||||
BOOL RemoveManifestApplicationItemGetName (_In_ LPCWSTR lpName)
|
||||
{
|
||||
if (std::wnstring (lpName ? lpName : L"").empty ()) return FALSE;
|
||||
return RemoveApplicationAttributeItem (lpName);
|
||||
}
|
||||
HAPPENUMERATOR GetManifestApplications (_In_ HPKGMANIFESTREAD hReader)
|
||||
{
|
||||
auto ptr = ToPtrManifest (hReader);
|
||||
if (!ptr) return nullptr;
|
||||
switch (ptr->type ())
|
||||
{
|
||||
case PackageType::single: {
|
||||
auto reader = ptr->appx_reader ();
|
||||
auto app = reader.applications ();
|
||||
auto appvec = new app_enumerator ();
|
||||
app.applications (*appvec);
|
||||
return ToHandleAppEnumerator (appvec);
|
||||
} break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
void DestroyManifestApplications (_In_ HAPPENUMERATOR hEnumerator)
|
||||
{
|
||||
auto ptr = ToPtrAppxApps (hEnumerator);
|
||||
if (ptr) delete ptr;
|
||||
}
|
||||
// Resources
|
||||
HLIST_PVOID GetManifestResourcesLanguages (_In_ HPKGMANIFESTREAD hReader)
|
||||
{
|
||||
auto ptr = ToPtrManifest (hReader);
|
||||
if (!ptr) return nullptr;
|
||||
std::vector <std::wnstring> langs;
|
||||
switch (ptr->type ())
|
||||
{
|
||||
case PackageType::single:
|
||||
{
|
||||
auto reader = ptr->appx_reader ();
|
||||
auto res = reader.resources ();
|
||||
res.languages (langs);
|
||||
break;
|
||||
}
|
||||
case PackageType::bundle:
|
||||
{
|
||||
auto br = ptr->bundle_reader ();
|
||||
auto res = br.package_id_items ();
|
||||
res.enumerate ([&langs] (IAppxBundleManifestPackageInfo *inf) {
|
||||
auto item = appx_info::appx_iditem (inf);
|
||||
std::vector <std::wnstring> l;
|
||||
auto qr = item.qualified_resources ();
|
||||
qr.languages (l);
|
||||
for (auto &it : l) push_unique <std::wnstring> (langs, it);
|
||||
});
|
||||
break;
|
||||
}
|
||||
default: return nullptr;
|
||||
}
|
||||
if (langs.empty ()) return nullptr;
|
||||
size_t count = langs.size ();
|
||||
size_t bytes = sizeof (LIST_PVOID) + sizeof (LPWSTR) * (count - 1);
|
||||
auto list = (HLIST_PVOID)malloc (bytes);
|
||||
ZeroMemory (list, bytes);
|
||||
if (!list) return nullptr;
|
||||
list->dwSize = 0;
|
||||
for (auto &it : langs) list->alpVoid [list->dwSize ++] = _wcsdup (it.c_str ());
|
||||
return list;
|
||||
}
|
||||
HLIST_LCID GetManifestResourcesLanguagesToLcid (_In_ HPKGMANIFESTREAD hReader)
|
||||
{
|
||||
auto ptr = ToPtrManifest (hReader);
|
||||
if (!ptr) return nullptr;
|
||||
std::vector <std::wnstring> langs;
|
||||
switch (ptr->type ())
|
||||
{
|
||||
case PackageType::single:
|
||||
{
|
||||
auto reader = ptr->appx_reader ();
|
||||
auto res = reader.resources ();
|
||||
res.languages (langs);
|
||||
break;
|
||||
}
|
||||
case PackageType::bundle:
|
||||
{
|
||||
auto br = ptr->bundle_reader ();
|
||||
auto res = br.package_id_items ();
|
||||
res.enumerate ([&langs] (IAppxBundleManifestPackageInfo *inf) {
|
||||
auto item = appx_info::appx_iditem (inf);
|
||||
std::vector <std::wnstring> l;
|
||||
auto qr = item.qualified_resources ();
|
||||
qr.languages (l);
|
||||
for (auto &it : l) push_unique <std::wnstring> (langs, it);
|
||||
});
|
||||
break;
|
||||
}
|
||||
default: return nullptr;
|
||||
}
|
||||
if (langs.empty ()) return nullptr;
|
||||
size_t len = sizeof (LIST_LCID) + sizeof (LCID) * langs.size ();
|
||||
HLIST_LCID hList = (HLIST_LCID)malloc (len);
|
||||
ZeroMemory (hList, len);
|
||||
hList->dwSize = 0;
|
||||
for (auto &it : langs)
|
||||
{
|
||||
LCID lcid = LocaleCodeToLcid (it);
|
||||
if (lcid)
|
||||
{
|
||||
hList->aLcid [hList->dwSize ++] = lcid;
|
||||
}
|
||||
}
|
||||
return hList;
|
||||
}
|
||||
HLIST_UINT32 GetManifestResourcesScales (_In_ HPKGMANIFESTREAD hReader)
|
||||
|
||||
{
|
||||
auto ptr = ToPtrManifest (hReader);
|
||||
if (!ptr) return nullptr;
|
||||
std::vector <UINT32> scales;
|
||||
switch (ptr->type ())
|
||||
{
|
||||
case PackageType::single:
|
||||
{
|
||||
auto reader = ptr->appx_reader ();
|
||||
auto res = reader.resources ();
|
||||
res.scales (scales);
|
||||
break;
|
||||
}
|
||||
case PackageType::bundle:
|
||||
{
|
||||
auto br = ptr->bundle_reader ();
|
||||
auto res = br.package_id_items ();
|
||||
res.enumerate ([&scales] (IAppxBundleManifestPackageInfo *inf) {
|
||||
auto item = appx_info::appx_iditem (inf);
|
||||
std::vector <UINT32> s;
|
||||
auto qr = item.qualified_resources ();
|
||||
qr.scales (s);
|
||||
for (auto &it : s) push_unique (scales, it);
|
||||
});
|
||||
break;
|
||||
}
|
||||
default: return nullptr;
|
||||
}
|
||||
if (scales.empty ()) return nullptr;
|
||||
size_t len = sizeof (LIST_UINT32) + sizeof (UINT32) * scales.size ();
|
||||
HLIST_UINT32 hList = (HLIST_UINT32)malloc (len);
|
||||
ZeroMemory (hList, len);
|
||||
hList->dwSize = 0;
|
||||
for (auto &it : scales)
|
||||
{
|
||||
if (!it) continue;
|
||||
hList->aUI32 [hList->dwSize ++] = it;
|
||||
}
|
||||
return hList;
|
||||
}
|
||||
DWORD GetManifestResourcesDxFeatureLevels (_In_ HPKGMANIFESTREAD hReader)
|
||||
|
||||
{
|
||||
auto ptr = ToPtrManifest (hReader);
|
||||
if (!ptr) return 0;
|
||||
DWORD dwFlags = 0;
|
||||
switch (ptr->type ())
|
||||
{
|
||||
case PackageType::single:
|
||||
{
|
||||
auto reader = ptr->appx_reader ();
|
||||
auto res = reader.resources ();
|
||||
std::vector <DX_FEATURE_LEVEL> dxlevels;
|
||||
res.dx_feature_level (dxlevels);
|
||||
for (auto &it : dxlevels)
|
||||
{
|
||||
switch (it)
|
||||
{
|
||||
case DX_FEATURE_LEVEL::DX_FEATURE_LEVEL_9:
|
||||
dwFlags |= PKG_RESOURCES_DXFEATURE_LEVEL9; break;
|
||||
case DX_FEATURE_LEVEL::DX_FEATURE_LEVEL_10:
|
||||
dwFlags |= PKG_RESOURCES_DXFEATURE_LEVEL10; break;
|
||||
case DX_FEATURE_LEVEL::DX_FEATURE_LEVEL_11:
|
||||
dwFlags |= PKG_RESOURCES_DXFEATURE_LEVEL11; break;
|
||||
case (DX_FEATURE_LEVEL)4:
|
||||
dwFlags |= PKG_RESOURCES_DXFEATURE_LEVEL12; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PackageType::bundle:
|
||||
{
|
||||
auto br = ptr->bundle_reader ();
|
||||
auto res = br.package_id_items ();
|
||||
res.enumerate ([&dwFlags] (IAppxBundleManifestPackageInfo *inf) {
|
||||
auto item = appx_info::appx_iditem (inf);
|
||||
std::vector <DX_FEATURE_LEVEL> dxlevels;
|
||||
auto qr = item.qualified_resources ();
|
||||
qr.dx_feature_level (dxlevels);
|
||||
for (auto &it : dxlevels)
|
||||
{
|
||||
switch (it)
|
||||
{
|
||||
case DX_FEATURE_LEVEL::DX_FEATURE_LEVEL_9:
|
||||
dwFlags |= PKG_RESOURCES_DXFEATURE_LEVEL9; break;
|
||||
case DX_FEATURE_LEVEL::DX_FEATURE_LEVEL_10:
|
||||
dwFlags |= PKG_RESOURCES_DXFEATURE_LEVEL10; break;
|
||||
case DX_FEATURE_LEVEL::DX_FEATURE_LEVEL_11:
|
||||
dwFlags |= PKG_RESOURCES_DXFEATURE_LEVEL11; break;
|
||||
case (DX_FEATURE_LEVEL)4:
|
||||
dwFlags |= PKG_RESOURCES_DXFEATURE_LEVEL12; break;
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
default: return 0;
|
||||
}
|
||||
return dwFlags;
|
||||
}
|
||||
// Dependencies
|
||||
HLIST_DEPINFO GetManifestDependencesInfoList (_In_ HPKGMANIFESTREAD hReader)
|
||||
{
|
||||
auto ptr = ToPtrManifest (hReader);
|
||||
if (!ptr) return nullptr;
|
||||
std::vector <dep_info> vec;
|
||||
switch (ptr->type ())
|
||||
{
|
||||
case PackageType::single: {
|
||||
auto reader = ptr->appx_reader ();
|
||||
auto deps = reader.dependencies ();
|
||||
deps.dependencies (vec);
|
||||
} break;
|
||||
}
|
||||
size_t len = sizeof (LIST_DEPINFO) + sizeof (DEPENDENCY_INFO) * vec.size ();
|
||||
HLIST_DEPINFO hList = (HLIST_DEPINFO)malloc (len);
|
||||
ZeroMemory (hList, len);
|
||||
hList->dwSize = 0;
|
||||
for (auto &it : vec)
|
||||
{
|
||||
auto &dep = hList->aDepInfo [hList->dwSize ++];
|
||||
dep.lpName = _wcsdup (it.name.c_str ());
|
||||
dep.lpPublisher = _wcsdup (it.publisher.c_str ());
|
||||
dep.verMin = VersionClassToStruct (it.minversion);
|
||||
}
|
||||
return hList;
|
||||
}
|
||||
// Capabilities
|
||||
HLIST_PVOID GetManifestCapabilitiesList (_In_ HPKGMANIFESTREAD hReader)
|
||||
{
|
||||
auto ptr = ToPtrManifest (hReader);
|
||||
if (!ptr) return nullptr;
|
||||
std::vector <std::wnstring> caps;
|
||||
switch (ptr->type ())
|
||||
{
|
||||
case PackageType::single: {
|
||||
auto reader = ptr->appx_reader ();
|
||||
auto cap = reader.capabilities ();
|
||||
std::vector <std::wstring> vec;
|
||||
cap.capabilities_names (vec);
|
||||
for (auto &it : vec)
|
||||
{
|
||||
auto cname = std::wnstring (it.c_str ());
|
||||
if (cname.empty ()) continue;
|
||||
push_unique (caps, cname);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
size_t len = sizeof (LIST_PVOID) + sizeof (LPWSTR) * caps.size ();
|
||||
HLIST_PVOID hList = (HLIST_PVOID)malloc (len);
|
||||
ZeroMemory (hList, len);
|
||||
hList->dwSize = 0;
|
||||
for (auto &it : caps)
|
||||
{
|
||||
hList->alpVoid [hList->dwSize ++] = (LPVOID)_wcsdup (it.c_str ());
|
||||
}
|
||||
return hList;
|
||||
}
|
||||
HLIST_PVOID GetManifestDeviceCapabilitiesList (_In_ HPKGMANIFESTREAD hReader)
|
||||
{
|
||||
auto ptr = ToPtrManifest (hReader);
|
||||
if (!ptr) return nullptr;
|
||||
std::vector <std::wnstring> caps;
|
||||
switch (ptr->type ())
|
||||
{
|
||||
case PackageType::single: {
|
||||
auto reader = ptr->appx_reader ();
|
||||
auto cap = reader.capabilities ();
|
||||
std::vector <std::wstring> vec;
|
||||
cap.device_capabilities (vec);
|
||||
for (auto &it : vec)
|
||||
{
|
||||
auto cname = std::wnstring (it.c_str ());
|
||||
if (cname.empty ()) continue;
|
||||
push_unique (caps, cname);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
size_t len = sizeof (LIST_PVOID) + sizeof (LPWSTR) * caps.size ();
|
||||
HLIST_PVOID hList = (HLIST_PVOID)malloc (len);
|
||||
ZeroMemory (hList, len);
|
||||
hList->dwSize = 0;
|
||||
for (auto &it : caps)
|
||||
{
|
||||
hList->alpVoid [hList->dwSize ++] = (LPVOID)_wcsdup (it.c_str ());
|
||||
}
|
||||
return hList;
|
||||
}
|
||||
// Prerequisite
|
||||
BOOL GetManifestPrerequisite (_In_ HPKGMANIFESTREAD hReader, _In_ LPCWSTR lpName, _Outptr_ VERSION *pVerRet)
|
||||
{
|
||||
auto ptr = ToPtrManifest (hReader);
|
||||
if (!ptr) return FALSE;
|
||||
switch (ptr->type ())
|
||||
{
|
||||
case PackageType::single: {
|
||||
auto reader = ptr->appx_reader ();
|
||||
auto pre = reader.prerequisites ();
|
||||
auto ver = pre.get_version (lpName ? lpName : L"");
|
||||
*pVerRet = VersionClassToStruct (ver);
|
||||
return !ver.empty ();
|
||||
} break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ extern "C"
|
||||
#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);
|
||||
@@ -286,6 +286,155 @@ extern "C"
|
||||
// 获取功能名的显示名,如 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);
|
||||
|
||||
#ifdef _DEFAULT_INIT_VALUE_
|
||||
#undef _DEFAULT_INIT_VALUE_
|
||||
#endif
|
||||
|
||||
@@ -1336,3 +1336,202 @@ class package
|
||||
appxreader appx_reader () const { return appxreader (*(IAppxPackageReader **)&this->appx); }
|
||||
bundlereader bundle_reader () const { return bundlereader (*(IAppxBundleReader **)&this->bundle); }
|
||||
};
|
||||
|
||||
class appxmanifest: virtual public com_info_quote <IAppxManifestReader>
|
||||
{
|
||||
using Base = com_info_quote <IAppxManifestReader>;
|
||||
template <typename IComPtr, typename ReturnType, typename Fn> HRESULT get (IComPtr iptr, Fn func, ReturnType *retvalue) const { if (!iptr) return E_FAIL; return (iptr->*func) (retvalue); }
|
||||
using Manifest = IAppxManifestReader;
|
||||
public:
|
||||
using Base::Base;
|
||||
Manifest *manifest () { return pointer (); }
|
||||
template <class IComPtr, class Func> HRESULT get_from_manifest (Func fn, _Outptr_ IComPtr *output) const
|
||||
{
|
||||
if (!pointer ()) return E_FAIL;
|
||||
return get (pointer (), fn, output);
|
||||
}
|
||||
HRESULT get_identity (_Outptr_ IAppxManifestPackageId **output) const { return get_from_manifest <IAppxManifestPackageId *> (&Manifest::GetPackageId, output); }
|
||||
appx_info::appx_id identity () const
|
||||
{
|
||||
IAppxManifestPackageId *ip = nullptr;
|
||||
get_identity (&ip);
|
||||
return appx_info::appx_id (ip);
|
||||
}
|
||||
appx_info::appx_res resources () const
|
||||
{
|
||||
return appx_info::appx_res (pointer ());
|
||||
}
|
||||
HRESULT get_properties (_Outptr_ IAppxManifestProperties **output) const { return get_from_manifest <IAppxManifestProperties *> (&Manifest::GetProperties, output); }
|
||||
appx_info::appx_prop properties () const
|
||||
{
|
||||
IAppxManifestProperties *ip = nullptr;
|
||||
HRESULT hr = get_properties (&ip);
|
||||
return appx_info::appx_prop (ip);
|
||||
}
|
||||
appx_info::appx_preq prerequisites () const
|
||||
{
|
||||
return appx_info::appx_preq (pointer ());
|
||||
}
|
||||
HRESULT get_applications (_Outptr_ IAppxManifestApplicationsEnumerator **output) const { return get_from_manifest <IAppxManifestApplicationsEnumerator *> (&Manifest::GetApplications, output); }
|
||||
appx_info::appx_apps applications () const
|
||||
{
|
||||
IAppxManifestApplicationsEnumerator *ip = nullptr;
|
||||
get_applications (&ip);
|
||||
return appx_info::appx_apps (ip);
|
||||
}
|
||||
HRESULT get_capabilities (_Outptr_ APPX_CAPABILITIES *output) const { return get_from_manifest <APPX_CAPABILITIES> (&Manifest::GetCapabilities, output); }
|
||||
HRESULT get_device_capabilities (_Outptr_ IAppxManifestDeviceCapabilitiesEnumerator **output) const { return get_from_manifest <IAppxManifestDeviceCapabilitiesEnumerator *> (&Manifest::GetDeviceCapabilities, output); }
|
||||
appx_info::appx_capabs capabilities () const
|
||||
{
|
||||
APPX_CAPABILITIES caps;
|
||||
IAppxManifestDeviceCapabilitiesEnumerator *ip = nullptr;
|
||||
if (pointer ()) pointer ()->GetDeviceCapabilities (&ip);
|
||||
auto im = pointer ();
|
||||
if (SUCCEEDED (get_capabilities (&caps))) return appx_info::appx_capabs (ip, caps, im);
|
||||
return appx_info::appx_capabs (ip);
|
||||
}
|
||||
HRESULT get_dependencies (_Outptr_ IAppxManifestPackageDependenciesEnumerator **output) const { return get_from_manifest <IAppxManifestPackageDependenciesEnumerator *> (&Manifest::GetPackageDependencies, output); }
|
||||
appx_info::appx_deps dependencies () const
|
||||
{
|
||||
IAppxManifestPackageDependenciesEnumerator *ip = nullptr;
|
||||
get_dependencies (&ip);
|
||||
return appx_info::appx_deps (ip);
|
||||
}
|
||||
PackageRole package_role () const
|
||||
{
|
||||
auto prop = properties ();
|
||||
if (prop.framework ()) return PackageRole::framework;
|
||||
try { if (prop.resource_package ()) return PackageRole::resource; }
|
||||
catch (const std::exception &e) {}
|
||||
auto app = applications ();
|
||||
std::vector <std::wstring> apps;
|
||||
if (app.app_user_model_ids (apps)) return PackageRole::application;
|
||||
else return PackageRole::unknown;
|
||||
}
|
||||
};
|
||||
class bundlemanifest: virtual public com_info_quote <IAppxBundleManifestReader>
|
||||
{
|
||||
using Base = com_info_quote <IAppxBundleManifestReader>;
|
||||
public:
|
||||
using Base::Base;
|
||||
template <typename IComPtr, typename ReturnType, typename Fn> HRESULT get (IComPtr iptr, Fn func, ReturnType *retvalue) const { if (!iptr) return E_FAIL; return (iptr->*func) (retvalue); }
|
||||
using Manifest = IAppxBundleManifestReader;
|
||||
Manifest *manifest () { return pointer (); }
|
||||
template <class IComPtr, class Func> HRESULT get_from_manifest (Func fn, _Outptr_ IComPtr *output) const
|
||||
{
|
||||
if (!pointer ()) return E_FAIL;
|
||||
return get (pointer (), fn, output);
|
||||
}
|
||||
HRESULT get_identity (_Outptr_ IAppxManifestPackageId **output) const { return get_from_manifest (&Manifest::GetPackageId, output); }
|
||||
appx_info::appx_id identity () const
|
||||
{
|
||||
IAppxManifestPackageId *ip = nullptr;
|
||||
get_identity (&ip);
|
||||
return appx_info::appx_id (ip);
|
||||
}
|
||||
HRESULT get_package_id_items (_Outptr_ IAppxBundleManifestPackageInfoEnumerator **output) const { return get_from_manifest (&Manifest::GetPackageInfoItems, output); }
|
||||
appx_info::appx_iditems package_id_items () const
|
||||
{
|
||||
IAppxBundleManifestPackageInfoEnumerator *ip = nullptr;
|
||||
get_package_id_items (&ip);
|
||||
return appx_info::appx_iditems (ip);
|
||||
}
|
||||
};
|
||||
|
||||
HRESULT GetAppxManifestReader (_In_ LPCWSTR inputPath, _Outptr_ IAppxManifestReader **manifestReader)
|
||||
{
|
||||
if (!manifestReader) return E_POINTER;
|
||||
*manifestReader = nullptr;
|
||||
HRESULT hr;
|
||||
CComPtr <IStream> stream;
|
||||
CComPtr <IAppxFactory> factory;
|
||||
CComPtr <IAppxPackageReader> packageReader;
|
||||
hr = SHCreateStreamOnFileEx (
|
||||
inputPath,
|
||||
STGM_READ | STGM_SHARE_DENY_NONE,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
FALSE,
|
||||
nullptr,
|
||||
&stream
|
||||
);
|
||||
if (FAILED (hr)) return hr;
|
||||
hr = CoCreateInstance (
|
||||
__uuidof (AppxFactory),
|
||||
nullptr,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
IID_PPV_ARGS (&factory)
|
||||
);
|
||||
if (FAILED (hr)) return hr;
|
||||
hr = factory->CreatePackageReader (stream, &packageReader);
|
||||
if (SUCCEEDED (hr))
|
||||
{
|
||||
return packageReader->GetManifest (manifestReader);
|
||||
}
|
||||
hr = factory->CreateManifestReader (stream, manifestReader);
|
||||
return hr;
|
||||
}
|
||||
HRESULT GetBundleManifestReader (_In_ LPCWSTR bundlePath, _Outptr_ IAppxBundleManifestReader **manifestReader)
|
||||
{
|
||||
if (!manifestReader) return E_POINTER;
|
||||
*manifestReader = nullptr;
|
||||
HRESULT hr;
|
||||
CComPtr <IStream> stream;
|
||||
CComPtr <IAppxBundleFactory> factory;
|
||||
CComPtr <IAppxBundleReader> bundleReader;
|
||||
hr = SHCreateStreamOnFileEx (
|
||||
bundlePath,
|
||||
STGM_READ | STGM_SHARE_DENY_NONE,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
FALSE,
|
||||
nullptr,
|
||||
&stream
|
||||
);
|
||||
if (FAILED (hr)) return hr;
|
||||
hr = CoCreateInstance (
|
||||
__uuidof(AppxBundleFactory),
|
||||
nullptr,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
IID_PPV_ARGS (&factory)
|
||||
);
|
||||
if (FAILED (hr)) return hr;
|
||||
hr = factory->CreateBundleReader (stream, &bundleReader);
|
||||
if (FAILED (hr)) return hr;
|
||||
hr = bundleReader->GetManifest (manifestReader);
|
||||
if (FAILED (hr)) return hr = factory->CreateBundleManifestReader (stream, manifestReader);
|
||||
return hr;
|
||||
}
|
||||
|
||||
class manifest
|
||||
{
|
||||
IAppxManifestReader *appx = nullptr;
|
||||
IAppxBundleManifestReader *bundle = nullptr;
|
||||
public:
|
||||
~manifest () { destroy (); }
|
||||
manifest (const std::wstring &filepath = L"") { create (filepath); }
|
||||
void destroy ()
|
||||
{
|
||||
if (appx) { appx->Release (); appx = nullptr; }
|
||||
if (bundle) { bundle->Release (); bundle = nullptr; }
|
||||
}
|
||||
bool create (const std::wstring &filepath)
|
||||
{
|
||||
destroy ();
|
||||
if (!IsFileExists (filepath)) return false;
|
||||
HRESULT hr = GetBundleManifestReader (filepath.c_str (), &bundle);
|
||||
if (SUCCEEDED (hr)) return true;
|
||||
if (bundle) { bundle->Release (); bundle = nullptr; }
|
||||
hr = GetAppxManifestReader (filepath.c_str (), &appx);
|
||||
if (SUCCEEDED (hr)) return true;
|
||||
if (appx) { appx->Release (); appx = nullptr; }
|
||||
return false;
|
||||
}
|
||||
bool valid () const { return (bool)appx ^ (bool)bundle; }
|
||||
PackageType type () const
|
||||
{
|
||||
if (appx) return PackageType::single;
|
||||
if (bundle) return PackageType::bundle;
|
||||
return PackageType::unknown;
|
||||
}
|
||||
appxmanifest appx_reader () const { return appxmanifest (*(IAppxManifestReader **)&this->appx); }
|
||||
bundlemanifest bundle_reader () const { return bundlemanifest (*(IAppxBundleManifestReader **)&this->bundle); }
|
||||
};
|
||||
Reference in New Issue
Block a user