mirror of
https://github.com/modernw/App-Installer-For-Windows-8.x-Reset.git
synced 2026-04-11 17:57:19 +10:00
1159 lines
43 KiB
C++
1159 lines
43 KiB
C++
#pragma once
|
|
#include <map>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <Shlwapi.h>
|
|
#include <AppxPackaging.h>
|
|
#include <strsafe.h>
|
|
#include <sstream>
|
|
#include <atlbase.h>
|
|
#include <functional>
|
|
#include <utility>
|
|
#include "dynarr.h"
|
|
#include "version.h"
|
|
#include "stringres.h"
|
|
#include "norstr.h"
|
|
#include "raii.h"
|
|
|
|
bool IsFileExistsW (LPCWSTR filename)
|
|
{
|
|
DWORD dwAttrib = GetFileAttributesW (filename);
|
|
return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
|
}
|
|
bool IsFileExistsA (LPCSTR filename)
|
|
{
|
|
DWORD dwAttrib = GetFileAttributesA (filename);
|
|
return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
|
}
|
|
bool IsFileExists (LPWSTR filePath) { return IsFileExistsW (filePath); }
|
|
bool IsFileExists (LPCSTR filePath) { return IsFileExistsA (filePath); }
|
|
bool IsFileExists (std::string filePath) { return IsFileExistsA (filePath.c_str ()); }
|
|
bool IsFileExists (std::wstring filePath) { return IsFileExistsW (filePath.c_str ()); }
|
|
|
|
HRESULT GetBundleReader (_In_ LPCWSTR inputFileName, _Outptr_ IAppxBundleReader** bundleReader)
|
|
{
|
|
if (bundleReader == NULL) return E_POINTER;
|
|
*bundleReader = NULL;
|
|
HRESULT hr = S_OK;
|
|
CComPtr <IAppxBundleFactory> appxBundleFactory;
|
|
CComPtr <IStream> inputStream;
|
|
hr = CoCreateInstance (__uuidof(AppxBundleFactory), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS (&appxBundleFactory));
|
|
if (FAILED (hr)) return hr;
|
|
hr = SHCreateStreamOnFileEx (inputFileName, STGM_READ | STGM_SHARE_DENY_NONE, 0, FALSE, NULL, &inputStream);
|
|
if (FAILED (hr)) return hr;
|
|
hr = appxBundleFactory->CreateBundleReader (inputStream, bundleReader);
|
|
return hr;
|
|
}
|
|
HRESULT GetPackageReader (_In_ LPCWSTR inputFileName, _Outptr_ IAppxPackageReader **reader)
|
|
{
|
|
if (reader == NULL) return E_POINTER;
|
|
*reader = NULL;
|
|
HRESULT hr = S_OK;
|
|
CComPtr <IAppxFactory> appxFactory;
|
|
CComPtr <IStream> inputStream;
|
|
hr = CoCreateInstance (__uuidof(AppxFactory), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS (&appxFactory));
|
|
if (FAILED (hr)) return hr;
|
|
hr = SHCreateStreamOnFileEx (inputFileName, STGM_READ | STGM_SHARE_DENY_NONE, 0, FALSE, NULL, &inputStream);
|
|
if (FAILED (hr)) return hr;
|
|
hr = appxFactory->CreatePackageReader (inputStream, reader);
|
|
return hr;
|
|
}
|
|
HRESULT GetAppxPackageReader (_In_ IStream *inputStream, _Outptr_ IAppxPackageReader **packageReader)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComPtr <IAppxFactory> appxFactory = NULL;
|
|
hr = CoCreateInstance (__uuidof (AppxFactory), NULL, CLSCTX_INPROC_SERVER, __uuidof (IAppxFactory), (LPVOID *)(&appxFactory));
|
|
if (SUCCEEDED (hr)) hr = appxFactory->CreatePackageReader (inputStream, packageReader);
|
|
return hr;
|
|
}
|
|
HRESULT GetAppxManifestReader2 (IAppxManifestReader *m, IAppxManifestReader2 **m2)
|
|
{
|
|
if (!m | !m2) return E_FAIL;
|
|
return m->QueryInterface (__uuidof (IAppxManifestReader2), (void **)m2);
|
|
}
|
|
|
|
class app_info: public std::map <std::wnstring, std::wstring>
|
|
{
|
|
using Base = std::map <std::wnstring, std::wstring>;
|
|
public:
|
|
using Base::Base;
|
|
std::wstring user_model_id () const { return this->find (L"AppUserModelID")->second; }
|
|
friend bool operator == (const app_info &a1, const app_info &a2) { return std::wnstring (a1.user_model_id ()) == std::wnstring (a2.user_model_id ()); }
|
|
friend bool operator != (const app_info &a1, const app_info &a2) { return std::wnstring (a1.user_model_id ()) != std::wnstring (a2.user_model_id ()); }
|
|
explicit operator bool () const { return std::wnstring::to_nstring (this->user_model_id ()).empty (); }
|
|
};
|
|
|
|
class dep_info
|
|
{
|
|
public:
|
|
std::wstring name = L"";
|
|
std::wstring publisher = L"";
|
|
version minversion;
|
|
dep_info (const std::wstring &name, const std::wstring &publisher, version versionLimit):
|
|
name (std::wnstring::trim (name)), publisher (std::wnstring::trim (publisher)), minversion (versionLimit) {}
|
|
dep_info (IAppxManifestPackageDependency *&dependency)
|
|
{
|
|
LPWSTR lpName = nullptr, lpPublisher = nullptr;
|
|
UINT64 u64Ver = 0;
|
|
raii rel ([&lpName, &lpPublisher] () -> void {
|
|
if (lpName) CoTaskMemFree (lpName);
|
|
if (lpPublisher) CoTaskMemFree (lpPublisher);
|
|
});
|
|
if (SUCCEEDED (dependency->GetName (&lpName)) && lpName) name += lpName;
|
|
if (SUCCEEDED (dependency->GetPublisher (&lpPublisher)) && lpPublisher) publisher += lpPublisher;
|
|
if (SUCCEEDED (dependency->GetMinVersion (&u64Ver))) minversion = u64Ver;
|
|
}
|
|
dep_info () {}
|
|
bool operator == (const dep_info &another) { return std::wnstring (this->name) == std::wnstring (another.name); }
|
|
bool empty () { return std::wnstring (name).empty (); }
|
|
};
|
|
|
|
template <typename GetType, typename RetType = GetType> RetType process_default (GetType &g)
|
|
{
|
|
return RetType (g);
|
|
}
|
|
template <typename EnumerationType, typename GetType, typename RetType = GetType, typename RetVectorType = std::vector <RetType>>
|
|
size_t EnumerateComInterface (EnumerationType *iEnum, RetVectorType &retarr, std::function <RetType (GetType &)> process = process_default <GetType, RetType>)
|
|
{
|
|
BOOL hasCurrent;
|
|
HRESULT hr = iEnum->GetHasCurrent (&hasCurrent);
|
|
if (SUCCEEDED (hr) && hasCurrent) retarr.reserve (8);
|
|
while (SUCCEEDED (hr) && hasCurrent)
|
|
{
|
|
GetType value;
|
|
hr = iEnum->GetCurrent (&value);
|
|
if (SUCCEEDED (hr))
|
|
{
|
|
try
|
|
{
|
|
push_normal (retarr, process (value));
|
|
}
|
|
catch (const std::exception &e) {}
|
|
}
|
|
hr = iEnum->MoveNext (&hasCurrent);
|
|
}
|
|
return retarr.size ();
|
|
}
|
|
template <typename T> bool is_data_valid_default (T &data) { return true; }
|
|
|
|
enum class PackageType: UINT8
|
|
{
|
|
unknown = 0, // 未知,也是无效包
|
|
single = 1, // Appx 包
|
|
bundle = 2 // AppxBundle 包
|
|
};
|
|
enum class PackageRole: UINT8
|
|
{
|
|
unknown = 0, // 未知
|
|
application = 1, // 应用包,安装后是为可以运行的包
|
|
framework = 2, // 框架包(依赖项),安装后可为其他人
|
|
resource = 3 // 资源包,为应用包提供语言等资源
|
|
};
|
|
template <typename ComInterface> class com_info
|
|
{
|
|
private:
|
|
CComPtr <ComInterface> icom = nullptr;
|
|
protected:
|
|
ComInterface *pointer () const noexcept { return icom; }
|
|
void attach (ComInterface *ptr) { icom.Attach (ptr); }
|
|
void set (ComInterface *ptr) { icom = ptr; }
|
|
template <typename Fn> std::wstring get (_In_ Fn func) const
|
|
{
|
|
if (!icom) return L"";
|
|
LPWSTR lpstr = nullptr;
|
|
raii task ([&lpstr] () {
|
|
if (lpstr) CoTaskMemFree (lpstr);
|
|
lpstr = nullptr;
|
|
});
|
|
return (SUCCEEDED ((icom->*func)(&lpstr)) && lpstr) ? std::wstring (lpstr) : L"";
|
|
}
|
|
template <typename GetType, typename RetType = GetType, typename Fn> RetType get (_In_ Fn func, _In_ std::function <RetType (GetType &)> process = process_default <GetType, RetType>) const
|
|
{
|
|
if (!icom) return RetType ();
|
|
GetType value {};
|
|
if (SUCCEEDED ((icom->*func) (&value))) return process (value);
|
|
else return RetType ();
|
|
}
|
|
template <typename EnumInterfaceType, typename Fn> size_t enumerate (_In_ Fn func, _Out_ std::vector <std::wstring> &output) const
|
|
{
|
|
output.clear ();
|
|
if (!icom) return 0;
|
|
CComPtr <EnumInterfaceType> ienum;
|
|
if (FAILED ((icom->*func) (&ienum))) return 0;
|
|
return EnumerateComInterface <EnumInterfaceType, LPWSTR, std::wstring> (ienum, output, [] (LPWSTR &lpstr) -> std::wstring {
|
|
raii reltask ([&lpstr] () { if (lpstr) { CoTaskMemFree (lpstr); lpstr = nullptr; } });
|
|
return std::wstring (lpstr ? lpstr : L"");
|
|
});
|
|
}
|
|
template <typename EnumInterfaceType, typename GetType, typename RetType = GetType, typename RetVectorType = std::vector <RetType>, typename Fn> size_t enumerate (_In_ Fn func, _Out_ RetVectorType &output, _In_ std::function <RetType (GetType &)> process = process_default <GetType, RetType>) const
|
|
{
|
|
output.clear ();
|
|
if (!icom) return 0;
|
|
CComPtr <EnumInterfaceType> ienum;
|
|
if (FAILED (icom->*func (&ienum)) || !ienum) return 0;
|
|
return EnumerateComInterface <EnumInterfaceType, GetType, RetType, RetVectorType> (ienum, output, process);
|
|
}
|
|
public:
|
|
using Interface = ComInterface;
|
|
explicit com_info (ComInterface *ptr) { icom.Attach (ptr); }
|
|
com_info (const com_info &) = delete;
|
|
com_info &operator = (const com_info &) = delete;
|
|
com_info (com_info &&) noexcept = default;
|
|
com_info &operator = (com_info &&) noexcept = default;
|
|
bool valid () const { return !!icom; }
|
|
};
|
|
template <typename ComInterface> class com_info_quote
|
|
{
|
|
using IComInterface = ComInterface *;
|
|
private:
|
|
IComInterface &icom = nullptr;
|
|
protected:
|
|
ComInterface *pointer () const noexcept { return icom; }
|
|
template <typename Fn> std::wstring get (_In_ Fn func) const
|
|
{
|
|
if (!icom) return L"";
|
|
LPWSTR lpstr = nullptr;
|
|
raii task ([&lpstr] () {
|
|
if (lpstr) CoTaskMemFree (lpstr);
|
|
lpstr = nullptr;
|
|
});
|
|
return (SUCCEEDED ((icom->*func)(&lpstr)) && lpstr) ? std::wstring (lpstr) : L"";
|
|
}
|
|
template <typename GetType, typename RetType = GetType, typename Fn> RetType get (_In_ Fn func, _In_ std::function <RetType (GetType &)> process = process_default <GetType, RetType>) const
|
|
{
|
|
if (!icom) return RetType ();
|
|
GetType value {};
|
|
if (SUCCEEDED ((icom->*func) (&value))) return process (value);
|
|
else return RetType ();
|
|
}
|
|
template <typename EnumInterfaceType, typename Fn> size_t enumerate (_In_ Fn func, _Out_ std::vector <std::wstring> &output) const
|
|
{
|
|
output.clear ();
|
|
if (!icom) return 0;
|
|
CComPtr <EnumInterfaceType> ienum;
|
|
if (FAILED ((icom->*func) (&ienum))) return 0;
|
|
return EnumerateComInterface <EnumInterfaceType, LPWSTR, std::wstring> (ienum, output, [] (LPWSTR &lpstr) -> std::wstring {
|
|
raii reltask ([&lpstr] () { if (lpstr) { CoTaskMemFree (lpstr); lpstr = nullptr; } });
|
|
return std::wstring (lpstr ? lpstr : L"");
|
|
});
|
|
}
|
|
template <typename EnumInterfaceType, typename GetType, typename RetType = GetType, typename RetVectorType = std::vector <RetType>, typename Fn> size_t enumerate (_In_ Fn func, _Out_ RetVectorType &output, _In_ std::function <RetType (GetType &)> process = process_default <GetType, RetType>) const
|
|
{
|
|
output.clear ();
|
|
if (!icom) return 0;
|
|
CComPtr <EnumInterfaceType> ienum;
|
|
if (FAILED (icom->*func (&ienum)) || !ienum) return 0;
|
|
return EnumerateComInterface <EnumInterfaceType, GetType, RetType, RetVectorType> (ienum, output, process);
|
|
}
|
|
public:
|
|
using Interface = ComInterface;
|
|
explicit com_info_quote (IComInterface &ptr): icom (ptr) {}
|
|
com_info_quote (const com_info_quote &) = delete;
|
|
com_info_quote &operator = (const com_info_quote &) = delete;
|
|
com_info_quote (com_info_quote &&) noexcept = default;
|
|
com_info_quote &operator = (com_info_quote &&) noexcept = default;
|
|
bool valid () const { return !!icom; }
|
|
};
|
|
namespace appx_info
|
|
{
|
|
class appx_id: virtual public com_info <IAppxManifestPackageId>
|
|
{
|
|
using Base = com_info <IAppxManifestPackageId>;
|
|
public:
|
|
using Base::Base;
|
|
std::wstring name () const { return get (&Interface::GetName); }
|
|
std::wstring publisher () const { return get (&Interface::GetPublisher); }
|
|
std::wstring package_family_name () const { return get (&Interface::GetPackageFamilyName); }
|
|
std::wstring package_full_name () const { return get (&Interface::GetPackageFullName); }
|
|
std::wstring resource_id () const { return get (&Interface::GetResourceId); }
|
|
version version () const { return get <UINT64, Version> (&Interface::GetVersion); }
|
|
APPX_PACKAGE_ARCHITECTURE architecture () const { return get <APPX_PACKAGE_ARCHITECTURE> (&Interface::GetArchitecture); }
|
|
bool publisher_compare (const std::wstring &another) const
|
|
{
|
|
BOOL ret = FALSE;
|
|
return (SUCCEEDED (pointer ()->ComparePublisher (another.c_str (), &ret)) ? ret != FALSE : false);
|
|
}
|
|
};
|
|
class appx_qres: virtual public com_info <IAppxManifestQualifiedResourcesEnumerator>
|
|
{
|
|
using Base = com_info <IAppxManifestQualifiedResourcesEnumerator>;
|
|
public:
|
|
using Base::Base;
|
|
size_t enumerate (_In_ std::function <void (IAppxManifestQualifiedResource *)> callback) const
|
|
{
|
|
size_t cnt = 0;
|
|
BOOL hasCurrent = FALSE;
|
|
HRESULT hr = pointer ()->GetHasCurrent (&hasCurrent);
|
|
while (SUCCEEDED (hr) && hasCurrent)
|
|
{
|
|
CComPtr <IAppxManifestQualifiedResource> qres;
|
|
hr = pointer ()->GetCurrent (&qres);
|
|
if (SUCCEEDED (hr))
|
|
{
|
|
cnt ++;
|
|
callback (qres);
|
|
}
|
|
hr = pointer ()->MoveNext (&hasCurrent);
|
|
}
|
|
return cnt;
|
|
}
|
|
size_t qualified_resources (
|
|
_Out_ std::vector <std::wstring> *languages = nullptr,
|
|
_Out_ std::vector <UINT32> *scales = nullptr,
|
|
_Out_ std::vector <DX_FEATURE_LEVEL> *dxlevels = nullptr
|
|
) const
|
|
{
|
|
if (languages) languages->clear ();
|
|
if (scales) scales->clear ();
|
|
if (dxlevels) dxlevels->clear ();
|
|
return enumerate ([&languages, &scales, &dxlevels] (IAppxManifestQualifiedResource *qr) {
|
|
LPWSTR lpstr = nullptr;
|
|
raii endt ([&lpstr] () {
|
|
if (lpstr) CoTaskMemFree (lpstr);
|
|
lpstr = nullptr;
|
|
});
|
|
UINT32 u32 = 0;
|
|
DX_FEATURE_LEVEL dx = DX_FEATURE_LEVEL::DX_FEATURE_LEVEL_UNSPECIFIED;
|
|
if (SUCCEEDED (qr->GetLanguage (&lpstr)) && lpstr && languages) languages->push_back (lpstr);
|
|
else if (SUCCEEDED (qr->GetScale (&u32)) && u32 && scales) scales->push_back (u32);
|
|
else if (SUCCEEDED (qr->GetDXFeatureLevel (&dx)) && dx != DX_FEATURE_LEVEL::DX_FEATURE_LEVEL_UNSPECIFIED && dxlevels) dxlevels->push_back (dx);
|
|
});
|
|
}
|
|
size_t languages (_Out_ std::vector <std::wstring> &languages) const { return qualified_resources (&languages); }
|
|
size_t languages (_Out_ std::vector <std::wnstring> &output) const
|
|
{
|
|
output.clear ();
|
|
BOOL hasCurrent = false;
|
|
HRESULT hr = pointer ()->GetHasCurrent (&hasCurrent);
|
|
while (SUCCEEDED (hr) && hasCurrent)
|
|
{
|
|
CComPtr <IAppxManifestQualifiedResource> qr;
|
|
hr = pointer ()->GetCurrent (&qr);
|
|
if (SUCCEEDED (hr))
|
|
{
|
|
LPWSTR lpstr = nullptr;
|
|
raii endt ([&lpstr] () {
|
|
if (lpstr) CoTaskMemFree (lpstr);
|
|
lpstr = nullptr;
|
|
});
|
|
hr = qr->GetLanguage (&lpstr);
|
|
if (SUCCEEDED (hr) && lpstr) push_unique (output, std::wnstring (lpstr));
|
|
}
|
|
hr = pointer ()->MoveNext (&hasCurrent);
|
|
}
|
|
return output.size ();
|
|
}
|
|
size_t scales (_Out_ std::vector <UINT32> &scales) const { return qualified_resources (nullptr, &scales); }
|
|
size_t dx_feature_level (_Out_ std::vector <DX_FEATURE_LEVEL> &dxlevels) const { return qualified_resources (nullptr, nullptr, &dxlevels); }
|
|
};
|
|
class appx_res: virtual public com_info <IAppxManifestReader>
|
|
{
|
|
using Base = com_info <IAppxManifestReader>;
|
|
public:
|
|
using Base::Base;
|
|
appx_res (IAppxManifestReader *ptr = nullptr): com_info (nullptr) { set (ptr); }
|
|
size_t languages (_Out_ std::vector <std::wstring> &output) const
|
|
{
|
|
output.clear ();
|
|
return enumerate <IAppxManifestResourcesEnumerator> (&Interface::GetResources, output);
|
|
}
|
|
size_t languages (_Out_ std::vector <std::wnstring> &output) const
|
|
{
|
|
output.clear ();
|
|
BOOL hasCurrent = false;
|
|
CComPtr <IAppxManifestResourcesEnumerator> re;
|
|
HRESULT hr = pointer ()->GetResources (&re);
|
|
if (FAILED (hr)) return false;
|
|
hr = re->GetHasCurrent (&hasCurrent);
|
|
while (SUCCEEDED (hr) && hasCurrent)
|
|
{
|
|
LPWSTR lpstr = nullptr;
|
|
raii endt ([&lpstr] () {
|
|
if (lpstr) CoTaskMemFree (lpstr);
|
|
lpstr = nullptr;
|
|
});
|
|
hr = re->GetCurrent (&lpstr);
|
|
if (SUCCEEDED (hr) && lpstr)
|
|
{
|
|
push_unique (output, std::wnstring (lpstr));
|
|
}
|
|
hr = re->MoveNext (&hasCurrent);
|
|
}
|
|
return output.size ();
|
|
}
|
|
size_t scales (_Out_ std::vector <UINT32> &scales) const
|
|
{
|
|
return qualified_resources <UINT32> (&IAppxManifestQualifiedResource::GetScale, scales, [] (UINT32 &v) -> bool {
|
|
return v != 0;
|
|
});
|
|
}
|
|
size_t dx_feature_level (_Out_ std::vector <DX_FEATURE_LEVEL> &dxlevels) const
|
|
{
|
|
return qualified_resources <DX_FEATURE_LEVEL> (&IAppxManifestQualifiedResource::GetDXFeatureLevel, dxlevels, [] (DX_FEATURE_LEVEL &v) -> bool {
|
|
return v != DX_FEATURE_LEVEL::DX_FEATURE_LEVEL_UNSPECIFIED;
|
|
});
|
|
}
|
|
appx_qres to_qualified_resources () const
|
|
{
|
|
CComPtr <IAppxManifestReader2> m2;
|
|
IAppxManifestQualifiedResourcesEnumerator *ip = nullptr;
|
|
if (SUCCEEDED (GetAppxManifestReader2 (pointer (), &m2))) m2->GetQualifiedResources (&ip);
|
|
return appx_qres (ip);
|
|
}
|
|
private:
|
|
template <typename GetValue, typename RetValue = GetValue, typename Fn, typename Vector = std::vector <RetValue>>
|
|
size_t qualified_resources (_In_ Fn func, _Out_ Vector &output, _In_ std::function <bool (GetValue &)> valid = is_data_valid_default <GetValue>, _In_ std::function <RetValue (GetValue &)> process = process_default <GetValue, RetValue>) const
|
|
{
|
|
output.clear ();
|
|
CComPtr <IAppxManifestReader2> m2;
|
|
if (FAILED (GetAppxManifestReader2 (pointer (), &m2))) return 0;
|
|
CComPtr <IAppxManifestQualifiedResourcesEnumerator> e;
|
|
if (FAILED (m2->GetQualifiedResources (&e))) return 0;
|
|
BOOL hasCurrent = false;
|
|
HRESULT hr = e->GetHasCurrent (&hasCurrent);
|
|
while (SUCCEEDED (hr) && hasCurrent)
|
|
{
|
|
CComPtr <IAppxManifestQualifiedResource> res;
|
|
if (SUCCEEDED (e->GetCurrent (&res)))
|
|
{
|
|
GetValue value;
|
|
hr = (res->*func) (&value);
|
|
if (SUCCEEDED (hr) && valid (value))
|
|
{
|
|
output.push_back (process (value));
|
|
}
|
|
}
|
|
hr = e->MoveNext (&hasCurrent);
|
|
}
|
|
return output.size ();
|
|
}
|
|
size_t qualified_resources (_Out_ std::vector <std::wstring> &languages, _Out_ std::vector <UINT32> &scales, _Out_ std::vector <DX_FEATURE_LEVEL> &dxlevels)
|
|
{
|
|
languages.clear ();
|
|
scales.clear ();
|
|
dxlevels.clear ();
|
|
size_t cnt = 0;
|
|
CComPtr <IAppxManifestReader2> m2;
|
|
if (FAILED (GetAppxManifestReader2 (pointer (), &m2))) return 0;
|
|
CComPtr <IAppxManifestQualifiedResourcesEnumerator> e;
|
|
if (FAILED (m2->GetQualifiedResources (&e))) return 0;
|
|
BOOL hasCurrent = false;
|
|
HRESULT hr = e->GetHasCurrent (&hasCurrent);
|
|
while (SUCCEEDED (hr) && hasCurrent)
|
|
{
|
|
CComPtr <IAppxManifestQualifiedResource> res;
|
|
if (SUCCEEDED (e->GetCurrent (&res)))
|
|
{
|
|
LPWSTR lpstr = nullptr;
|
|
raii endt ([&lpstr] () {
|
|
if (lpstr) CoTaskMemFree (lpstr);
|
|
lpstr = nullptr;
|
|
});
|
|
UINT32 scale = 0;
|
|
DX_FEATURE_LEVEL dx = DX_FEATURE_LEVEL::DX_FEATURE_LEVEL_UNSPECIFIED;
|
|
if (SUCCEEDED (res->GetLanguage (&lpstr)) && lpstr)
|
|
{
|
|
push_unique <std::wstring> (languages, std::wstring (lpstr), [] (const std::wstring &v1, const std::wstring &v2) -> bool {
|
|
return std::wnstring (v1) == std::wnstring (v2);
|
|
});
|
|
}
|
|
if (SUCCEEDED (res->GetScale (&scale)) && scale)
|
|
{
|
|
push_unique (scales, scale);
|
|
}
|
|
if (SUCCEEDED (res->GetDXFeatureLevel (&dx)) && dx != DX_FEATURE_LEVEL::DX_FEATURE_LEVEL_UNSPECIFIED)
|
|
{
|
|
push_unique (dxlevels, dx);
|
|
}
|
|
cnt ++;
|
|
}
|
|
hr = e->MoveNext (&hasCurrent);
|
|
}
|
|
return cnt;
|
|
}
|
|
};
|
|
class appx_prop: virtual public com_info <IAppxManifestProperties>
|
|
{
|
|
using Base = com_info <IAppxManifestProperties>;
|
|
public:
|
|
using Base::Base;
|
|
std::wstring string_value (const std::wstring &name) const
|
|
{
|
|
LPWSTR lpstr = nullptr;
|
|
raii endt ([&lpstr] () {
|
|
if (lpstr) CoTaskMemFree (lpstr);
|
|
lpstr = nullptr;
|
|
});
|
|
HRESULT hr = pointer ()->GetStringValue (name.c_str (), &lpstr);
|
|
if (SUCCEEDED (hr) && lpstr) return std::wstring () + lpstr;
|
|
return L"";
|
|
}
|
|
bool bool_value (const std::wstring &name) const
|
|
{
|
|
BOOL boolvalue = FALSE;
|
|
HRESULT hr = pointer ()->GetBoolValue (name.c_str (), &boolvalue);
|
|
if (SUCCEEDED (hr)) return boolvalue != FALSE;
|
|
return FALSE;
|
|
}
|
|
std::wstring display_name () const { return string_value (L"DisplayName"); }
|
|
std::wstring description () const { return string_value (L"Description"); }
|
|
std::wstring publisher () const { return string_value (L"PublisherDisplayName"); }
|
|
std::wstring logo () const { return string_value (L"Logo"); }
|
|
// 判断这个包是否为依赖项(框架包/运行库)
|
|
bool framework () const { return bool_value (L"Framework"); }
|
|
// 判断这个包是否为资源包
|
|
bool resource_package () const { return bool_value (L"ResourcePackage"); }
|
|
};
|
|
class appx_preq: virtual public com_info <IAppxManifestReader>
|
|
{
|
|
using Base = com_info <IAppxManifestReader>;
|
|
public:
|
|
using Base::Base;
|
|
appx_preq (IAppxManifestReader *ptr = nullptr): com_info (nullptr) { set (ptr); }
|
|
version os_min_version () const { return get_version (L"OSMinVersion"); }
|
|
version os_max_version_tested () const { return get_version (L"OSMaxVersionTested"); }
|
|
version get_version (const std::wstring &name) const
|
|
{
|
|
UINT64 u64 = 0;
|
|
if (SUCCEEDED (pointer ()->GetPrerequisite (name.c_str (), &u64))) return version (u64);
|
|
return version ();
|
|
}
|
|
};
|
|
class appx_apps: virtual public com_info <IAppxManifestApplicationsEnumerator>
|
|
{
|
|
using Base = com_info <IAppxManifestApplicationsEnumerator>;
|
|
public:
|
|
using Base::Base;
|
|
size_t applications (_Out_ std::vector <app_info> &output) const
|
|
{
|
|
return EnumerateComInterface <IAppxManifestApplicationsEnumerator, IAppxManifestApplication *, app_info> (pointer (), output, [] (IAppxManifestApplication *&p) -> app_info {
|
|
raii rel ([&p] () {
|
|
if (p) p->Release ();
|
|
p = nullptr;
|
|
});
|
|
app_info app;
|
|
LPWSTR userid;
|
|
{
|
|
raii endt ([&userid] () {
|
|
if (userid) CoTaskMemFree (userid);
|
|
userid = nullptr;
|
|
});
|
|
if (SUCCEEDED (p->GetAppUserModelId (&userid)))
|
|
{
|
|
app [L"AppUserModelID"] = userid;
|
|
}
|
|
}
|
|
for (auto &it : GetApplicationAttributeItems ())
|
|
{
|
|
LPWSTR lpstr;
|
|
raii endt1 ([&lpstr] () {
|
|
if (lpstr) CoTaskMemFree (lpstr);
|
|
lpstr = nullptr;
|
|
});
|
|
if (std::wnstring (it) == std::wnstring (L"AppUserModelID")) continue;
|
|
if (SUCCEEDED (p->GetStringValue (it.c_str (), &lpstr)) && lpstr)
|
|
app [it] = lpstr;
|
|
else app [it] = std::wstring ();
|
|
}
|
|
return app;
|
|
});
|
|
}
|
|
size_t app_user_model_ids (_Out_ std::vector <std::wstring> &output) const
|
|
{
|
|
return EnumerateComInterface <IAppxManifestApplicationsEnumerator, IAppxManifestApplication *, std::wstring> (pointer (), output, [] (IAppxManifestApplication *&p) -> std::wstring {
|
|
raii rel ([&p] () {
|
|
if (p) p->Release ();
|
|
p = nullptr;
|
|
});
|
|
LPWSTR userid;
|
|
raii endt ([&userid] () {
|
|
if (userid) CoTaskMemFree (userid);
|
|
userid = nullptr;
|
|
});
|
|
if (SUCCEEDED (p->GetAppUserModelId (&userid))) return userid;
|
|
else return L"";
|
|
});
|
|
}
|
|
size_t string_values (_In_ const std::wstring &name, _Out_ std::vector <std::wstring> &output) const
|
|
{
|
|
return EnumerateComInterface <IAppxManifestApplicationsEnumerator, IAppxManifestApplication *, std::wstring> (pointer (), output, [&name] (IAppxManifestApplication *&p) -> std::wstring {
|
|
raii rel ([&p] () {
|
|
if (p) p->Release ();
|
|
p = nullptr;
|
|
});
|
|
LPWSTR str = nullptr;
|
|
raii endt ([&str] () {
|
|
if (str) CoTaskMemFree (str);
|
|
str = nullptr;
|
|
});
|
|
if (SUCCEEDED (p->GetStringValue (name.c_str (), &str))) return std::wstring (str);
|
|
else return L"";
|
|
});
|
|
}
|
|
size_t id_s (_Out_ std::vector <std::wstring> &output) const { return string_values (L"Id", output); }
|
|
size_t visualelements_displaynames (_Out_ std::vector <std::wstring> &output) const { return string_values (L"DisplayName", output); }
|
|
size_t visualelements_backgroundcolors (_Out_ std::vector <std::wstring> &output) const { return string_values (L"BackgroundColor", output); }
|
|
size_t visualelements_foregroundcolors (_Out_ std::vector <std::wstring> &output) const { return string_values (L"ForegroundText", output); }
|
|
size_t visualelements_shortnames (_Out_ std::vector <std::wstring> &output) const { return string_values (L"ShortName", output); }
|
|
size_t visualelements_44x44logos (_Out_ std::vector <std::wstring> &output) const { return string_values (L"Square44x44Logo", output); }
|
|
size_t size () const
|
|
{
|
|
size_t cnt = 0;
|
|
BOOL hasCurrent = FALSE;
|
|
HRESULT hr = pointer ()->GetHasCurrent (&hasCurrent);
|
|
while (SUCCEEDED (hr) && hasCurrent)
|
|
{
|
|
hr = pointer ()->GetHasCurrent (&hasCurrent);
|
|
if (SUCCEEDED (hr) && hasCurrent) cnt ++;
|
|
hr = pointer ()->MoveNext (&hasCurrent);
|
|
}
|
|
return cnt;
|
|
}
|
|
};
|
|
class appx_capabs: virtual public com_info <IAppxManifestDeviceCapabilitiesEnumerator>
|
|
{
|
|
using Base = com_info <IAppxManifestDeviceCapabilitiesEnumerator>;
|
|
APPX_CAPABILITIES cflags;
|
|
public:
|
|
using Base::Base;
|
|
appx_capabs (IAppxManifestDeviceCapabilitiesEnumerator *devicec, APPX_CAPABILITIES capa): cflags (capa), com_info (devicec) {}
|
|
appx_capabs () = default;
|
|
APPX_CAPABILITIES capabilities () const { return cflags; }
|
|
size_t device_capabilities (_Out_ std::vector <std::wstring> &output) const
|
|
{
|
|
return EnumerateComInterface <IAppxManifestDeviceCapabilitiesEnumerator, LPWSTR, std::wstring> (pointer (), output, [] (LPWSTR &lp) {
|
|
raii ([&lp] () {
|
|
if (lp) CoTaskMemFree (lp);
|
|
lp = nullptr;
|
|
});
|
|
return lp ? lp : L"";
|
|
});
|
|
}
|
|
// 从功能按位数据转换到功能名。
|
|
size_t capabilities_names (_Out_ std::vector <std::wstring> &output) const
|
|
{
|
|
output.clear ();
|
|
CapabilitiesFlagsToNames (cflags, output);
|
|
return output.size ();
|
|
}
|
|
// 获取功能和设备功能的所有功能名
|
|
size_t all_capabilities (_Out_ std::vector <std::wstring> &output) const
|
|
{
|
|
output.clear ();
|
|
std::vector <std::wstring> devs;
|
|
device_capabilities (devs);
|
|
capabilities_names (output);
|
|
for (auto &it : devs) push_unique (output, it);
|
|
return output.size ();
|
|
}
|
|
};
|
|
class appx_deps: virtual public com_info <IAppxManifestPackageDependenciesEnumerator>
|
|
{
|
|
using Base = com_info <IAppxManifestPackageDependenciesEnumerator>;
|
|
public:
|
|
using Base::Base;
|
|
size_t dependencies (_Out_ std::vector <dep_info> &output) const
|
|
{
|
|
return EnumerateComInterface <IAppxManifestPackageDependenciesEnumerator, IAppxManifestPackageDependency *, dep_info> (pointer (), output, [] (IAppxManifestPackageDependency *&ptr) -> dep_info {
|
|
raii endt ([&ptr] () {
|
|
if (ptr) ptr->Release ();
|
|
ptr = nullptr;
|
|
});
|
|
dep_info dep (ptr);
|
|
return dep;
|
|
});
|
|
}
|
|
size_t size () const
|
|
{
|
|
size_t cnt = 0;
|
|
BOOL hasCurrent = FALSE;
|
|
HRESULT hr = pointer ()->GetHasCurrent (&hasCurrent);
|
|
while (SUCCEEDED (hr) && hasCurrent)
|
|
{
|
|
hr = pointer ()->GetHasCurrent (&hasCurrent);
|
|
if (SUCCEEDED (hr) && hasCurrent) cnt ++;
|
|
hr = pointer ()->MoveNext (&hasCurrent);
|
|
}
|
|
return cnt;
|
|
}
|
|
};
|
|
class appx_iditem: virtual public com_info <IAppxBundleManifestPackageInfo>
|
|
{
|
|
using Base = com_info <IAppxBundleManifestPackageInfo>;
|
|
public:
|
|
using Base::Base;
|
|
appx_iditem (IAppxBundleManifestPackageInfo *ptr): com_info (nullptr) { set (ptr); }
|
|
std::wstring file_name () const { return get (&Interface::GetFileName); }
|
|
UINT64 offset () const { return get <UINT64> (&Interface::GetOffset); }
|
|
HRESULT get_identity (_Outptr_ IAppxManifestPackageId **output) const { return pointer ()->GetPackageId (output); }
|
|
appx_id identity () const
|
|
{
|
|
IAppxManifestPackageId *ip = nullptr;
|
|
HRESULT hr = get_identity (&ip);
|
|
return appx_id (ip);
|
|
}
|
|
APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE type () const { return get <APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE> (&Interface::GetPackageType); }
|
|
HRESULT get_qualified_resources (_Outptr_ IAppxManifestQualifiedResourcesEnumerator **output) const { return pointer ()->GetResources (output); }
|
|
appx_qres qualified_resources () const
|
|
{
|
|
IAppxManifestQualifiedResourcesEnumerator *ip = nullptr;
|
|
get_qualified_resources (&ip);
|
|
return appx_qres (ip);
|
|
}
|
|
UINT64 size () const { return get <UINT64> (&Interface::GetSize); }
|
|
};
|
|
class appx_iditems: virtual public com_info <IAppxBundleManifestPackageInfoEnumerator>
|
|
{
|
|
using Base = com_info <IAppxBundleManifestPackageInfoEnumerator>;
|
|
public:
|
|
using Base::Base;
|
|
size_t enumerate (_In_ std::function <void (IAppxBundleManifestPackageInfo *)> callback, APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE enumtype = (APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE)-1) const
|
|
{
|
|
BOOL hasCurrent = FALSE;
|
|
HRESULT hr = pointer ()->GetHasCurrent (&hasCurrent);
|
|
size_t cnt = 0;
|
|
while (SUCCEEDED (hr) && hasCurrent)
|
|
{
|
|
CComPtr <IAppxBundleManifestPackageInfo> item;
|
|
hr = pointer ()->GetCurrent (&item);
|
|
if (SUCCEEDED (hr))
|
|
{
|
|
APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE type = (APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE)-1;
|
|
item->GetPackageType (&type);
|
|
switch (type)
|
|
{
|
|
case APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE::APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_APPLICATION:
|
|
cnt ++;
|
|
callback (item);
|
|
break;
|
|
case APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE::APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_RESOURCE:
|
|
cnt ++;
|
|
callback (item);
|
|
break;
|
|
default:
|
|
cnt ++;
|
|
callback (item);
|
|
break;
|
|
}
|
|
}
|
|
hr = pointer ()->MoveNext (&hasCurrent);
|
|
}
|
|
return cnt;
|
|
}
|
|
size_t enumerate (_Out_ std::vector <appx_iditem> &output, _In_ APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE enumtype = (APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE)-1) const
|
|
{
|
|
output.clear ();
|
|
enumerate ([&output] (IAppxBundleManifestPackageInfo *ip) {
|
|
output.push_back (appx_iditem (ip));
|
|
}, enumtype);
|
|
return output.size ();
|
|
}
|
|
size_t enumerate (_Out_ std::vector <appx_iditem> &apps, _Out_ std::vector <appx_iditem> &ress) const
|
|
{
|
|
return enumerate ([&apps, &ress] (IAppxBundleManifestPackageInfo *p) {
|
|
APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE type;
|
|
p->GetPackageType (&type);
|
|
switch (type)
|
|
{
|
|
case APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE::APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_APPLICATION:
|
|
apps.push_back (appx_iditem (p)); break;
|
|
case APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE::APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_RESOURCE:
|
|
ress.push_back (appx_iditem (p)); break;
|
|
}
|
|
});
|
|
}
|
|
size_t application_packages (_Out_ std::vector <appx_iditem> &output) const { return enumerate (output, APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE::APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_APPLICATION); }
|
|
size_t resource_packages (_Out_ std::vector <appx_iditem> &output) const { return enumerate (output, APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE::APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_RESOURCE); }
|
|
size_t size () const
|
|
{
|
|
BOOL hasCurrent = FALSE;
|
|
HRESULT hr = pointer ()->GetHasCurrent (&hasCurrent);
|
|
size_t cnt = 0;
|
|
while (SUCCEEDED (hr) && hasCurrent)
|
|
{
|
|
cnt ++;
|
|
hr = pointer ()->MoveNext (&hasCurrent);
|
|
}
|
|
return cnt;
|
|
}
|
|
};
|
|
}
|
|
class appxreader: virtual public com_info_quote <IAppxPackageReader>
|
|
{
|
|
using Base = com_info_quote <IAppxPackageReader>;
|
|
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 Package = IAppxPackageReader;
|
|
using Manifest = IAppxManifestReader;
|
|
public:
|
|
using Base::Base;
|
|
HRESULT manifest (_Outptr_ IAppxManifestReader **output) const { return get (pointer (), &Package::GetManifest, output); }
|
|
template <class IComPtr, class Func> HRESULT get_from_manifest (Func fn, _Outptr_ IComPtr *output) const
|
|
{
|
|
CComPtr <IAppxManifestReader> m;
|
|
HRESULT hr = manifest (&m);
|
|
if (FAILED (hr)) return hr;
|
|
return hr = get (m, 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
|
|
{
|
|
CComPtr <IAppxManifestReader> m;
|
|
HRESULT hr = manifest (&m);
|
|
return appx_info::appx_res (m);
|
|
}
|
|
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
|
|
{
|
|
CComPtr <IAppxManifestReader> m;
|
|
HRESULT hr = manifest (&m);
|
|
return appx_info::appx_preq (m);
|
|
}
|
|
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;
|
|
get_device_capabilities (&ip);
|
|
if (SUCCEEDED (get_capabilities (&caps))) return appx_info::appx_capabs (ip, caps);
|
|
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;
|
|
}
|
|
HRESULT payload_stream (_In_ const std::wstring &filename, _Outptr_ IAppxFile **output) const { return pointer ()->GetPayloadFile (filename.c_str (), output); }
|
|
HRESULT payloads_stream (_Outptr_ IAppxFilesEnumerator **output) const { return pointer ()->GetPayloadFiles (output); }
|
|
HRESULT footprint_stream (_In_ APPX_FOOTPRINT_FILE_TYPE type, _Outptr_ IAppxFile **output) const { return pointer ()->GetFootprintFile (type, output); }
|
|
HRESULT resources_pri_stream (_Outptr_ IAppxFile **output) const { return payload_stream (L"resources.pri", output); }
|
|
HRESULT blockmap (_Outptr_ IAppxBlockMapReader **output) const { return pointer ()->GetBlockMap (output); }
|
|
};
|
|
class bundlereader: virtual public com_info_quote <IAppxBundleReader>
|
|
{
|
|
using Base = com_info_quote <IAppxBundleReader>;
|
|
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 Package = IAppxBundleReader;
|
|
using Manifest = IAppxBundleManifestReader;
|
|
HRESULT manifest (_Outptr_ IAppxBundleManifestReader **output) const { return get (pointer (), &Package::GetManifest, output); }
|
|
template <class IComPtr, class Func> HRESULT get_from_manifest (Func fn, _Outptr_ IComPtr *output) const
|
|
{
|
|
CComPtr <IAppxBundleManifestReader> m;
|
|
HRESULT hr = manifest (&m);
|
|
if (FAILED (hr)) return hr;
|
|
return hr = get (m, 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 get_payload_package (_In_ const std::wstring &filename, _Outptr_ IAppxFile **output) const { return pointer ()->GetPayloadPackage (filename.c_str (), output); }
|
|
HRESULT get_payload_packages (_Outptr_ IAppxFilesEnumerator **output) const { return pointer ()->GetPayloadPackages (output); }
|
|
HRESULT footprint_stream (_In_ APPX_BUNDLE_FOOTPRINT_FILE_TYPE type, _Outptr_ IAppxFile **output) const { return pointer ()->GetFootprintFile (type, output); }
|
|
HRESULT blockmap (_Outptr_ IAppxBlockMapReader **output) const { return pointer ()->GetBlockMap (output); }
|
|
HRESULT payload_package (_In_ const std::wstring &filename, std::function <void (IAppxPackageReader *)> callback) const
|
|
{
|
|
CComPtr <IAppxFile> appxfile;
|
|
CComPtr <IStream> stream;
|
|
CComPtr <IAppxPackageReader> ip;
|
|
HRESULT hr = S_OK;
|
|
if (FAILED (hr = get_payload_package (filename, &appxfile))) return hr;
|
|
if (FAILED (hr = appxfile->GetStream (&stream))) return hr;
|
|
hr = GetAppxPackageReader (stream, &ip);
|
|
if (callback) callback (ip);
|
|
return hr;
|
|
}
|
|
size_t payload_packages (std::function <void (IAppxPackageReader *, LPCWSTR)> callback) const
|
|
{
|
|
CComPtr <IAppxFilesEnumerator> iae;
|
|
BOOL hasCurrent = false;
|
|
HRESULT hr = get_payload_packages (&iae);
|
|
hr = iae->GetHasCurrent (&hasCurrent);
|
|
size_t cnt = 0;
|
|
while (SUCCEEDED (hr) && hasCurrent)
|
|
{
|
|
CComPtr <IAppxFile> afile;
|
|
if (SUCCEEDED (iae->GetCurrent (&afile)))
|
|
{
|
|
LPWSTR filename = nullptr;
|
|
raii endt ([&filename] () {
|
|
if (filename) CoTaskMemFree (filename);
|
|
filename = nullptr;
|
|
});
|
|
afile->GetName (&filename);
|
|
CComPtr <IStream> stream;
|
|
if (SUCCEEDED (afile->GetStream (&stream)))
|
|
{
|
|
CComPtr <IAppxPackageReader> ip;
|
|
if (SUCCEEDED (GetAppxPackageReader (stream, &ip)))
|
|
{
|
|
cnt ++;
|
|
if (callback) callback (ip, filename);
|
|
}
|
|
}
|
|
}
|
|
hr = iae->MoveNext (&hasCurrent);
|
|
}
|
|
return cnt;
|
|
}
|
|
HRESULT random_application_package (_Outptr_ IAppxPackageReader **output) const
|
|
{
|
|
CComPtr <IAppxBundleManifestPackageInfoEnumerator> iditems;
|
|
HRESULT hr = get_package_id_items (&iditems);
|
|
if (FAILED (hr)) return hr;
|
|
BOOL hc = FALSE;
|
|
hr = iditems->GetHasCurrent (&hc);
|
|
bool find = false;
|
|
std::wstring fname = L"";
|
|
while (SUCCEEDED (hr) && hc)
|
|
{
|
|
CComPtr <IAppxBundleManifestPackageInfo> iditem;
|
|
hr = iditems->GetCurrent (&iditem);
|
|
if (SUCCEEDED (hr))
|
|
{
|
|
APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE ptype;
|
|
if (!(SUCCEEDED (iditem->GetPackageType (&ptype)) && ptype == APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE::APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_APPLICATION))
|
|
{
|
|
hr = iditems->MoveNext (&hc);
|
|
continue;
|
|
}
|
|
LPWSTR lpfname = nullptr;
|
|
raii endt ([&lpfname] () {
|
|
if (lpfname) CoTaskMemFree (lpfname);
|
|
lpfname = nullptr;
|
|
});
|
|
if (SUCCEEDED (iditem->GetFileName (&lpfname)) && lpfname)
|
|
{
|
|
fname += lpfname;
|
|
find = true;
|
|
break;
|
|
}
|
|
}
|
|
hr = iditems->MoveNext (&hc);
|
|
}
|
|
if (!find) return FAILED (hr) ? hr : E_FAIL;
|
|
CComPtr <IAppxFile> afile;
|
|
hr = get_payload_package (fname, &afile);
|
|
if (FAILED (hr)) return hr;
|
|
CComPtr <IStream> ist;
|
|
hr = afile->GetStream (&ist);
|
|
if (FAILED (hr)) return hr;
|
|
return GetAppxPackageReader (ist, output);
|
|
}
|
|
HRESULT random_resource_package (_Outptr_ IAppxPackageReader **output) const
|
|
{
|
|
CComPtr <IAppxBundleManifestPackageInfoEnumerator> iditems;
|
|
HRESULT hr = get_package_id_items (&iditems);
|
|
if (FAILED (hr)) return hr;
|
|
BOOL hc = FALSE;
|
|
hr = iditems->GetHasCurrent (&hc);
|
|
bool find = false;
|
|
std::wstring fname = L"";
|
|
while (SUCCEEDED (hr) && hc)
|
|
{
|
|
CComPtr <IAppxBundleManifestPackageInfo> iditem;
|
|
hr = iditems->GetCurrent (&iditem);
|
|
if (SUCCEEDED (hr))
|
|
{
|
|
APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE ptype;
|
|
if (!(SUCCEEDED (iditem->GetPackageType (&ptype)) && ptype == APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE::APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_RESOURCE))
|
|
{
|
|
hr = iditems->MoveNext (&hc);
|
|
continue;
|
|
}
|
|
LPWSTR lpfname = nullptr;
|
|
raii endt ([&lpfname] () {
|
|
if (lpfname) CoTaskMemFree (lpfname);
|
|
lpfname = nullptr;
|
|
});
|
|
if (SUCCEEDED (iditem->GetFileName (&lpfname)) && lpfname)
|
|
{
|
|
fname += lpfname;
|
|
find = true;
|
|
break;
|
|
}
|
|
}
|
|
hr = iditems->MoveNext (&hc);
|
|
}
|
|
if (!find) return FAILED (hr) ? hr : E_FAIL;
|
|
CComPtr <IAppxFile> afile;
|
|
hr = get_payload_package (fname, &afile);
|
|
if (FAILED (hr)) return hr;
|
|
CComPtr <IStream> ist;
|
|
hr = afile->GetStream (&ist);
|
|
if (FAILED (hr)) return hr;
|
|
return GetAppxPackageReader (ist, output);
|
|
}
|
|
size_t application_packages (std::function <void (IAppxPackageReader *)> callback) const
|
|
{
|
|
CComPtr <IAppxBundleManifestPackageInfoEnumerator> iditems;
|
|
HRESULT hr = get_package_id_items (&iditems);
|
|
if (FAILED (hr)) return hr;
|
|
BOOL hc = FALSE;
|
|
hr = iditems->GetHasCurrent (&hc);
|
|
std::vector <std::wstring> files;
|
|
while (SUCCEEDED (hr) && hc)
|
|
{
|
|
CComPtr <IAppxBundleManifestPackageInfo> iditem;
|
|
hr = iditems->GetCurrent (&iditem);
|
|
if (SUCCEEDED (hr))
|
|
{
|
|
APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE ptype;
|
|
if (!(SUCCEEDED (iditem->GetPackageType (&ptype)) && ptype == APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE::APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_APPLICATION))
|
|
{ hr = iditems->MoveNext (&hc); continue; }
|
|
LPWSTR lpfname = nullptr;
|
|
raii endt ([&lpfname] () { if (lpfname) CoTaskMemFree (lpfname); lpfname = nullptr; });
|
|
if (SUCCEEDED (iditem->GetFileName (&lpfname)) && lpfname) files.push_back (lpfname);
|
|
}
|
|
hr = iditems->MoveNext (&hc);
|
|
}
|
|
size_t cnt = 0;
|
|
for (auto &fname : files)
|
|
{
|
|
CComPtr <IAppxFile> afile;
|
|
hr = get_payload_package (fname, &afile);
|
|
if (SUCCEEDED (hr))
|
|
{
|
|
CComPtr <IStream> istrm;
|
|
hr = afile->GetStream (&istrm);
|
|
if (SUCCEEDED (hr))
|
|
{
|
|
CComPtr <IAppxPackageReader> aread;
|
|
hr = GetAppxPackageReader (istrm, &aread);
|
|
if (SUCCEEDED (hr))
|
|
{
|
|
cnt ++;
|
|
callback (aread);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return cnt;
|
|
}
|
|
size_t resource_packages (std::function <void (IAppxPackageReader *)> callback) const
|
|
{
|
|
CComPtr <IAppxBundleManifestPackageInfoEnumerator> iditems;
|
|
HRESULT hr = get_package_id_items (&iditems);
|
|
if (FAILED (hr)) return hr;
|
|
BOOL hc = FALSE;
|
|
hr = iditems->GetHasCurrent (&hc);
|
|
std::vector <std::wstring> files;
|
|
while (SUCCEEDED (hr) && hc)
|
|
{
|
|
CComPtr <IAppxBundleManifestPackageInfo> iditem;
|
|
hr = iditems->GetCurrent (&iditem);
|
|
if (SUCCEEDED (hr))
|
|
{
|
|
APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE ptype;
|
|
if (!(SUCCEEDED (iditem->GetPackageType (&ptype)) && ptype == APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE::APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_RESOURCE))
|
|
{ hr = iditems->MoveNext (&hc); continue; }
|
|
LPWSTR lpfname = nullptr;
|
|
raii endt ([&lpfname] () { if (lpfname) CoTaskMemFree (lpfname); lpfname = nullptr; });
|
|
if (SUCCEEDED (iditem->GetFileName (&lpfname)) && lpfname) files.push_back (lpfname);
|
|
}
|
|
hr = iditems->MoveNext (&hc);
|
|
}
|
|
size_t cnt = 0;
|
|
for (auto &fname : files)
|
|
{
|
|
CComPtr <IAppxFile> afile;
|
|
hr = get_payload_package (fname, &afile);
|
|
if (SUCCEEDED (hr))
|
|
{
|
|
CComPtr <IStream> istrm;
|
|
hr = afile->GetStream (&istrm);
|
|
if (SUCCEEDED (hr))
|
|
{
|
|
CComPtr <IAppxPackageReader> aread;
|
|
hr = GetAppxPackageReader (istrm, &aread);
|
|
if (SUCCEEDED (hr))
|
|
{
|
|
cnt ++;
|
|
callback (aread);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return cnt;
|
|
}
|
|
};
|
|
|
|
class package
|
|
{
|
|
IAppxPackageReader *appx = nullptr;
|
|
IAppxBundleReader *bundle = nullptr;
|
|
public:
|
|
~package () { destroy (); }
|
|
package (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 = GetBundleReader (filepath.c_str (), &bundle);
|
|
if (SUCCEEDED (hr)) return true;
|
|
if (bundle) { bundle->Release (); bundle = nullptr; }
|
|
hr = GetPackageReader (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;
|
|
}
|
|
appxreader appx_reader () const { return appxreader (*(IAppxPackageReader **)&this->appx); }
|
|
bundlereader bundle_reader () const { return bundlereader (*(IAppxBundleReader **)&this->bundle); }
|
|
};
|