mirror of
https://github.com/modernw/App-Installer-For-Windows-8.x-Reset.git
synced 2026-04-11 17:57:19 +10:00
315 lines
11 KiB
C++
315 lines
11 KiB
C++
// 下列 ifdef 块是创建使从 DLL 导出更简单的
|
||
// 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 PRIFORMATCLI_EXPORTS
|
||
// 符号编译的。在使用此 DLL 的
|
||
// 任何其他项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将
|
||
// PRIFORMATCLI_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的
|
||
// 符号视为是被导出的。
|
||
#ifdef PRIFORMATCLI_EXPORTS
|
||
#define PRIFORMATCLI_API __declspec(dllexport)
|
||
#else
|
||
#define PRIFORMATCLI_API __declspec(dllimport)
|
||
#endif
|
||
|
||
#ifndef _PRI_READER_CLI_HEADER_
|
||
#define _PRI_READER_CLI_HEADER_
|
||
|
||
#ifdef __cplusplus
|
||
#define _DEFAULT_VALUE_SET(valueexpr) = valueexpr
|
||
#ifndef PRIFORMATCLI_EXPORTS
|
||
#define _DEFAULT_VALUE_SET_FUNC(valueexpr) _DEFAULT_VALUE_SET (valueexpr)
|
||
#else
|
||
#define _DEFAULT_VALUE_SET_FUNC(valueexpr)
|
||
#endif
|
||
#else
|
||
#define _DEFAULT_VALUE_SET(valueexpr)
|
||
#define _DEFAULT_VALUE_SET_FUNC(valueexpr)
|
||
#endif
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
// 为了兼容。将 IStream * 转换成 PCOISTREAM 使用(C 用强制类型转换,C++ 也可以用强制类型,或者 reinterpret_cast?)。
|
||
typedef struct COISTREAM__ *PCOISTREAM;
|
||
// 返回 PriFile 实例指针。
|
||
typedef struct CSPRIFILE__ *PCSPRIFILE;
|
||
// 创建 PriFile 实例。请传入有效指针。失败返回 nullptr。
|
||
typedef struct LPCWSTRLIST__
|
||
{
|
||
DWORD dwLength _DEFAULT_VALUE_SET (0);
|
||
LPCWSTR aswArray [1] _DEFAULT_VALUE_SET ({0});
|
||
} LPCWSTRLIST, *HLPCWSTRLIST;
|
||
// 注意:PriFile 使用 IStream * 流类似于“借用”关系。要保证 PriFile 实例的生命周期
|
||
// 在 IStream * 的生命周期内。
|
||
PRIFORMATCLI_API PCSPRIFILE CreatePriFileInstanceFromStream (PCOISTREAM pStream);
|
||
// 销毁 PriFile 对象。注意: PriFile 的销毁不会影响 IStream *。
|
||
PRIFORMATCLI_API void DestroyPriFileInstance (PCSPRIFILE pFilePri);
|
||
// 获取 PriFile 的文本资源。文本资源是会根据当前系统/用户正在使用的语言来选择最合适的文本。
|
||
// 这里没有自定义获取。注:返回的有效非空指针请用 free 来释放。
|
||
// 传入的是 ms-resource: 开头的字符串,以 URI 形式。
|
||
// 示例:
|
||
// 1. ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_DisplayName (常见于 UWP 应用)
|
||
// 2. ms-resource:ApplicationTitleWithBranding (常见于 Windows 8.x 应用)
|
||
PRIFORMATCLI_API LPWSTR GetPriStringResource (PCSPRIFILE pFilePri, LPCWSTR lpswUri);
|
||
// 获取 PriFile 的文件路径资源。对于一些如图像资源,会有对于系统不同 DPI 的适应
|
||
// 目录分隔符为“\”(在应用清单中对于文件路径一直使用“\”),“/”不会支持。且一定为相对路径。
|
||
// 注:返回的有效非空指针请用 free 释放。
|
||
PRIFORMATCLI_API LPWSTR GetPriPathResource (PCSPRIFILE pFilePri, LPCWSTR lpswFilePath);
|
||
// 从文件路径创建 PriFile 实例。(虽然用不上)。销毁同样通过 DestroyPriFileInstance。
|
||
PRIFORMATCLI_API PCSPRIFILE CreatePriFileInstanceFromPath (LPCWSTR lpswFilePath);
|
||
// 注意:可能会由于并发等导致返回的异常信息会错乱。
|
||
PRIFORMATCLI_API LPCWSTR PriFileGetLastError ();
|
||
// 对于多个资源,建议一次遍及,预先进行缓存。通过 GetPriStringResource 获取值。
|
||
PRIFORMATCLI_API void FindPriStringResource (PCSPRIFILE pFilePri, HLPCWSTRLIST hUriList);
|
||
// 对于多个资源,建议一次遍及,预先进行缓存。通过 GetPriPathResource 获取值。
|
||
PRIFORMATCLI_API void FindPriPathResource (PCSPRIFILE pFilePri, HLPCWSTRLIST hPathList);
|
||
// 清理内存缓存数据,仅用于测试用。注意:清理指的是所有。
|
||
PRIFORMATCLI_API void ClearPriCacheData ();
|
||
// 获取资源,作用与 GetPriStringResource 和 GetPriPathResource 一样。(因为这两个函数都是调用此函数)
|
||
PRIFORMATCLI_API LPWSTR GetPriResource (PCSPRIFILE pFilePri, LPCWSTR lpswResId);
|
||
// 开始查找资源,与 FindPriStringResource 和 FindPriPathResource 一样(因为这两个函数都是调用此函数)
|
||
PRIFORMATCLI_API void FindPriResource (PCSPRIFILE pFilePri, HLPCWSTRLIST hUriList);
|
||
// 工具函数,用于判断是否为 ms-resource: 前缀
|
||
PRIFORMATCLI_API BOOL IsMsResourcePrefix (LPCWSTR pResName);
|
||
// 工具函数,用于判断是否为 ms-resource:// 前缀
|
||
PRIFORMATCLI_API BOOL IsMsResourceUriFull (LPCWSTR pResUri);
|
||
// 工具函数,用于判断是否为 MS-Resource URI
|
||
PRIFORMATCLI_API BOOL IsMsResourceUri (LPCWSTR pResUri);
|
||
#ifdef _DEFAULT_VALUE_SET
|
||
#undef _DEFAULT_VALUE_SET
|
||
#endif
|
||
#ifdef _DEFAULT_VALUE_SET_FUNC
|
||
#undef _DEFAULT_VALUE_SET_FUNC
|
||
#endif
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#if defined (__cplusplus)
|
||
#include <string>
|
||
#include <atlbase.h>
|
||
#include <Shlwapi.h>
|
||
#include <functional>
|
||
#include <vector>
|
||
#include <map>
|
||
// 注意:此类仅为操作类,如果以 IStream * 来初始化类的话在类销毁时不会释放 IStream *。请在此类实例生命期结束后必须释放 IStream *
|
||
typedef class prifile
|
||
{
|
||
private:
|
||
PCSPRIFILE m_hPriFile = nullptr;
|
||
class reltask
|
||
{
|
||
public:
|
||
std::function <void ()> endtask;
|
||
reltask (std::function <void ()> pf): endtask (pf) {}
|
||
reltask () { if (endtask) endtask (); }
|
||
};
|
||
public:
|
||
bool valid () const { return m_hPriFile != nullptr; }
|
||
void destroy ()
|
||
{
|
||
if (m_hPriFile)
|
||
{
|
||
DestroyPriFileInstance (m_hPriFile);
|
||
m_hPriFile = nullptr;
|
||
}
|
||
}
|
||
~prifile () { destroy (); }
|
||
bool create (IStream *p)
|
||
{
|
||
try
|
||
{
|
||
destroy ();
|
||
if (!p) return false;
|
||
m_hPriFile = CreatePriFileInstanceFromStream ((PCOISTREAM)p);
|
||
}
|
||
catch (const std::exception &e)
|
||
{
|
||
m_hPriFile = nullptr;
|
||
}
|
||
return valid ();
|
||
}
|
||
bool create (const std::wstring &filepath)
|
||
{
|
||
try
|
||
{
|
||
destroy ();
|
||
if (filepath.empty ()) return false;
|
||
m_hPriFile = CreatePriFileInstanceFromPath (filepath.c_str ());
|
||
}
|
||
catch (const std::exception &e)
|
||
{
|
||
m_hPriFile = nullptr;
|
||
}
|
||
return valid ();
|
||
}
|
||
prifile (IStream *pStream) { create (pStream); }
|
||
prifile (const std::wstring &filepath) { create (filepath); }
|
||
prifile () = default;
|
||
void add_search (const std::vector <std::wstring> &arr) const
|
||
{
|
||
BYTE *buf = (BYTE *)malloc (sizeof (LPCWSTRLIST) + sizeof (LPWSTR) * arr.size ());
|
||
reltask release ([&buf] () {
|
||
if (buf) free (buf);
|
||
buf = nullptr;
|
||
});
|
||
HLPCWSTRLIST hList = (HLPCWSTRLIST)buf;
|
||
hList->dwLength = arr.size ();
|
||
for (size_t i = 0; i < hList->dwLength; i ++)
|
||
{
|
||
hList->aswArray [i] = arr [i].c_str ();
|
||
}
|
||
FindPriResource (m_hPriFile, hList);
|
||
}
|
||
void add_search (const std::wstring &arr) const
|
||
{
|
||
BYTE buf [sizeof (LPCWSTRLIST) + sizeof (LPWSTR)] = {0};
|
||
HLPCWSTRLIST hList = (HLPCWSTRLIST)buf;
|
||
hList->dwLength = 1;
|
||
hList->aswArray [0] = arr.c_str ();
|
||
FindPriResource (m_hPriFile, hList);
|
||
}
|
||
std::wstring resource (const std::wstring &resname) const
|
||
{
|
||
LPWSTR lpstr = nullptr;
|
||
reltask release ([&lpstr] () {
|
||
if (lpstr) free (lpstr);
|
||
lpstr = nullptr;
|
||
});
|
||
lpstr = GetPriResource (m_hPriFile, resname.c_str ());
|
||
return lpstr ? lpstr : L"";
|
||
}
|
||
size_t resources (const std::vector <std::wstring> &resnames, std::map <std::wstring, std::wstring> &output) const
|
||
{
|
||
add_search (resnames);
|
||
for (auto &it : resnames) output [it] = resource (it);
|
||
return output.size ();
|
||
}
|
||
LPCWSTR last_error () { return PriFileGetLastError (); }
|
||
std::wstring path (const std::wstring &resname) const { return resource (resname); }
|
||
size_t paths (const std::vector <std::wstring> &resnames, std::map <std::wstring, std::wstring> &output) const { return resources (resnames, output); }
|
||
std::wstring string (const std::wstring &resname) const { return resource (resname); }
|
||
size_t strings (const std::vector <std::wstring> &resnames, std::map <std::wstring, std::wstring> &output) const { return resources (resnames, output); }
|
||
} prifilecli;
|
||
// 注意:此类仅为操作类,如果以 IStream * 来初始化类的话在类销毁时不会释放 IStream *。请在此类实例生命期结束后必须释放 IStream *
|
||
typedef class prifilebundle
|
||
{
|
||
public:
|
||
struct PRI_INST
|
||
{
|
||
// 0b01 语言 0b10 缩放资源 0b11 两者(或者是应用包的资源包)
|
||
uint8_t type = 0;
|
||
prifile priinst;
|
||
bool res_language () const { return type & 0b01; }
|
||
bool res_scale () const { return type & 0b10; }
|
||
bool res_both () const { return type & 0b11; }
|
||
bool is_valid () const { return type & 0b11; }
|
||
// 类型:0: 无效,不许插入,1:语言资源,2:缩放资源,3:两者都有
|
||
// 必须插入有效的内容
|
||
PRI_INST (uint8_t type = 0, IStream *ipri = nullptr):
|
||
type (type), priinst (ipri) {}
|
||
};
|
||
private:
|
||
std::vector <PRI_INST> prifiles;
|
||
std::map <uint8_t, PRI_INST *> mappri;
|
||
public:
|
||
prifilebundle () { prifiles.reserve (3); }
|
||
// 类型:0: 无效,不许插入,1:语言资源,2:缩放资源,3:两者都有
|
||
// 插入 3 类型的不会顶替 1 和 2 类型,只会顶替 3 类型。所以类中储存的实例最多只有三个。
|
||
// 必须指定有效类型。如果 prifile 为 nullptr,则以位置相应类型的 pri 要执行销毁。
|
||
bool set (uint8_t type, IStream *prifile)
|
||
{
|
||
uint8_t realt = type & 0b11;
|
||
if (!type) return false;
|
||
if (mappri.find (type & 0b11) != mappri.end ())
|
||
{
|
||
auto &prii = mappri [realt];
|
||
prii->priinst.destroy ();
|
||
if (prifile) prii->priinst.create (prifile);
|
||
}
|
||
else
|
||
{
|
||
if (!prifile) return false;
|
||
prifiles.emplace_back (realt, prifile);
|
||
for (auto &it : prifiles)
|
||
{
|
||
if (it.type == realt) { mappri [realt] = ⁢ break; }
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
// 类型:0: 无效,不许插入,1:语言资源,2:缩放资源,3:两者都有
|
||
// 失败返回 nullptr
|
||
// 注意:获取 1 和 2 对应的 pri 资源,如果不存在会尝试返回 3 的资源。
|
||
// mustreturn 指的是必须返回一个 pri 实例,不管是否符合。这是个没办法的办法
|
||
prifile *get (uint8_t type, bool mustreturn = false)
|
||
{
|
||
type &= 0b11;
|
||
auto it = mappri.find (type);
|
||
if (it != mappri.end ()) return &it->second->priinst;
|
||
if (type != 0b11)
|
||
{
|
||
it = mappri.find (0b11);
|
||
if (it != mappri.end ()) return &it->second->priinst;
|
||
}
|
||
if (!prifiles.empty () && mustreturn) return &prifiles.front ().priinst;
|
||
return nullptr;
|
||
}
|
||
void add_search (const std::vector <std::wstring> &arr)
|
||
{
|
||
std::vector <std::wstring> strresname;
|
||
std::vector <std::wstring> pathresname;
|
||
for (auto &it : arr)
|
||
{
|
||
if (IsMsResourcePrefix (it.c_str ())) strresname.push_back (it);
|
||
else pathresname.push_back (it);
|
||
}
|
||
auto langpri = get (1, true);
|
||
auto scalepri = get (2, true);
|
||
if (langpri) langpri->add_search (strresname);
|
||
if (scalepri) scalepri->add_search (pathresname);
|
||
}
|
||
void add_search (const std::wstring &resname)
|
||
{
|
||
if (IsMsResourcePrefix (resname.c_str ()))
|
||
{
|
||
auto langpri = get (1, true);
|
||
if (langpri) langpri->add_search (resname);
|
||
}
|
||
else
|
||
{
|
||
auto scalepri = get (2, true);
|
||
if (scalepri) scalepri->add_search (resname);
|
||
}
|
||
}
|
||
std::wstring resource (const std::wstring &resname)
|
||
{
|
||
if (IsMsResourcePrefix (resname.c_str ()))
|
||
{
|
||
auto langpri = get (1, true);
|
||
if (langpri) return langpri->resource (resname);
|
||
}
|
||
else
|
||
{
|
||
auto scalepri = get (2, true);
|
||
if (scalepri) return scalepri->resource (resname);
|
||
}
|
||
return L"";
|
||
}
|
||
size_t resources (const std::vector <std::wstring> &resnames, std::map <std::wstring, std::wstring> &output)
|
||
{
|
||
add_search (resnames);
|
||
for (auto &it : resnames) output [it] = resource (it);
|
||
return output.size ();
|
||
}
|
||
std::wstring path (const std::wstring &resname) { return resource (resname); }
|
||
size_t paths (const std::vector <std::wstring> &resnames, std::map <std::wstring, std::wstring> &output) { return resources (resnames, output); }
|
||
std::wstring string (const std::wstring &resname) { return resource (resname); }
|
||
size_t strings (const std::vector <std::wstring> &resnames, std::map <std::wstring, std::wstring> &output) { return resources (resnames, output); }
|
||
void destroy ()
|
||
{
|
||
mappri.clear ();
|
||
prifiles.clear ();
|
||
}
|
||
} prifilebcli;
|
||
#endif
|
||
|
||
#endif |