The encapsulation of the package manager API has been completed (only a portion of the API has been encapsulated).

This commit is contained in:
Bruce
2025-11-08 23:50:27 +08:00
parent 1b30f3caa5
commit 978f9b6a45
36 changed files with 2855 additions and 40 deletions

View File

@@ -92,14 +92,23 @@ void GetLocaleElaboratedCodeFromLcid (LCID lcid, std::string &ret)
ret = GetLocaleElaboratedCodeFromLcidA (lcid);
}
LCID LocaleCodeToLcidW (LPCWSTR localeCode)
LCID LocaleCodeToLcidW (const std::wstring &localeCode)
{
BYTE buf [LOCALE_NAME_MAX_LENGTH * sizeof (WCHAR)] = {0};
int res = GetLocaleInfoEx (localeCode, LOCALE_RETURN_NUMBER | LOCALE_ILANGUAGE, (LPWSTR)buf, LOCALE_NAME_MAX_LENGTH);
LCID lcid = *((LCID *)buf);
return lcid;
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
try
{
BYTE buf [LOCALE_NAME_MAX_LENGTH * sizeof (WCHAR)] = {0};
int res = GetLocaleInfoEx (localeCode.c_str (), LOCALE_RETURN_NUMBER | LOCALE_ILANGUAGE, (LPWSTR)buf, LOCALE_NAME_MAX_LENGTH);
LCID lcid = *((LCID *)buf);
return lcid;
}
catch (const std::exception &e) {}
return LocaleNameToLCID (localeCode.c_str (), 0);
#else
return LocaleNameToLCID (localeCode.c_str (), 0);
#endif
}
LCID LocaleCodeToLcidA (LPCSTR localeCode)
LCID LocaleCodeToLcidA (const std::string &localeCode)
{
std::wstring lcWide = StringToWString (std::string (localeCode));
return LocaleCodeToLcidW (lcWide.c_str ());
@@ -157,7 +166,91 @@ std::string LcidToLocaleCodeA (LCID lcid, char divide = '-')
}
std::wstring LcidToLocaleCodeW (LCID lcid, WCHAR divide = L'-')
{
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
try
{
WCHAR buf [LOCALE_NAME_MAX_LENGTH] = {0};
LCIDToLocaleName (lcid, buf, LOCALE_NAME_MAX_LENGTH, 0);
return buf;
}
catch (const std::exception &e) {}
return GetLocaleRestrictedCodeFromLcidW (lcid) + divide + GetLocaleElaboratedCodeFromLcidW (lcid);
#else
return GetLocaleRestrictedCodeFromLcidW (lcid) + divide + GetLocaleElaboratedCodeFromLcidW (lcid);
#endif
}
std::wstring LcidToLocaleCode (LCID lcid, WCHAR divide = L'-') { return LcidToLocaleCodeW (lcid, divide); }
std::string LcidToLocaleCode (LCID lcid, char divide = '-') { return LcidToLocaleCodeA (lcid, divide); }
std::string LcidToLocaleCode (LCID lcid, char divide = '-') { return LcidToLocaleCodeA (lcid, divide); }
std::wstring GetUserDefaultLocaleName ()
{
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
try
{
WCHAR buf [LOCALE_NAME_MAX_LENGTH] = {0};
GetUserDefaultLocaleName (buf, LOCALE_NAME_MAX_LENGTH);
return buf;
}
catch (const std::exception &e) {}
return LcidToLocaleCodeW (GetUserDefaultLCID ());
#else
return LcidToLocaleCodeW (GetUserDefaultLCID ());
#endif
}
std::wstring GetSystemDefaultLocaleName ()
{
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
try
{
WCHAR buf [LOCALE_NAME_MAX_LENGTH] = {0};
GetSystemDefaultLocaleName (buf, LOCALE_NAME_MAX_LENGTH);
return buf;
}
catch (const std::exception &e) {}
return LcidToLocaleCodeW (GetSystemDefaultLCID ());
#else
return LcidToLocaleCodeW (GetSystemDefaultLCID ());
#endif
}
std::wstring GetComputerLocaleCodeW ()
{
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
{
try
{
{
LCID lcid = GetThreadLocale ();
std::wstring tmp = LcidToLocaleCodeW (lcid);
if (lcid && tmp.length () > 1) return tmp;
}
{
WCHAR buf [LOCALE_NAME_MAX_LENGTH] = {0};
GetUserDefaultLocaleName (buf, LOCALE_NAME_MAX_LENGTH);
if (lstrlenW (buf)) return buf;
}
{
WCHAR buf [LOCALE_NAME_MAX_LENGTH] = {0};
GetSystemDefaultLocaleName (buf, LOCALE_NAME_MAX_LENGTH);
return buf;
}
}
catch (const std::exception &e) {}
LCID lcid = GetThreadLocale ();
if (!lcid) lcid = GetUserDefaultLCID ();
if (!lcid) lcid = GetSystemDefaultLCID ();
return LcidToLocaleCodeW (lcid);
}
#else
{
LCID lcid = GetThreadLocale ();
if (!lcid) lcid = GetUserDefaultLCID ();
if (!lcid) lcid = GetSystemDefaultLCID ();
return LcidToLocaleCodeW (lcid);
}
#endif
}
bool LocaleNameCompare (const std::wstring &left, const std::wstring &right)
{
return std::wnstring::equals (left, right) || LocaleCodeToLcidW (left) == LocaleCodeToLcidW (right);
}

View File

@@ -5,6 +5,7 @@
#include "readobj.h"
#include "pkgread.h"
#include "localeex.h"
#include "themeinfo.h"
#define ToHandleRead(_cpp_ptr_) reinterpret_cast <HPKGREAD> (_cpp_ptr_)
#define ToPtrPackage(_cpp_ptr_) reinterpret_cast <package *> (_cpp_ptr_)
@@ -859,4 +860,313 @@ BOOL GetPackagePrerequisite (_In_ HPKGREAD hReader, _In_ LPCWSTR lpName, _Outptr
} break;
}
return FALSE;
}
}
// Selector
std::wnstring SelectLanguageSuitPackageNameByLocaleCode (std::map <std::wnstring, appx_info::resource> &in, const std::wstring &langcode, std::wnstring &output)
{
output.clear ();
for (auto &it : in)
{
if (it.second.restype != appx_info::ResourceType::language) continue;
for (auto &it_s : it.second.resvalue.languages) if (LocaleNameCompare (it_s, langcode)) return output = it.first;
}
return output = L"";
}
std::wnstring SelectLanguageSuitPackageName (std::map <std::wnstring, appx_info::resource> &in, std::wnstring &output)
{
output.clear ();
output = SelectLanguageSuitPackageNameByLocaleCode (in, GetComputerLocaleCodeW (), output);
if (output.empty ()) output = SelectLanguageSuitPackageNameByLocaleCode (in, L"en-US", output);
if (output.empty ())
{
for (auto &it : in)
{
if (it.second.pkgtype == APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_APPLICATION)
{
output = it.first;
break;
}
}
}
if (output.empty ())
{
try { output = in.begin ()->first; }
catch (const std::exception &e) { output = L""; }
}
return output;
}
std::wnstring SelectScaleSuitPackageName (std::map <std::wnstring, appx_info::resource> &in, std::wnstring &output)
{
output.clear ();
struct res_key_value
{
std::wnstring filename = L"";
uint32_t scale = 0;
res_key_value (const std::wstring &fpath = L"", uint32_t s = 0):
filename (fpath), scale (s) {}
};
std::vector <res_key_value> rkv;
for (auto &it : in) if ((WORD)it.second.restype & (WORD)appx_info::ResourceType::scale)
{
for (auto &it_s : it.second.resvalue.scales)
{
if (!it_s) continue;
rkv.push_back (res_key_value (it.first, it_s));
}
}
std::sort (rkv.begin (), rkv.end (), [] (const res_key_value &a, const res_key_value &b) {
return a.scale < b.scale;
});
auto dpi = GetDPI ();
for (auto &it : rkv) if (it.scale > dpi) return output = it.filename;
if (output.empty ()) { for (auto it = rkv.rbegin (); it != rkv.rend (); ++ it) if (it->scale < dpi) return output = it->filename; }
if (output.empty ()) { for (auto &it : in) if (it.second.pkgtype == APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_APPLICATION) return output = it.first; }
try { output = in.begin ()->first; }
catch (const std::exception &e) { output = L""; }
return output;
}
// File Stream
HANDLE GetAppxFileFromAppxPackage (_In_ HPKGREAD hReader, _In_ LPCWSTR lpFileName)
{
auto ptr = ToPtrPackage (hReader);
if (!ptr) return nullptr;
if (!lpFileName) return nullptr;
switch (ptr->type ())
{
case PackageType::single: {
auto reader = ptr->appx_reader ();
CComPtr <IAppxFile> afile;
if (FAILED (reader.payload_stream (lpFileName, &afile))) return nullptr;
IStream *istream = nullptr;
if (FAILED (afile->GetStream (&istream))) return nullptr;
else return istream;
} break;
case PackageType::bundle: {
auto bread = ptr->bundle_reader ();
CComPtr <IAppxPackageReader> appfile;
if (FAILED (bread.random_application_package (&appfile))) return nullptr;
appxreader reader (appfile.p);
CComPtr <IAppxFile> afile;
if (FAILED (reader.payload_stream (lpFileName, &afile))) return nullptr;
IStream *istream = nullptr;
if (FAILED (afile->GetStream (&istream))) return nullptr;
else return istream;
} break;
}
return nullptr;
}
HANDLE GetAppxBundlePayloadPackageFile (_In_ HPKGREAD hReader, _In_ LPCWSTR lpFileName)
{
auto ptr = ToPtrPackage (hReader);
if (!ptr) return nullptr;
if (!lpFileName) return nullptr;
if (ptr->type () == PackageType::bundle)
{
auto reader = ptr->bundle_reader ();
CComPtr <IAppxFile> iafile;
if (FAILED (reader.get_payload_package (lpFileName, &iafile))) return nullptr;
IStream *istream = nullptr;
if (FAILED (iafile->GetStream (&istream))) return nullptr;
else return istream;
}
else return nullptr;
}
HANDLE GetAppxPriFileStream (_In_ HPKGREAD hReader) { return GetAppxFileFromAppxPackage (hReader, L"resources.pri"); }
HANDLE GetFileFromPayloadPackage (_In_ HANDLE hPackageStream, _In_ LPCWSTR lpFileName)
{
if (!hPackageStream || !lpFileName) return nullptr;
IStream *ifs = (IStream *)hPackageStream;
CComPtr <IAppxPackageReader> iappx;
if (FAILED (GetAppxPackageReader (ifs, &iappx))) return nullptr;
appxreader reader (iappx.p);
CComPtr <IAppxFile> iaf;
if (FAILED (reader.payload_stream (lpFileName, &iaf))) return nullptr;
IStream *istream = nullptr;
if (FAILED (iaf->GetStream (&istream))) return nullptr;
else return istream;
}
HANDLE GetPriFileFromPayloadPackage (_In_ HANDLE hPackageStream) { return GetFileFromPayloadPackage (hPackageStream, L"resources.pri"); }
BOOL GetSuitablePackageFromBundle (_In_ HPKGREAD hReader, _Outptr_ HANDLE *pStreamForLang, _Outptr_ HANDLE *pStreamForScale)
{
auto ptr = ToPtrPackage (hReader);
if (!ptr) return FALSE;
if (ptr->type () != PackageType::bundle) return FALSE;
if (pStreamForLang) *pStreamForLang = nullptr;
if (pStreamForScale) *pStreamForScale = nullptr;
auto bread = ptr->bundle_reader ();
auto pkgsinfo = bread.package_id_items ();
std::map <std::wnstring, appx_info::resource> mapfr;
pkgsinfo.resource_info (mapfr);
std::wnstring lf = L"", sf = L"";
SelectLanguageSuitPackageName (mapfr, lf);
SelectScaleSuitPackageName (mapfr, sf);
if (lf == sf)
{
WORD flag = (bool)pStreamForLang << 1 | (bool)pStreamForScale;
switch (flag)
{
case 0b01:
case 0b10:
case 0b11: {
IStream *file = nullptr;
CComPtr <IAppxFile> pread;
if (FAILED (bread.get_payload_package (lf, &pread))) return false;
if (FAILED (pread->GetStream (&file))) return false;
if (pStreamForLang) *pStreamForLang = file;
if (pStreamForScale) *pStreamForScale = file;
return true;
} break;
default:
case 0b00: {
CComPtr <IAppxFile> pread;
if (FAILED (bread.get_payload_package (lf, &pread))) return false;
CComPtr <IStream> file = nullptr;
if (FAILED (pread->GetStream (&file))) return false;
else return true;
} break;
}
}
else
{
{
CComPtr <IAppxFile> reslangpkg;
if (FAILED (bread.get_payload_package (lf, &reslangpkg))) return false;
if (pStreamForLang)
{
IStream *file = nullptr;
if (FAILED (reslangpkg->GetStream (&file))) return false;
*pStreamForLang = file;
}
else
{
CComPtr <IStream> file;
if (FAILED (reslangpkg->GetStream (&file))) return false;
}
}
{
CComPtr <IAppxFile> resscalepkg;
if (FAILED (bread.get_payload_package (sf, &resscalepkg))) return false;
if (pStreamForScale)
{
IStream *file = nullptr;
if (FAILED (resscalepkg->GetStream (&file))) return false;
*pStreamForScale = file;
}
else
{
CComPtr <IStream> file;
if (FAILED (resscalepkg->GetStream (&file))) return false;
}
}
}
return true;
}
ULONG DestroyAppxFileStream (_In_ HANDLE hFileStream)
{
if (!hFileStream) return 0;
IStream *ptr = reinterpret_cast <IStream *> (hFileStream);
if (!ptr) return 0;
return ptr->Release ();
}
HANDLE GetAppxBundleApplicationPackageFile (_In_ HPKGREAD hReader)
{
if (!hReader) return nullptr;
auto ptr = ToPtrPackage (hReader);
if (!ptr) return nullptr;
switch (ptr->type ())
{
case PackageType::single: {
return nullptr;
} break;
case PackageType::bundle: {
auto bread = ptr->bundle_reader ();
IStream *ipf = nullptr;
if (FAILED (bread.random_application_package (&ipf))) return nullptr;
else return ipf;
} break;
}
return nullptr;
}
std::wstring GetMimeTypeFromStream (IStream *filestream)
{
if (!filestream) return L"";
LARGE_INTEGER liZero = {0};
filestream->Seek (liZero, STREAM_SEEK_SET, nullptr);
BYTE buffer [256] = {0};
ULONG bytesRead = 0;
HRESULT hr = filestream->Read (buffer, sizeof (buffer), &bytesRead);
filestream->Seek (liZero, STREAM_SEEK_SET, nullptr);
if (FAILED (hr) || bytesRead == 0) return L"";
LPWSTR lpMime = nullptr;
raii relt ([&lpMime] () {
if (lpMime) CoTaskMemFree (lpMime);
lpMime = nullptr;
});
std::wstring mime;
hr = FindMimeFromData (
nullptr, // pBC
nullptr, // URL (unknown)
buffer, // data buffer
bytesRead, // data size
nullptr, // proposed MIME
FMFD_RETURNUPDATEDIMGMIMES |
FMFD_IGNOREMIMETEXTPLAIN |
FMFD_URLASFILENAME,
&lpMime, // result
0 // reserved
);
if (SUCCEEDED (hr) && lpMime) mime = lpMime;
if (mime.empty ())
{
if (bytesRead >= 8 && memcmp (buffer, "\x89PNG\r\n\x1A\n", 8) == 0) mime = L"image/png";
else if (bytesRead >= 3 && buffer [0] == 0xFF && buffer [1] == 0xD8) mime = L"image/jpeg";
else if (bytesRead >= 6 && memcmp (buffer, "GIF89a", 6) == 0) mime = L"image/gif";
else if (bytesRead >= 2 && buffer [0] == 'B' && buffer [1] == 'M') mime = L"image/bmp";
else if (bytesRead >= 12 && memcmp (buffer, "RIFF", 4) == 0 && memcmp (buffer + 8, "WEBP", 4) == 0) mime = L"image/webp";
else if (bytesRead >= 4 && memcmp (buffer, "\x00\x00\x01\x00", 4) == 0) mime = L"image/x-icon";
else mime = L"application/octet-stream";
}
return mime;
}
std::wstring GetBase64StringFromStreamW (IStream *ifile)
{
if (!ifile) return L"";
IStream *&pStream = ifile;
LARGE_INTEGER liZero = {};
pStream->Seek (liZero, STREAM_SEEK_SET, nullptr);
STATSTG statstg;
pStream->Stat (&statstg, STATFLAG_NONAME);
ULARGE_INTEGER uliSize = statstg.cbSize;
std::vector <BYTE> buffer (uliSize.QuadPart);
ULONG bytesRead;
pStream->Read (buffer.data (), static_cast <ULONG> (buffer.size ()), &bytesRead);
DWORD base64Size = 0;
if (!CryptBinaryToStringW (buffer.data (), bytesRead, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, nullptr, &base64Size)) return nullptr;
std::vector <WCHAR> base64Buffer (base64Size + 1);
if (!CryptBinaryToStringW (buffer.data (), bytesRead, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, base64Buffer.data (), &base64Size)) return nullptr;
pStream->Seek (liZero, STREAM_SEEK_SET, nullptr);
return std::wstring (base64Buffer.data ());
}
LPWSTR StreamToBase64W (_In_ HANDLE hFileStream, _Out_writes_ (dwCharCount) LPWSTR lpMimeBuf, _In_ DWORD dwCharCount, _Outptr_ LPWSTR *lpBase64Head)
{
IStream *ifs = (IStream *)hFileStream;
if (!ifs) return nullptr;
LPWSTR retptr = nullptr;
std::wstring ret = L"";
std::wstring mime = GetMimeTypeFromStream (ifs);
auto &dwBufSize = dwCharCount;
if (lpMimeBuf)
{
ZeroMemory (lpMimeBuf, sizeof (WCHAR) * dwBufSize);
wcsncpy_s (lpMimeBuf, dwBufSize, mime.c_str (), _TRUNCATE);
}
ret += L"data:" + mime + L";base64,";
size_t head = ret.length ();
ret += GetBase64StringFromStreamW (ifs);
retptr = _wcsdup (ret.c_str ());
if (lpBase64Head) *lpBase64Head = retptr + head;
return retptr;
}

View File

@@ -14,7 +14,7 @@
#ifdef __cplusplus
#define _DEFAULT_INIT_VALUE_(_init_value_) = _init_value_
#ifdef PKGREAD_EXPORTS
#ifndef PKGREAD_EXPORTS
#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_) = _init_value_
#else
#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_)
@@ -252,6 +252,36 @@ extern "C"
#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_)
// 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);
#ifdef _DEFAULT_INIT_VALUE_
#undef _DEFAULT_INIT_VALUE_
#endif
@@ -262,24 +292,142 @@ extern "C"
}
#endif
#if defined (__cplusplus) && !defined (PKGREAD_EXPORTS)
#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"
};
class package_reader
{
private:
HPKGREAD hReader = nullptr;
std::wstring filepath = L"";
struct deconstr
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);
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) 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);
HANDLE hd = GetAppxBundleApplicationPackageFile (hReader);
destruct relthd ([&hd] () {
if (hd) DestroyAppxFileStream (hd);
});
HANDLE hdpri = GetPriFileFromPayloadPackage (hd);
if (hd) pribundlereader.set (3, (IStream *)hd);
} break;
case 0b11: {
if (ls) pribundlereader.set (1, (IStream *)hlpri);
if (ss) pribundlereader.set (2, (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;
}
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) {}
#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
{
@@ -333,22 +481,151 @@ class package_reader
if (FAILED (hr)) return bRetWhenFailed;
else return ret != FALSE;
}
std::wstring display_name () const { return string_value (PKG_PROPERTIES_DISPLAYNAME); }
std::wstring publisher_display_name () const { return string_value (PKG_PROPERTIES_PUBLISHER); }
std::wstring description () const { return string_value (PKG_PROPERTIES_DESCRIPTION); }
std::wstring logo () const { return string_value (PKG_PROPERTIES_LOGO); }
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) 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);
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;
std::wstring user_model_id () const { return this->find (L"AppUserModelID")->second; }
friend bool operator == (const application &a1, const application &a2) { return !_wcsicmp (a1.user_model_id ().c_str (), a2.user_model_id ().c_str ()); }
friend bool operator != (const application &a1, const application &a2) { return _wcsicmp (a1.user_model_id ().c_str (), a2.user_model_id ().c_str ()); }
explicit operator bool () const { return this->user_model_id ().empty (); }
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);
@@ -356,6 +633,21 @@ class package_reader
{
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)
@@ -376,6 +668,124 @@ class package_reader
}
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) 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
{
@@ -405,7 +815,11 @@ class package_reader
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];
@@ -418,6 +832,13 @@ class package_reader
}
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
{
@@ -569,7 +990,16 @@ class package_reader
{
file (fpath);
}
~package_reader () { DestroyPackageReader (hReader); hReader = nullptr; }
~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)
{
@@ -581,12 +1011,64 @@ class package_reader
// PKGROLE_* 前缀常量
WORD package_role () const { return GetPackageRole (hReader); }
identity get_identity () { return identity (hReader); }
properties get_properties () { return properties (hReader); }
applications get_applications () { return applications (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
}
};
#endif

BIN
pkgread/pkgread.rc Normal file

Binary file not shown.

View File

@@ -92,6 +92,7 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>urlmon.lib;crypt32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -122,6 +123,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>urlmon.lib;crypt32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -145,18 +147,18 @@
<Text Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\priformatcli\priformatcli\priformatcli.h" />
<ClInclude Include="dynarr.h" />
<ClInclude Include="localeex.h" />
<ClInclude Include="norstr.h" />
<ClInclude Include="pkgread.h" />
<ClInclude Include="raii.h" />
<ClInclude Include="readobj.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="resource1.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="stringres.h" />
<ClInclude Include="syncutil.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="themeinfo.h" />
<ClInclude Include="version.h" />
</ItemGroup>
<ItemGroup>
@@ -185,6 +187,9 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="pkgread.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@@ -33,9 +33,6 @@
<ClInclude Include="version.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="stringres.h">
<Filter>头文件</Filter>
</ClInclude>
@@ -54,7 +51,10 @@
<ClInclude Include="localeex.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\..\priformatcli\priformatcli\priformatcli.h">
<ClInclude Include="resource1.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="themeinfo.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
@@ -72,4 +72,9 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="pkgread.rc">
<Filter>资源文件</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@@ -209,7 +209,6 @@ template <typename ComInterface> class com_info_quote
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"";
@@ -254,6 +253,7 @@ template <typename ComInterface> class com_info_quote
com_info_quote (com_info_quote &&) noexcept = default;
com_info_quote &operator = (com_info_quote &&) noexcept = default;
bool valid () const { return !!icom; }
ComInterface *pointer () const noexcept { return icom; }
};
namespace appx_info
{
@@ -703,6 +703,34 @@ namespace appx_info
}
UINT64 size () const { return get <UINT64> (&Interface::GetSize); }
};
enum class ResourceType
{
unknown = 0b00,
language = 0b01,
scale = 0b10,
both = 0b11
};
struct resource
{
ResourceType restype = ResourceType::unknown;
APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE pkgtype = APPX_BUNDLE_PAYLOAD_PACKAGE_TYPE_APPLICATION;
struct resource_content
{
std::vector <std::wnstring> languages;
std::vector <uint32_t> scales;
resource_content (const std::vector <std::wnstring> &langs): languages (langs) {}
resource_content (const std::vector <uint32_t> &ss): scales (ss) {}
resource_content (const std::vector <std::wnstring> &langs, const std::vector <uint32_t> &ss): languages (langs), scales (ss) {}
resource_content () = default;
} resvalue;
resource (const std::vector <std::wnstring> &languages):
restype (ResourceType::language), resvalue (languages) {}
resource (const std::vector <uint32_t> &ss):
restype (ResourceType::scale), resvalue (ss) {}
resource (const std::vector <std::wnstring> &langs, const std::vector <uint32_t> &ss):
restype (ResourceType::both), resvalue (langs, ss) {}
resource (): restype (ResourceType::unknown), resvalue () {}
};
class appx_iditems: virtual public com_info <IAppxBundleManifestPackageInfoEnumerator>
{
using Base = com_info <IAppxBundleManifestPackageInfoEnumerator>;
@@ -777,6 +805,33 @@ namespace appx_info
}
return cnt;
}
size_t resource_info (std::map <std::wnstring, resource> &output) const
{
output.clear ();
std::vector <appx_iditem> items;
enumerate (items);
for (auto &it : items)
{
std::wnstring fpath = it.file_name ();
auto qres = it.qualified_resources ();
std::vector <std::wstring> langs;
std::vector <uint32_t> scales;
qres.qualified_resources (&langs, &scales);
std::vector <std::wnstring> langs_n;
for (auto &it_l : langs) langs_n.push_back (it_l);
BYTE status = (bool)langs_n.size () << 1 | (bool)scales.size ();
switch (status)
{
case 0b01: output [fpath] = resource (scales); break;
case 0b10: output [fpath] = resource (langs_n); break;
case 0b11: output [fpath] = resource (langs_n, scales); break;
default:
case 0b00: output [fpath] = resource (); break;
}
output [fpath].pkgtype = it.type ();
}
return output.size ();
}
};
}
class appxreader: virtual public com_info_quote <IAppxPackageReader>
@@ -1029,6 +1084,98 @@ class bundlereader: virtual public com_info_quote <IAppxBundleReader>
if (FAILED (hr)) return hr;
return GetAppxPackageReader (ist, output);
}
HRESULT random_application_package (_Outptr_ IAppxFile **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;
return get_payload_package (fname, output);
}
HRESULT random_resource_package (_Outptr_ IAppxFile **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;
return hr = get_payload_package (fname, output);
}
HRESULT random_application_package (_Outptr_ IStream **output) const
{
CComPtr <IAppxFile> iaf;
HRESULT hr = S_OK;
if (FAILED (hr = random_application_package (&iaf))) return hr;
return iaf->GetStream (output);
}
HRESULT random_resource_package (_Outptr_ IStream **output) const
{
CComPtr <IAppxFile> iaf;
HRESULT hr = S_OK;
if (FAILED (hr = random_resource_package (&iaf))) return hr;
return iaf->GetStream (output);
}
size_t application_packages (std::function <void (IAppxPackageReader *)> callback) const
{
CComPtr <IAppxBundleManifestPackageInfoEnumerator> iditems;

View File

@@ -23,4 +23,13 @@
#include <sstream>
#include <atlbase.h>
#include <functional>
#include <utility>
#include <utility>
#include <urlmon.h>
#include <wincrypt.h>
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif

40
pkgread/themeinfo.h Normal file
View File

@@ -0,0 +1,40 @@
#pragma once
#include <Windows.h>
bool IsHighContrastEnabled ()
{
HIGHCONTRAST hc = {sizeof (HIGHCONTRAST)};
if (SystemParametersInfo (SPI_GETHIGHCONTRAST, sizeof (hc), &hc, 0)) return (hc.dwFlags & HCF_HIGHCONTRASTON) != 0;
return false;
}
enum class HighContrastTheme
{
None,
Black,
White,
Other
};
HighContrastTheme GetHighContrastTheme ()
{
HIGHCONTRAST hc = {sizeof (HIGHCONTRAST)};
if (!SystemParametersInfo (SPI_GETHIGHCONTRAST, sizeof (hc), &hc, 0)) return HighContrastTheme::None;
if (!(hc.dwFlags & HCF_HIGHCONTRASTON)) return HighContrastTheme::None;
COLORREF bgColor = GetSysColor (COLOR_WINDOW);
COLORREF textColor = GetSysColor (COLOR_WINDOWTEXT);
int brightnessBg = (GetRValue (bgColor) + GetGValue (bgColor) + GetBValue (bgColor)) / 3;
int brightnessText = (GetRValue (textColor) + GetGValue (textColor) + GetBValue (textColor)) / 3;
if (brightnessBg < brightnessText) return HighContrastTheme::Black;
else if (brightnessBg > brightnessText) return HighContrastTheme::White;
else return HighContrastTheme::Other;
}
int GetDPI ()
{
HDC hDC = GetDC (NULL);
int DPI_A = (int)(((double)GetDeviceCaps (hDC, 118) / (double)GetDeviceCaps (hDC, 8)) * 100);
int DPI_B = (int)(((double)GetDeviceCaps (hDC, 88) / 96) * 100);
ReleaseDC (NULL, hDC);
if (DPI_A == 100) return DPI_B;
else if (DPI_B == 100) return DPI_A;
else if (DPI_A == DPI_B) return DPI_A;
else return 0;
}