diff --git a/AppInstallerReset.sln b/AppInstallerReset.sln index 586ab1e..e0e0ff3 100644 --- a/AppInstallerReset.sln +++ b/AppInstallerReset.sln @@ -4,16 +4,25 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "appinstaller", "AppInstallerReset\AppInstallerReset.vcxproj", "{C96219BE-8AFF-4914-8933-B6B7047A94D8}" + ProjectSection(ProjectDependencies) = postProject + {33D91B58-1981-4A3C-B4D1-86EE406CDE12} = {33D91B58-1981-4A3C-B4D1-86EE406CDE12} + {A7753282-AA16-43D9-8ACA-7065239DD702} = {A7753282-AA16-43D9-8ACA-7065239DD702} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pkgread", "pkgread\pkgread.vcxproj", "{A7753282-AA16-43D9-8ACA-7065239DD702}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dlltest", "dlltest\dlltest.vcxproj", "{F5CCB3AB-AC43-432A-862D-4F264760B09B}" ProjectSection(ProjectDependencies) = postProject + {8EAC0230-4990-4E41-8E0F-D641D1561396} = {8EAC0230-4990-4E41-8E0F-D641D1561396} {33D91B58-1981-4A3C-B4D1-86EE406CDE12} = {33D91B58-1981-4A3C-B4D1-86EE406CDE12} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dlltest", "dlltest\dlltest.vcxproj", "{F5CCB3AB-AC43-432A-862D-4F264760B09B}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "priformatcli", "..\priformatcli\priformatcli\priformatcli.vcxproj", "{33D91B58-1981-4A3C-B4D1-86EE406CDE12}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pkgmgr", "pkgmgr\pkgmgr.vcxproj", "{8EAC0230-4990-4E41-8E0F-D641D1561396}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "notice", "notice\notice.vcxproj", "{798ED492-EECE-457D-8FD8-129DA93CE126}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -54,6 +63,18 @@ Global {33D91B58-1981-4A3C-B4D1-86EE406CDE12}.Release|x64.Build.0 = Release|x64 {33D91B58-1981-4A3C-B4D1-86EE406CDE12}.Release|x86.ActiveCfg = Release|Win32 {33D91B58-1981-4A3C-B4D1-86EE406CDE12}.Release|x86.Build.0 = Release|Win32 + {8EAC0230-4990-4E41-8E0F-D641D1561396}.Debug|x64.ActiveCfg = Debug|Win32 + {8EAC0230-4990-4E41-8E0F-D641D1561396}.Debug|x86.ActiveCfg = Debug|Win32 + {8EAC0230-4990-4E41-8E0F-D641D1561396}.Debug|x86.Build.0 = Debug|Win32 + {8EAC0230-4990-4E41-8E0F-D641D1561396}.Release|x64.ActiveCfg = Release|Win32 + {8EAC0230-4990-4E41-8E0F-D641D1561396}.Release|x86.ActiveCfg = Release|Win32 + {8EAC0230-4990-4E41-8E0F-D641D1561396}.Release|x86.Build.0 = Release|Win32 + {798ED492-EECE-457D-8FD8-129DA93CE126}.Debug|x64.ActiveCfg = Debug|Win32 + {798ED492-EECE-457D-8FD8-129DA93CE126}.Debug|x86.ActiveCfg = Debug|Win32 + {798ED492-EECE-457D-8FD8-129DA93CE126}.Debug|x86.Build.0 = Debug|Win32 + {798ED492-EECE-457D-8FD8-129DA93CE126}.Release|x64.ActiveCfg = Release|Win32 + {798ED492-EECE-457D-8FD8-129DA93CE126}.Release|x86.ActiveCfg = Release|Win32 + {798ED492-EECE-457D-8FD8-129DA93CE126}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/dlltest/dlltest.vcxproj b/dlltest/dlltest.vcxproj index 1c8879e..2b864fd 100644 --- a/dlltest/dlltest.vcxproj +++ b/dlltest/dlltest.vcxproj @@ -93,6 +93,7 @@ Console true + $(OutDir)pkgread.lib;$(OutDir)priformatcli.lib;$(OutDir)pkgmgr.lib;%(AdditionalDependencies) @@ -125,7 +126,7 @@ true true true - $(OutDir)pkgread.lib;%(AdditionalDependencies) + $(OutDir)pkgread.lib;$(OutDir)priformatcli.lib;%(AdditionalDependencies) diff --git a/dlltest/main.cpp b/dlltest/main.cpp index 379361b..18a83bd 100644 --- a/dlltest/main.cpp +++ b/dlltest/main.cpp @@ -1,13 +1,18 @@ #include -#include "..\pkgread\pkgread.h" #include #include #include #include +#include +#include "..\priformatcli\priformatcli.h" +#include "..\pkgread\pkgread.h" +#include "..\pkgmgr\pkgmgr.h" void read_package (const std::wstring &filepath) { package_reader pr (filepath); + pr.enable_pri_convert (true); + pr.use_pri (true); std::wcout << L"Is Valid: " << (pr.valid () ? L"true" : L"false") << std::endl; std::wcout << L"Package Type: "; switch (pr.package_type ()) @@ -61,6 +66,7 @@ void read_package (const std::wstring &filepath) std::wcout << L"\tDescription: " << prop.description () << std::endl; std::wcout << L"\tPublisher Display Name: " << prop.publisher_display_name () << std::endl; std::wcout << L"\tLogo: " << prop.logo () << std::endl; + std::wcout << L"\tLogo Base64: " << prop.logo_base64 () << std::endl; std::wcout << L"\tFramework: " << (prop.framework () ? L"true" : L"false") << std::endl; std::wcout << L"\tResource Package: " << (prop.resource_package () ? L"true" : L"false") << std::endl; auto preq = pr.get_prerequisites (); @@ -134,7 +140,9 @@ void read_package (const std::wstring &filepath) std::wcout << L"\tApplication" << cnt ++ << std::endl; for (auto &it_s : it) { - std::wcout << L"\t\t" << it_s.first << L": " << it_s.second << std::endl; + std::wcout << L"\t\t" << it_s.first << L": " << it.newat (it_s.first) << std::endl; + std::wstring base64 = it.newat_base64 (it_s.first); + if (!base64.empty ()) std::wcout << L"\t\t" << it_s.first << L" (Base64): " << base64 << std::endl; } } } @@ -154,20 +162,57 @@ void read_package (const std::wstring &filepath) } } } - +using cbfunc = std::function ; +void ProgressCallback (DWORD dwProgress, void *pCustom) +{ + if (auto func = reinterpret_cast (pCustom)) (*func)(dwProgress); +} +HRESULT AddAppxPackage (const std::wstring path, cbfunc callback, std::wstring &errorcode, std::wstring &detailmsg) +{ + LPWSTR ec = nullptr, dm = nullptr; + struct reltask + { + using endfunc = std::function ; + endfunc endtask = nullptr; + reltask (endfunc et): endtask (et) {} + ~reltask () { if (endtask) endtask (); } + } relt ([=] () { + if (ec) free (ec); + if (dm) free (dm); + }); + HRESULT hr = AddAppxPackageFromPath (path.c_str (), nullptr, DEPOLYOPTION_NONE, ProgressCallback, &callback, &ec, &dm); + errorcode.clear (); + detailmsg.clear (); + if (ec) errorcode = ec; + if (dm) detailmsg = dm; + return hr; +} int main (int argc, char *argv []) { setlocale (LC_ALL, ""); std::wcout.imbue (std::locale ("", LC_CTYPE)); std::wcout << L"Please enter the file path: " << std::endl; std::wcout << L"\\> "; - std::wstring pkgPathStr = L"E:\\Profiles\\Bruce\\Desktop\\resources.pri"; - //std::getline (std::wcin, pkgPathStr); + std::wstring pkgPathStr = L"E:\\Profiles\\Bruce\\Desktop\\Discourse.appx"; + pkgPathStr = L"F:\\BaiduNetdiskDownload\\Collection4\\Microsoft.BingFinance_2015.709.2014.2069_neutral_~_8wekyb3d8bbwe\\FinanceApp_3.0.4.336_x86.appx"; + pkgPathStr = L"F:\\BaiduNetdiskDownload\\Collection4\\Microsoft.BingFinance_2015.709.2014.2069_neutral_~_8wekyb3d8bbwe.appxbundle"; + pkgPathStr = L""; + if (pkgPathStr.empty ()) std::getline (std::wcin, pkgPathStr); pkgPathStr.erase ( std::remove (pkgPathStr.begin (), pkgPathStr.end (), L'\"'), pkgPathStr.end () ); - + std::wcout << L"Installing ..." << std::endl; + std::wstring ec, dm; + HRESULT hr = AddAppxPackage (pkgPathStr, [] (int progress) { + std::wcout << L"\r " << progress << L"%"; + }, ec, dm); + if (SUCCEEDED (hr)) std::wcout << std::endl << L"Installed Successfully." << std::endl; + else + { + std::wcout << std::endl << L"Exception: " << ec << L"(0x" << std::hex << std::setw (8) << std::setfill (L'0') << hr << L")" << std::endl; + std::wcout << L"Detail Message: " << dm << std::endl; + } system ("pause"); return 0; } \ No newline at end of file diff --git a/notice/ReadMe.txt b/notice/ReadMe.txt new file mode 100644 index 0000000..6fbb505 --- /dev/null +++ b/notice/ReadMe.txt @@ -0,0 +1,30 @@ +======================================================================== + 动态链接库:pkgmgr 项目概述 +======================================================================== + +应用程序向导已为您创建了此 pkgmgr DLL。 + +本文件概要介绍组成 pkgmgr 应用程序的每个文件的内容。 + + +pkgmgr.vcxproj + 这是使用应用程序向导生成的 VC++ 项目的主项目文件,其中包含生成该文件的 Visual C++ 的版本信息,以及有关使用应用程序向导选择的平台、配置和项目功能的信息。 + +pkgmgr.vcxproj.filters + 这是使用“应用程序向导”生成的 VC++ 项目筛选器文件。它包含有关项目文件与筛选器之间的关联信息。在 IDE 中,通过这种关联,在特定节点下以分组形式显示具有相似扩展名的文件。例如,“.cpp”文件与“源文件”筛选器关联。 + +pkgmgr.cpp + 这是主 DLL 源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h, StdAfx.cpp + 这些文件用于生成名为 pkgmgr.pch 的预编译头 (PCH) 文件和名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用“TODO:”注释来指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/notice/dllmain.cpp b/notice/dllmain.cpp new file mode 100644 index 0000000..260abc6 --- /dev/null +++ b/notice/dllmain.cpp @@ -0,0 +1,19 @@ +// dllmain.cpp : DLL Ӧóڵ㡣 +#include "stdafx.h" + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + diff --git a/notice/notice.cpp b/notice/notice.cpp new file mode 100644 index 0000000..fb4413b --- /dev/null +++ b/notice/notice.cpp @@ -0,0 +1,39 @@ +// pkgmgr.cpp : DLL Ӧóĵ +// + +#include "stdafx.h" +#include "notice.h" +#include "raii.h" +#include "version.h" + +#undef GetFullPathName +std::wstring GetFullPathName (const std::wstring &lpFileName) +{ + if (lpFileName.empty ()) return L""; + DWORD length = GetFullPathNameW (lpFileName.c_str (), 0, nullptr, nullptr); + if (length == 0) return L""; + std::vector buffer (length + 1, L'\0'); + DWORD result = GetFullPathNameW (lpFileName.c_str (), length, buffer.data (), nullptr); + if (result == 0) return L""; + return std::wstring (buffer.data (), result); +} + +std::wstring g_swExceptionCode = L""; +std::wstring g_swExceptionDetail = L""; + +struct destruct +{ + std::function endtask = nullptr; + destruct (std::function pfunc): endtask (pfunc) {} + ~destruct () { if (endtask) endtask (); } +}; +static std::wstring StringToWString (const std::string &str, UINT codePage = CP_ACP) +{ + if (str.empty ()) return std::wstring (); + int len = MultiByteToWideChar (codePage, 0, str.c_str (), -1, nullptr, 0); + if (len == 0) return std::wstring (); + std::wstring wstr (len - 1, L'\0'); + MultiByteToWideChar (codePage, 0, str.c_str (), -1, &wstr [0], len); + return wstr; +} + diff --git a/notice/notice.h b/notice/notice.h new file mode 100644 index 0000000..ca66229 --- /dev/null +++ b/notice/notice.h @@ -0,0 +1,39 @@ +// ifdef Ǵʹ DLL 򵥵 +// ı׼ DLL еļ϶ PKGMGR_EXPORTS +// űġʹô DLL +// κĿϲӦ˷šԴļаļκĿὫ +// PKGMGR_API ΪǴ DLL ģ DLL ô˺궨 +// ΪDZġ +#ifdef NOTICE_EXPORTS +#define NOTICE_API __declspec(dllexport) +#else +#define NOTICE_API __declspec(dllimport) +#endif + +// API áAppxںУ˾Ϊ˷ֹƵĺ + +#ifdef __cplusplus +extern "C" +{ +#endif +#ifdef __cplusplus +#define _DEFAULT_INIT_VALUE_(_init_value_) = _init_value_ +#ifndef PKGMGR_EXPORTS +#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_) = _init_value_ +#else +#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_) +#endif +#else +#define _DEFAULT_INIT_VALUE_(_init_value_) +#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_) +#endif + +#ifdef _DEFAULT_INIT_VALUE_ +#undef _DEFAULT_INIT_VALUE_ +#endif +#ifdef _DEFAULT_INIT_VALUE_FORFUNC_ +#undef _DEFAULT_INIT_VALUE_FORFUNC_ +#endif +#ifdef __cplusplus +} +#endif diff --git a/notice/notice.vcxproj b/notice/notice.vcxproj new file mode 100644 index 0000000..c46e2d1 --- /dev/null +++ b/notice/notice.vcxproj @@ -0,0 +1,107 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {798ED492-EECE-457D-8FD8-129DA93CE126} + Win32Proj + notice + notice + + + + DynamicLibrary + true + Unicode + v120 + false + + + DynamicLibrary + false + Unicode + v120 + false + + + + + + + + + + + + + + $(VCINSTALLDIR)\vcpackages;$(VCInstallDir)atlmfc\lib;$(VCInstallDir)lib;$(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(ReferencePath) + + + $(VCINSTALLDIR)\vcpackages;$(VCInstallDir)atlmfc\lib;$(VCInstallDir)lib;$(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(ReferencePath) + + + + + NotUsing + Level3 + Disabled + /ZW:nostdlib /FUplatform.winmd /FUwindows.winmd %(AdditionalOptions) + WIN32;_DEBUG;_WINDOWS;_USRDLL;NOTICE_EXPORTS;%(PreprocessorDefinitions) + true + false + + + Windows + true + RequireAdministrator + + + + + NotUsing + Level3 + MaxSpeed + true + true + /ZW:nostdlib /FUplatform.winmd /FUWindows.winmd %(AdditionalOptions) + WIN32;NDEBUG;_WINDOWS;_USRDLL;NOTICE_EXPORTS;%(PreprocessorDefinitions) + true + + + Windows + true + true + true + + + + + + + + + + + + + + + + + + + + 这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 + + + + \ No newline at end of file diff --git a/notice/notice.vcxproj.filters b/notice/notice.vcxproj.filters new file mode 100644 index 0000000..0ea694c --- /dev/null +++ b/notice/notice.vcxproj.filters @@ -0,0 +1,45 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + 源文件 + + + 源文件 + + + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + + + + \ No newline at end of file diff --git a/notice/packages.config b/notice/packages.config new file mode 100644 index 0000000..c2da1c1 --- /dev/null +++ b/notice/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/notice/raii.h b/notice/raii.h new file mode 100644 index 0000000..cc82c4f --- /dev/null +++ b/notice/raii.h @@ -0,0 +1,8 @@ +#pragma once +#include +struct raii +{ + std::function endtask = nullptr; + raii (std::function pFunc = nullptr): endtask (pFunc) {} + ~raii () { if (endtask) endtask (); } +}; \ No newline at end of file diff --git a/notice/stdafx.cpp b/notice/stdafx.cpp new file mode 100644 index 0000000..1945e44 --- /dev/null +++ b/notice/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : ֻ׼ļԴļ +// pkgmgr.pch ΪԤͷ +// stdafx.obj ԤϢ + +#include "stdafx.h" + +// TODO: STDAFX.H κĸͷļ +//ڴļ diff --git a/notice/stdafx.h b/notice/stdafx.h new file mode 100644 index 0000000..0a55300 --- /dev/null +++ b/notice/stdafx.h @@ -0,0 +1,38 @@ +// stdafx.h : ׼ϵͳļİļ +// Ǿʹõĵ +// ضĿİļ +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Windows ͷųʹõ +// Windows ͷļ: +#include + + + +// TODO: ڴ˴óҪͷļ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Microsoft::WRL; +using namespace ABI::Windows::UI::Notifications; +using namespace ABI::Windows::Data::Xml::Dom; +using namespace Microsoft::WRL::Wrappers; + +#include +#include \ No newline at end of file diff --git a/notice/targetver.h b/notice/targetver.h new file mode 100644 index 0000000..416cebf --- /dev/null +++ b/notice/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// SDKDDKVer.h õ߰汾 Windows ƽ̨ + +// ҪΪǰ Windows ƽ̨Ӧó WinSDKVer.h +// _WIN32_WINNT ΪҪֵ֧ƽ̨Ȼٰ SDKDDKVer.h + +#include diff --git a/notice/version.h b/notice/version.h new file mode 100644 index 0000000..5091c21 --- /dev/null +++ b/notice/version.h @@ -0,0 +1,125 @@ +#pragma once +#include +#include +#include +#include +typedef uint64_t UINT64; +typedef int64_t INT64; +typedef uint16_t UINT16; +typedef struct version +{ + UINT16 major = 0, minor = 0, build = 0, revision = 0; + version (UINT64 value): + major ((value >> 0x30) & 0xFFFF), minor ((value >> 0x20) & 0xFFFF), + build ((value >> 0x10) & 0xFFFF), revision ((value) & 0xFFFF) {} + version (UINT16 major, UINT16 minor, UINT16 build, UINT16 revision): + major (major), minor (minor), build (build), revision (revision) {} + version (const std::wstring &verstr) { this->interpret (verstr); } + version (const std::string &verstr) { this->interpret (verstr); } + version () {} + version (const version &other): major (other.major), minor (other.minor), build (other.build), revision (other.revision) {} + version (version &&other): major (other.major), minor (other.minor), build (other.build), revision (other.revision) {} + version &operator = (const version &other) + { + if (this != &other) + { + major = other.major; + minor = other.minor; + build = other.build; + revision = other.revision; + } + return *this; + } + version &operator = (version &&other) + { + if (this != &other) + { + major = other.major; + minor = other.minor; + build = other.build; + revision = other.revision; + } + return *this; + } + version &operator = (UINT64 value) { this->data (value); return *this; } + UINT64 data () const { return (((UINT64)major) << 48) | (((UINT64)minor) << 32) | (((UINT64)build) << 16) | ((UINT64)revision); } + UINT64 data (UINT64 value) + { + major = (value >> 48) & 0xFFFF; + minor = (value >> 32) & 0xFFFF; + build = (value >> 16) & 0xFFFF; + revision = value & 0xFFFF; + return value; + } + std::wstring stringifyw () const + { + std::wstringstream ss; + ss << major << L'.' << minor << L'.' << build << L'.' << revision; + return ss.str (); + } + std::string stringify () const + { + std::stringstream ss; + ss << major << '.' << minor << '.' << build << '.' << revision; + return ss.str (); + } + version &interpret (const std::wstring &verstr) + { + auto result = split (verstr); + if (result.size () > 0) this->major = _wtoi (result [0].c_str ()); + if (result.size () > 1) this->minor = _wtoi (result [1].c_str ()); + if (result.size () > 2) this->build = _wtoi (result [2].c_str ()); + if (result.size () > 3) this->revision = _wtoi (result [3].c_str ()); + return *this; + } + version &interpret (const std::string &verstr) + { + auto result = split (verstr); + if (result.size () > 0) this->major = atoi (result [0].c_str ()); + if (result.size () > 1) this->minor = atoi (result [1].c_str ()); + if (result.size () > 2) this->build = atoi (result [2].c_str ()); + if (result.size () > 3) this->revision = atoi (result [3].c_str ()); + return *this; + } + bool empty () const { return *(UINT64 *)this == 0; } + friend bool operator == (const version &l, const version &r) { return *(UINT64 *)&l == *(UINT64 *)&r; } + friend bool operator == (const version &l, const UINT64 &r) { return l.data () == r; } + friend bool operator == (const UINT64 &r, const version &l) { return l.data () == r; } + friend bool operator < (const version &l, const version &r) { return l.data () < r.data (); } + friend bool operator > (const version &l, const version &r) { return l.data () > r.data (); } + friend bool operator <= (const version &l, const version &r) { return l.data () <= r.data (); } + friend bool operator >= (const version &l, const version &r) { return l.data () >= r.data (); } + friend bool operator != (const version &l, const version &r) { return *(UINT64 *)&l != *(UINT64 *)&r; } + explicit operator bool () const { return !this->empty (); } + bool operator ! () { return this->empty (); } + friend std::ostream &operator << (std::ostream &o, const version &v) { return o << v.major << '.' << v.minor << '.' << v.build << '.' << v.revision; } + friend std::wostream &operator << (std::wostream &o, const version &v) { return o << v.major << '.' << v.minor << '.' << v.build << '.' << v.revision; } + bool equals (const version &r) const { return *this == r; } + INT64 compare (const version &r) const { return this->data () - r.data (); } + static version parse (const std::wstring &value) { return version (value); } + static version parse (const std::string &value) { return version (value); } + static std::wstring stringifyw (const version &v) { return v.stringifyw (); } + static std::string stringify (const version &v) { return v.stringify (); } + static bool equals (const version &l, const version &r) { return l == r; } + static INT64 compare (const version &l, const version &r) { return l.data () - r.data (); } + static version decode (UINT64 value) { return version (value); } + static UINT64 encode (const version &v) { return v.data (); } + protected: + template std::vector split (const StringType &str, typename StringType::value_type delimiter1 = '.', typename StringType::value_type delimiter2 = ',') + { + std::vector result; + std::basic_stringstream ss (str); + StringType segment; + while (std::getline (ss, segment, delimiter1)) + { + size_t pos = 0; + while ((pos = segment.find (delimiter2)) != StringType::npos) + { + result.push_back (segment.substr (0, pos)); + segment.erase (0, pos + 1); + } + if (!segment.empty ()) result.push_back (segment); + } + return result; + } +} Version; \ No newline at end of file diff --git a/pkgmgr/ReadMe.txt b/pkgmgr/ReadMe.txt new file mode 100644 index 0000000..6fbb505 --- /dev/null +++ b/pkgmgr/ReadMe.txt @@ -0,0 +1,30 @@ +======================================================================== + 动态链接库:pkgmgr 项目概述 +======================================================================== + +应用程序向导已为您创建了此 pkgmgr DLL。 + +本文件概要介绍组成 pkgmgr 应用程序的每个文件的内容。 + + +pkgmgr.vcxproj + 这是使用应用程序向导生成的 VC++ 项目的主项目文件,其中包含生成该文件的 Visual C++ 的版本信息,以及有关使用应用程序向导选择的平台、配置和项目功能的信息。 + +pkgmgr.vcxproj.filters + 这是使用“应用程序向导”生成的 VC++ 项目筛选器文件。它包含有关项目文件与筛选器之间的关联信息。在 IDE 中,通过这种关联,在特定节点下以分组形式显示具有相似扩展名的文件。例如,“.cpp”文件与“源文件”筛选器关联。 + +pkgmgr.cpp + 这是主 DLL 源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h, StdAfx.cpp + 这些文件用于生成名为 pkgmgr.pch 的预编译头 (PCH) 文件和名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用“TODO:”注释来指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/pkgmgr/dllmain.cpp b/pkgmgr/dllmain.cpp new file mode 100644 index 0000000..260abc6 --- /dev/null +++ b/pkgmgr/dllmain.cpp @@ -0,0 +1,19 @@ +// dllmain.cpp : DLL Ӧóڵ㡣 +#include "stdafx.h" + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + diff --git a/pkgmgr/pkgmgr.cpp b/pkgmgr/pkgmgr.cpp new file mode 100644 index 0000000..2e5f9e6 --- /dev/null +++ b/pkgmgr/pkgmgr.cpp @@ -0,0 +1,629 @@ +// pkgmgr.cpp : DLL Ӧóĵ +// + +#include "stdafx.h" +#include "pkgmgr.h" +#include "raii.h" +#include "version.h" + +#undef GetFullPathName +std::wstring GetFullPathName (const std::wstring &lpFileName) +{ + if (lpFileName.empty ()) return L""; + DWORD length = GetFullPathNameW (lpFileName.c_str (), 0, nullptr, nullptr); + if (length == 0) return L""; + std::vector buffer (length + 1, L'\0'); + DWORD result = GetFullPathNameW (lpFileName.c_str (), length, buffer.data (), nullptr); + if (result == 0) return L""; + return std::wstring (buffer.data (), result); +} + +std::wstring g_swExceptionCode = L""; +std::wstring g_swExceptionDetail = L""; + +struct destruct +{ + std::function endtask = nullptr; + destruct (std::function pfunc): endtask (pfunc) {} + ~destruct () { if (endtask) endtask (); } +}; +static std::wstring StringToWString (const std::string &str, UINT codePage = CP_ACP) +{ + if (str.empty ()) return std::wstring (); + int len = MultiByteToWideChar (codePage, 0, str.c_str (), -1, nullptr, 0); + if (len == 0) return std::wstring (); + std::wstring wstr (len - 1, L'\0'); + MultiByteToWideChar (codePage, 0, str.c_str (), -1, &wstr [0], len); + return wstr; +} +using onprogress = AsyncOperationProgressHandler ; +using onprogresscomp = AsyncOperationWithProgressCompletedHandler ; +using progressopt = IAsyncOperationWithProgress ^; +template HRESULT RunPackageManagerOperation (TAsyncOpCreator asyncCreator, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + g_swExceptionCode = L""; + g_swExceptionDetail = L""; + if (pErrorCode) *pErrorCode = nullptr; + if (pDetailMsg) *pDetailMsg = nullptr; + try + { + HANDLE hCompEvt = nullptr; + destruct closeevt ([&hCompEvt] () { + if (hCompEvt) { CloseHandle (hCompEvt); hCompEvt = nullptr; } + }); + hCompEvt = CreateEventExW (nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); + if (!hCompEvt) return E_FAIL; + auto depopt = asyncCreator (); + depopt->Progress = ref new onprogress ([pfCallback, pCustom] (progressopt operation, DeploymentProgress progress) { + if (pfCallback) pfCallback ((DWORD)progress.percentage, pCustom); + }); + depopt->Completed = ref new onprogresscomp ([&hCompEvt] (progressopt, AsyncStatus) { + SetEvent (hCompEvt); + }); + WaitForSingleObject (hCompEvt, INFINITE); + switch (depopt->Status) + { + case AsyncStatus::Completed: + return S_OK; + case AsyncStatus::Error: + { + auto depresult = depopt->GetResults (); + auto errorcode = depopt->ErrorCode; + HResult hr = errorcode; + String ^errstr = Exception::CreateException (errorcode.Value)->ToString (); + g_swExceptionCode += errstr && errstr->Data () ? errstr->Data () : L""; + g_swExceptionDetail += depresult->ErrorText->Data (); + if (pErrorCode) *pErrorCode = _wcsdup (g_swExceptionCode.c_str ()); + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return (HRESULT)errorcode.Value; + } + case AsyncStatus::Canceled: + g_swExceptionDetail = L"Installation Canceled"; + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return E_ABORT; + case AsyncStatus::Started: + g_swExceptionDetail = L"Installation is Running"; + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return E_PENDING; + } + } + catch (Exception ^e) + { + g_swExceptionDetail = e->ToString ()->Data (); + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return (SUCCEEDED ((HRESULT)e->HResult) ? E_FAIL : (HRESULT)e->HResult); + } + catch (const std::exception &e) + { + g_swExceptionDetail = StringToWString (e.what () ? e.what () : "Unknown exception."); + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return E_FAIL; + } + catch (...) + { + g_swExceptionDetail = L"Unknown exception"; + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return E_FAIL; + } + return E_FAIL; +} +[MTAThread] +HRESULT AddAppxPackageFromURI (LPCWSTR lpPkgFileUri, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUrlList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + return RunPackageManagerOperation ([=] () { + auto pkgmgr = ref new PackageManager (); + auto depuris = ref new Platform::Collections::Vector (); + if (alpDepUrlList) + { + for (size_t i = 0; i < alpDepUrlList->dwSize; i ++) + { + auto &pstr = alpDepUrlList->alpDepUris [i]; + try + { + if (pstr && *pstr) + { + auto depuristr = ref new String (pstr); + Uri ^duri = nullptr; + try { duri = ref new Uri (depuristr); } + catch (Exception ^e) + { + try + { + std::wstring fullpath = GetFullPathName (pstr ? pstr : L""); + if (fullpath.empty ()) fullpath = pstr ? pstr : L""; + duri = ref new Uri (ref new String (fullpath.c_str ())); + } + catch (Exception ^e) { continue; } + } + depuris->Append (duri); + } + } + catch (Exception ^e) { continue; } + } + } + if (depuris->Size > 0) depuris = nullptr; + auto ope = pkgmgr->AddPackageAsync (ref new Uri (ref new String (lpPkgFileUri)), depuris, (DeploymentOptions)dwDeployOption); + return ope; + }, pfCallback, pCustom, pErrorCode, pDetailMsg); +} +[MTAThread] +HRESULT AddAppxPackageFromPath (LPCWSTR lpPkgPath, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUrlList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + std::wstring fullpath = GetFullPathName (lpPkgPath ? lpPkgPath : L""); + if (fullpath.empty ()) fullpath = lpPkgPath ? lpPkgPath : L""; + return AddAppxPackageFromURI (fullpath.c_str (), alpDepUrlList, dwDeployOption, pfCallback, pCustom, pErrorCode, pDetailMsg); +} +std::wstring WinRTStringToStdString (String ^pstr) +{ + try { if (!pstr) return L""; return (pstr->Data () ? pstr->Data () : L""); } + catch (...) {} return L""; +} +#define PlatformGetStringValue(mpObj, _prop_) \ + ([&] () -> std::wstring { \ + auto strptr = (mpObj)->_prop_; \ + return WinRTStringToStdString (strptr); \ + }) () +void SidToAccountName (const std::wstring &sidString, std::wstring &stringSid) +{ + PSID sid = nullptr; + raii lrel ([&sid] () { + if (sid) LocalFree (sid); + sid = nullptr; + }); + if (ConvertStringSidToSidW (sidString.c_str (), &sid)) + { + DWORD nameCharCount = 0; + DWORD domainNameCharCount = 0; + SID_NAME_USE sidType; + LookupAccountSidW (nullptr, sid, nullptr, &nameCharCount, nullptr, &domainNameCharCount, &sidType); + std::vector namebuf (nameCharCount + 1); + std::vector domainNameBuf (domainNameCharCount + 1); + ZeroMemory (namebuf.data (), (nameCharCount + 1) * sizeof (WCHAR)); + ZeroMemory (domainNameBuf.data (), (domainNameCharCount + 1) * sizeof (WCHAR)); + if (LookupAccountSidW (nullptr, sid, namebuf.data (), &nameCharCount, domainNameBuf.data (), &domainNameCharCount, &sidType)) + { + stringSid = domainNameBuf.data (); + stringSid += stringSid + L"\\" + namebuf.data (); + } + } + if (stringSid.length () == 0) stringSid = sidString; +} +struct pkg_info +{ + struct identity + { + std::wstring name = L""; + std::wstring publisher = L""; + std::wstring fullname = L""; + std::wstring familyname = L""; + std::wstring resourceid = L""; + std::wstring publisherid = L""; + uint16_t architecture = -1; + Version version; + } id; + struct properities + { + std::wstring displayname = L""; + std::wstring description = L""; + std::wstring publisher = L""; + std::wstring logo = L""; + bool framework = false; + bool resource_package = false; + } prop; + bool bundle = false; + bool development_mode = false; + std::wstring installlocation = L""; + std::wstring users = L""; + std::wstring sids = L""; + std::vector dependencies; + static pkg_info parse (Windows::ApplicationModel::Package ^pkg, Windows::Management::Deployment::PackageManager ^mgr) + { + pkg_info pi; + if (!pkg) throw ref new InvalidArgumentException ("No package found."); + #define WAPParseSetValue(_left_part_, _right_part_, _default_value_) \ + do { try { _left_part_ = _right_part_; } catch (...) { _left_part_ = _default_value_; } } while (false) + #define WAPParseSetStringValue(_left_part_, _right_part_) \ + WAPParseSetValue (_left_part_, WinRTStringToStdString (_right_part_), L"") + WAPParseSetStringValue (pi.id.name, pkg->Id->Name); + WAPParseSetStringValue (pi.id.publisher, pkg->Id->Publisher); + WAPParseSetStringValue (pi.id.fullname, pkg->Id->FullName); + WAPParseSetStringValue (pi.id.familyname, pkg->Id->FamilyName); + WAPParseSetStringValue (pi.id.publisherid, pkg->Id->PublisherId); + WAPParseSetStringValue (pi.id.resourceid, pkg->Id->ResourceId); + try { pi.id.version = version (pkg->Id->Version.Major, pkg->Id->Version.Minor, pkg->Id->Version.Build, pkg->Id->Version.Revision); } catch (...) {} + WAPParseSetValue (pi.id.architecture, (WORD)pkg->Id->Architecture, (WORD)-1); + WAPParseSetStringValue (pi.prop.displayname, pkg->DisplayName); + WAPParseSetStringValue (pi.prop.description, pkg->Description); + WAPParseSetStringValue (pi.prop.publisher, pkg->PublisherDisplayName); + WAPParseSetStringValue (pi.prop.logo, pkg->Logo->ToString ()); + WAPParseSetValue (pi.prop.framework, pkg->IsFramework, false); + WAPParseSetValue (pi.prop.resource_package, pkg->IsResourcePackage, false); + WAPParseSetValue (pi.bundle, pkg->IsBundle, false); + WAPParseSetValue (pi.development_mode, pkg->IsDevelopmentMode, false); + WAPParseSetStringValue (pi.installlocation, pkg->InstalledLocation->Path); + try + { + size_t i = 0; + auto users = mgr->FindUsers (pkg->Id->FullName); + for (auto it : users) + { + { + std::wstring sid = L""; + SidToAccountName (it->UserSecurityId->Data (), sid); + if (i) pi.users += L';'; + pi.users += sid; + } + { + std::wstring sid; + WAPParseSetStringValue (sid, it->UserSecurityId); + if (i) pi.sids += L';'; + pi.users += sid; + } + i ++; + } + } + catch (...) {} + try + { + auto deps = pkg->Dependencies; + for (auto it : deps) + { + auto deppkg = pkg_info::parse (it, mgr); + deppkg.dependencies.clear (); + pi.dependencies.push_back (deppkg); + } + } + catch (...) {} + return pi; + #ifdef WAPParseSetStringValue + #undef WAPParseSetStringValue + #endif + #ifdef WAPParseSetValue + #undef WAPParseSetValue + #endif + } + // صķǻΪԽṹҪ̬롣ܳ + void to_c_struct (std::vector &bytesret) const + { + bytesret.clear (); + bytesret.resize (sizeof (FIND_PACKAGE_INFO) * (this->dependencies.size () + 1)); + FIND_PACKAGE_INFO &fpi = *(FIND_PACKAGE_INFO *)bytesret.data (); + fpi.piIdentity.lpFamilyName = this->id.familyname.c_str (); + fpi.piIdentity.lpFullName = this->id.fullname.c_str (); + fpi.piIdentity.lpName = this->id.name.c_str (); + fpi.piIdentity.lpPublisher = this->id.publisher.c_str (); + fpi.piIdentity.lpPublisherId = this->id.publisherid.c_str (); + fpi.piIdentity.lpResourceId = this->id.resourceid.c_str (); + fpi.piIdentity.qwVersion = this->id.version.data (); + fpi.piIdentity.wProcessArchitecture = this->id.architecture; + fpi.piProperties.bIsBundle = this->bundle; + fpi.piProperties.bIsDevelopmentMode = this->development_mode; + fpi.piProperties.bIsFramework = this->prop.framework; + fpi.piProperties.bIsResourcePackage = this->prop.resource_package; + fpi.piProperties.lpDescription = this->prop.description.c_str (); + fpi.piProperties.lpDisplayName = this->prop.displayname.c_str (); + fpi.piProperties.lpLogoUri = this->prop.logo.c_str (); + fpi.piProperties.lpPublisher = this->prop.publisher.c_str (); + fpi.dwDependencesSize = this->dependencies.size (); + fpi.lpInstallLocation = this->installlocation.c_str (); + fpi.lpUsers = this->users.c_str (); + FIND_PACKAGE_INFO *deps = (FIND_PACKAGE_INFO *)&fpi.ullBuffer; + for (size_t i = 0; i < this->dependencies.size (); i ++) + { + std::vector depbytes; + this->dependencies [i].to_c_struct (depbytes); + deps [i] = *(FIND_PACKAGE_INFO *)depbytes.data (); + } + } +}; +[STAThread] +HRESULT FindAppxPackageByCallback (std::function pfCallback, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + g_swExceptionCode = L""; + g_swExceptionDetail = L""; + try + { + auto pkgmgr = ref new PackageManager (); + auto pkgarr = pkgmgr->FindPackages (); + for (auto pkg : pkgarr) + { + auto pkginfo = pkg_info::parse (pkg, pkgmgr); + if (pfCallback) pfCallback (pkginfo); + } + return S_OK; + } + catch (AccessDeniedException ^e) + { + g_swExceptionDetail = e->ToString ()->Data (); + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return (SUCCEEDED ((HRESULT)e->HResult) ? E_FAIL : (HRESULT)e->HResult); + } + catch (Exception ^e) + { + g_swExceptionDetail = e->ToString ()->Data (); + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return (SUCCEEDED ((HRESULT)e->HResult) ? E_FAIL : (HRESULT)e->HResult); + } + catch (const std::exception &e) + { + g_swExceptionDetail = StringToWString (e.what () ? e.what () : "Unknown exception."); + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return E_FAIL; + } + catch (...) + { + g_swExceptionDetail = L"Unknown exception"; + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return E_FAIL; + } + return E_FAIL; +} +[STAThread] +HRESULT GetAppxPackages (PKGMGR_FINDENUMCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + return FindAppxPackageByCallback ([&pCustom, &pfCallback] (pkg_info &pi) { + std::vector bytes; + pi.to_c_struct (bytes); + if (pfCallback) pfCallback ((FIND_PACKAGE_INFO *)bytes.data (), pCustom); + }, pErrorCode, pDetailMsg); +} +[MTAThread] +HRESULT RemoveAppxPackage (LPCWSTR lpPkgFullName, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + return RunPackageManagerOperation ([=] () { + auto pkgmgr = ref new PackageManager (); + return pkgmgr->RemovePackageAsync (ref new String (lpPkgFullName)); + }, pfCallback, pCustom, pErrorCode, pDetailMsg); +} +[MTAThread] +HRESULT CleanupAppxPackage (LPCWSTR lpPkgName, LPCWSTR lpUserSID, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + return RunPackageManagerOperation ([=] () { + auto pkgmgr = ref new PackageManager (); + return pkgmgr->CleanupPackageForUserAsync (ref new String (lpPkgName), ref new String (lpUserSID)); + }, pfCallback, pCustom, pErrorCode, pDetailMsg); +} +[MTAThread] +HRESULT RegisterAppxPackageByUri (LPCWSTR lpManifestUri, PCREGISTER_PACKAGE_DEFENDENCIES alpDependencyUriList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + return RunPackageManagerOperation ([=] () { + auto pkgmgr = ref new PackageManager (); + auto depuris = ref new Platform::Collections::Vector (); + if (alpDependencyUriList) + { + for (size_t i = 0; i < alpDependencyUriList->dwSize; i ++) + { + auto &pstr = alpDependencyUriList->alpDepUris [i]; + try + { + if (pstr && *pstr) + { + auto depuristr = ref new String (pstr); + Uri ^duri = nullptr; + try { duri = ref new Uri (depuristr); } + catch (Exception ^e) + { + try + { + std::wstring fullpath = GetFullPathName (pstr ? pstr : L""); + if (fullpath.empty ()) fullpath = pstr ? pstr : L""; + duri = ref new Uri (ref new String (fullpath.c_str ())); + } + catch (Exception ^e) { continue; } + } + depuris->Append (duri); + } + } + catch (Exception ^e) { continue; } + } + } + if (depuris->Size > 0) depuris = nullptr; + return pkgmgr->RegisterPackageAsync (ref new Uri (ref new String (lpManifestUri)), depuris, (DeploymentOptions)dwDeployOption); + }, pfCallback, pCustom, pErrorCode, pDetailMsg); +} +[MTAThread] +HRESULT RegisterAppxPackageByPath (LPCWSTR lpManifestPath, PCREGISTER_PACKAGE_DEFENDENCIES alpDependencyUriList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + std::wstring fullpath = GetFullPathName (lpManifestPath ? lpManifestPath : L""); + if (fullpath.empty ()) fullpath = lpManifestPath ? lpManifestPath : L""; + return RegisterAppxPackageByPath (fullpath.c_str (), alpDependencyUriList, dwDeployOption, pfCallback, pCustom, pErrorCode, pDetailMsg); +} +[MTAThread] +HRESULT RegisterAppxPackageByFullName (LPCWSTR lpPackageFullName, PCREGISTER_PACKAGE_DEFENDENCIES alpDepFullNameList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + return RunPackageManagerOperation ([=] () { + auto pkgmgr = ref new PackageManager (); + auto depuris = ref new Platform::Collections::Vector (); + if (alpDepFullNameList) + { + for (size_t i = 0; i < alpDepFullNameList->dwSize; i ++) + { + auto &pstr = alpDepFullNameList->alpDepUris [i]; + try { if (pstr && *pstr) depuris->Append (ref new String (pstr)); } + catch (Exception ^e) { continue; } + } + } + if (depuris->Size > 0) depuris = nullptr; + return pkgmgr->RegisterPackageByFullNameAsync (ref new String (lpPackageFullName), depuris, (DeploymentOptions)dwDeployOption); + }, pfCallback, pCustom, pErrorCode, pDetailMsg); +} +template HRESULT ExecPackageManagerFunctionNoReturn (TFunction func, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + g_swExceptionCode = L""; + g_swExceptionDetail = L""; + try + { + func (); + return S_OK; + } + catch (Exception ^e) + { + g_swExceptionDetail = e->ToString ()->Data (); + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return (SUCCEEDED ((HRESULT)e->HResult) ? E_FAIL : (HRESULT)e->HResult); + } + catch (const std::exception &e) + { + g_swExceptionDetail = StringToWString (e.what () ? e.what () : "Unknown exception."); + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return E_FAIL; + } + catch (...) + { + g_swExceptionDetail = L"Unknown exception"; + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return E_FAIL; + } + return E_FAIL; +} +[STAThread] +HRESULT SetAppxPackageStatus (LPCWSTR lpPackageFullName, DWORD dwStatus, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + return ExecPackageManagerFunctionNoReturn ([=] () { + auto pkgmgr = ref new PackageManager (); + pkgmgr->SetPackageState (ref new String (lpPackageFullName), (Windows::Management::Deployment::PackageState)dwStatus); + }, pErrorCode, pDetailMsg); +} +[MTAThread] +HRESULT StageAppxPackageFromURI (LPCWSTR lpFileUri, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUriList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + return RunPackageManagerOperation ([=] () { + auto pkgmgr = ref new PackageManager (); + auto depuris = ref new Platform::Collections::Vector (); + if (alpDepUriList) + { + for (size_t i = 0; i < alpDepUriList->dwSize; i ++) + { + auto &pstr = alpDepUriList->alpDepUris [i]; + try + { + if (pstr && *pstr) + { + auto depuristr = ref new String (pstr); + Uri ^duri = nullptr; + try { duri = ref new Uri (depuristr); } + catch (Exception ^e) + { + try + { + std::wstring fullpath = GetFullPathName (pstr ? pstr : L""); + if (fullpath.empty ()) fullpath = pstr ? pstr : L""; + duri = ref new Uri (ref new String (fullpath.c_str ())); + } + catch (Exception ^e) { continue; } + } + depuris->Append (duri); + } + } + catch (Exception ^e) { continue; } + } + } + if (depuris->Size > 0) depuris = nullptr; + return pkgmgr->StagePackageAsync (ref new Uri (ref new String (lpFileUri)), depuris, (DeploymentOptions)dwDeployOption); + }, pfCallback, pCustom, pErrorCode, pDetailMsg); +} +[MTAThread] +HRESULT StageAppxPackageFromPath (LPCWSTR lpPkgPath, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUriList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + std::wstring fullpath = GetFullPathName (lpPkgPath ? lpPkgPath : L""); + if (fullpath.empty ()) fullpath = lpPkgPath ? lpPkgPath : L""; + return StageAppxPackageFromPath (fullpath.c_str (), alpDepUriList, dwDeployOption, pfCallback, pCustom, pErrorCode, pDetailMsg); +} +[MTAThread] +HRESULT StageAppxUserData (LPCWSTR lpPackageFullName, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + return RunPackageManagerOperation ([=] () { + auto pkgmgr = ref new PackageManager (); + return pkgmgr->StageUserDataAsync (ref new String (lpPackageFullName)); + }, pfCallback, pCustom, pErrorCode, pDetailMsg); +} +[MTAThread] +HRESULT UpdateAppxPackageFromURI (LPCWSTR lpPkgFileUri, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUrlList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + return RunPackageManagerOperation ([=] () { + auto pkgmgr = ref new PackageManager (); + auto depuris = ref new Platform::Collections::Vector (); + if (alpDepUrlList) + { + for (size_t i = 0; i < alpDepUrlList->dwSize; i ++) + { + auto &pstr = alpDepUrlList->alpDepUris [i]; + try + { + if (pstr && *pstr) + { + auto depuristr = ref new String (pstr); + Uri ^duri = nullptr; + try { duri = ref new Uri (depuristr); } + catch (Exception ^e) + { + try + { + std::wstring fullpath = GetFullPathName (pstr ? pstr : L""); + if (fullpath.empty ()) fullpath = pstr ? pstr : L""; + duri = ref new Uri (ref new String (fullpath.c_str ())); + } + catch (Exception ^e) { continue; } + } + depuris->Append (duri); + } + } + catch (Exception ^e) { continue; } + } + } + if (depuris->Size > 0) depuris = nullptr; + return pkgmgr->UpdatePackageAsync (ref new Uri (ref new String (lpPkgFileUri)), depuris, (DeploymentOptions)dwDeployOption); + }, pfCallback, pCustom, pErrorCode, pDetailMsg); +} +[MTAThread] +HRESULT UpdateAppxPackageFromPath (LPCWSTR lpPkgPath, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUrlList, DWORD dwDeployOption, PKGMRR_PROGRESSCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + std::wstring fullpath = GetFullPathName (lpPkgPath ? lpPkgPath : L""); + if (fullpath.empty ()) fullpath = lpPkgPath ? lpPkgPath : L""; + return UpdateAppxPackageFromURI (fullpath.c_str (), alpDepUrlList, dwDeployOption, pfCallback, pCustom, pErrorCode, pDetailMsg); +} +[STAThread] +HRESULT FindAppxPackage (LPCWSTR lpPackageFullName, PKGMGR_FINDENUMCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + g_swExceptionCode = L""; + g_swExceptionDetail = L""; + try + { + auto pkgmgr = ref new PackageManager (); + auto pkg = pkgmgr->FindPackage (ref new String (lpPackageFullName)); + auto pkginfo = pkg_info::parse (pkg, pkgmgr); + std::vector bytes; + pkginfo.to_c_struct (bytes); + if (pfCallback) pfCallback ((FIND_PACKAGE_INFO *)bytes.data (), pCustom); + return S_OK; + } + catch (AccessDeniedException ^e) + { + g_swExceptionDetail = e->ToString ()->Data (); + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return (SUCCEEDED ((HRESULT)e->HResult) ? E_FAIL : (HRESULT)e->HResult); + } + catch (Exception ^e) + { + g_swExceptionDetail = e->ToString ()->Data (); + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return (SUCCEEDED ((HRESULT)e->HResult) ? E_FAIL : (HRESULT)e->HResult); + } + catch (const std::exception &e) + { + g_swExceptionDetail = StringToWString (e.what () ? e.what () : "Unknown exception."); + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return E_FAIL; + } + catch (...) + { + g_swExceptionDetail = L"Unknown exception"; + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return E_FAIL; + } + return E_FAIL; +} +[STAThread] +LPCWSTR GetPackageManagerLastErrorCode () { return g_swExceptionCode.c_str (); } +[STAThread] +LPCWSTR GetPackageManagerLastErrorDetailMessage () { return g_swExceptionDetail.c_str (); } \ No newline at end of file diff --git a/pkgmgr/pkgmgr.h b/pkgmgr/pkgmgr.h new file mode 100644 index 0000000..551f86d --- /dev/null +++ b/pkgmgr/pkgmgr.h @@ -0,0 +1,192 @@ +// ifdef Ǵʹ DLL 򵥵 +// ı׼ DLL еļ϶ PKGMGR_EXPORTS +// űġʹô DLL +// κĿϲӦ˷šԴļаļκĿὫ +// PKGMGR_API ΪǴ DLL ģ DLL ô˺궨 +// ΪDZġ +#ifdef PKGMGR_EXPORTS +#define PKGMGR_API __declspec(dllexport) +#else +#define PKGMGR_API __declspec(dllimport) +#endif + +// API áAppxںУ˾Ϊ˷ֹƵĺ + +#ifdef __cplusplus +extern "C" +{ +#endif +#ifdef __cplusplus +#define _DEFAULT_INIT_VALUE_(_init_value_) = _init_value_ +#ifndef PKGMGR_EXPORTS +#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_) = _init_value_ +#else +#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_) +#endif +#else +#define _DEFAULT_INIT_VALUE_(_init_value_) +#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_) +#endif + + // ȻصpCustom ԴԶ + typedef void (*PKGMRR_PROGRESSCALLBACK) (DWORD dwProgress, void *pCustom); + +#define PKGMGR_RESULT_OK S_OK +#define PKGMGR_RESULT_ERROR E_FAIL +#define PKGMGR_RESULT_CANCEL E_ABORT +#define PKGMGR_RESULT_STARTED E_PENDING + + typedef struct _REGISTER_PACKAGE_DEFENDENCIES + { + DWORD dwSize _DEFAULT_INIT_VALUE_ (0); + LPWSTR alpDepUris [1]; + } REGISTER_PACKAGE_DEFENDENCIES, *PREGISTER_PACKAGE_DEFENDENCIES; + typedef const REGISTER_PACKAGE_DEFENDENCIES CREGISTER_PACKAGE_DEFENDENCIES, *PCREGISTER_PACKAGE_DEFENDENCIES; + + // ֵ Windows::Management::Deployment::DeploymentOptions һһӦҪд API + // ֻˡ + // ɲĵ https://learn.microsoft.com/zh-cn/uwp/api/windows.management.deployment.deploymentoptions?view=winrt-26100 + + // ôѡʱӦýڿģʽ°װ йؿģʽϢ ע + // ʹôѡùؼӦÿܽѡʹá + // ѡһʹãýERROR_INSTALL_FAILED +#define DEPOLYOPTION_FORCE_APP_SHUTDOWN 0x00000001 + // ǰʹô˰ڴ˰κΰǿƹرðḶ̌ԱԼעᡣ +#define DEPOLYOPTION_DEVELOPMENT_MODE 0x00000002 + // ôѡʱָʾӦԴԼ顣 Чݴעûݸ Դ + // ǿƶааԡ ûעаԴ + // Windows +#define DEPOLYOPTION_INSTALL_ALL_RESOURCES 0x00000020 + // ʹĬΪ +#define DEPOLYOPTION_NONE 0x00000000 + // װһ Appx/AppxBundle/Msix/MsixBundle + // ע⣺ļ·Ϊ DOS/NT 磺C:\Windows\... + // ú PowerShell Add-AppxPackage + // dwDeployOption DEPOLYOPTION_* + // ĴϢ free ͷ + PKGMGR_API HRESULT AddAppxPackageFromPath (LPCWSTR lpPkgPath, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUrlList _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), DWORD dwDeployOption _DEFAULT_INIT_VALUE_FORFUNC_ (DEPOLYOPTION_NONE), PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL)); + // װһ Appx/AppxBundle/Msix/MsixBundle + // ע⣺ļ·Ϊ URI + // ú PowerShell Add-AppxPackage + // dwDeployOption DEPOLYOPTION_* + // ĴϢ free ͷ + PKGMGR_API HRESULT AddAppxPackageFromURI (LPCWSTR lpFileUri, PCREGISTER_PACKAGE_DEFENDENCIES alpDepFullNameList _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), DWORD dwDeployOption _DEFAULT_INIT_VALUE_FORFUNC_ (DEPOLYOPTION_NONE), PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL)); + + typedef struct _FIND_PACKAGE_ID + { + UINT64 qwVersion _DEFAULT_INIT_VALUE_ (0); + // x86: 0 + // x64: 9 + // Arm: 5 + // Neutral: 11 + // Arm64: 12 + // Unknown: 65535(-1) + WORD wProcessArchitecture _DEFAULT_INIT_VALUE_ ((WORD)-1); + WORD wPadding [3]; + LPCWSTR lpName _DEFAULT_INIT_VALUE_ (NULL); + LPCWSTR lpFullName _DEFAULT_INIT_VALUE_ (NULL); + LPCWSTR lpFamilyName _DEFAULT_INIT_VALUE_ (NULL); + LPCWSTR lpPublisher _DEFAULT_INIT_VALUE_ (NULL); + LPCWSTR lpPublisherId _DEFAULT_INIT_VALUE_ (NULL); + LPCWSTR lpResourceId _DEFAULT_INIT_VALUE_ (NULL); + } FIND_PACKAGE_ID, *PFIND_PACKAGE_ID; + typedef struct _FIND_PACKAGE_PROPERTIES + { + LPCWSTR lpDisplayName _DEFAULT_INIT_VALUE_ (NULL); + LPCWSTR lpDescription _DEFAULT_INIT_VALUE_ (NULL); + LPCWSTR lpPublisher _DEFAULT_INIT_VALUE_ (NULL); + LPCWSTR lpLogoUri _DEFAULT_INIT_VALUE_ (NULL); + BOOL bIsFramework _DEFAULT_INIT_VALUE_ (FALSE); + BOOL bIsResourcePackage _DEFAULT_INIT_VALUE_ (FALSE); + BOOL bIsBundle _DEFAULT_INIT_VALUE_ (FALSE); + BOOL bIsDevelopmentMode _DEFAULT_INIT_VALUE_ (FALSE); + } FIND_PACKAGE_PROPERTIES, *PFIND_PACKAGE_PROPERTIES; + typedef struct _FIND_PACKAGE_INFO + { + FIND_PACKAGE_ID piIdentity; + FIND_PACKAGE_PROPERTIES piProperties; + LPCWSTR lpInstallLocation _DEFAULT_INIT_VALUE_ (NULL); + // û ";" ָ + LPCWSTR lpUsers _DEFAULT_INIT_VALUE_ (NULL); + // û ";" ָ + LPCWSTR lpSIDs _DEFAULT_INIT_VALUE_ (NULL); + DWORD dwDependencesSize _DEFAULT_INIT_VALUE_ (0); + // 壬ڴ + DWORD dwPadding _DEFAULT_INIT_VALUE_ (0); + // 壬̬֮ͨڴ淽ʽд顣 + UINT64 ullBuffer _DEFAULT_INIT_VALUE_ (0); + } FIND_PACKAGE_INFO, *PFIND_PACKAGE_INFO; + typedef const FIND_PACKAGE_INFO CFIND_PACKAGE_INFO, *LPCFIND_PACKAGE_INFO; + // עصʱָ벻Ҫֶͷ + typedef void (*PKGMGR_FINDENUMCALLBACK) (LPCFIND_PACKAGE_INFO pNowItem, void *pCustom); + // ͨصȡаϢصԶݡصֵжǷɹ + // ú PowerShell Get-AppxPackage + // ע⣺صаϢ޷޸ģҲͷšźִԶͷšҪڻصпһݡ + // ĴϢ free ͷ + PKGMGR_API HRESULT GetAppxPackages (PKGMGR_FINDENUMCALLBACK pfCallback, void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL)); + // ƳһѾװϵӦáע⣺ǰ + // ĴϢ free ͷ + PKGMGR_API HRESULT RemoveAppxPackage (LPCWSTR lpPkgFullName, PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL)); + // ָûָ ɾûûļΪûװİ + // ĴϢ free ͷ + PKGMGR_API HRESULT CleanupAppxPackage (LPCWSTR lpPkgName, LPCWSTR lpUserSID, PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL)); + + // עӦð + // dwDeployOption DEPOLYOPTION_* + PKGMGR_API HRESULT RegisterAppxPackageByPath (LPCWSTR lpManifestPath, PCREGISTER_PACKAGE_DEFENDENCIES alpDependencyUriList _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), DWORD dwDeployOption _DEFAULT_INIT_VALUE_FORFUNC_ (DEPOLYOPTION_NONE), PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL)); + // עӦð + // dwDeployOption DEPOLYOPTION_* + PKGMGR_API HRESULT RegisterAppxPackageByUri (LPCWSTR lpManifestUri, PCREGISTER_PACKAGE_DEFENDENCIES alpDependencyUriList _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), DWORD dwDeployOption _DEFAULT_INIT_VALUE_FORFUNC_ (DEPOLYOPTION_NONE), PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL)); + // עӦð + // dwDeployOption DEPOLYOPTION_* + PKGMGR_API HRESULT RegisterAppxPackageByFullName (LPCWSTR lpPackageFullName, PCREGISTER_PACKAGE_DEFENDENCIES alpDepFullNameList _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), DWORD dwDeployOption _DEFAULT_INIT_VALUE_FORFUNC_ (DEPOLYOPTION_NONE), PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL)); + + // https://learn.microsoft.com/zh-cn/uwp/api/windows.management.deployment.packagestate?view=winrt-26100 + + // á +#define PACKAGESTATUS_NORMAL 0 + // ֤Ч +#define PACKAGESTATUS_LICENSE_INVALID 1 + // Чδ֪Դ޸ġ +#define PACKAGESTATUS_MODIFIED 2 + // Чر۸ġ +#define PACKAGESTATUS_TAMPERED 3 + // 磬 ״̬ΪáѴ۸ġȡ + // dwStatus ʹ PACKAGESTATUS_* + PKGMGR_API HRESULT SetAppxPackageStatus (LPCWSTR lpPackageFullName, DWORD dwStatus, LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL)); + // ڲע½ ݴ浽ϵͳ + // dwDeployOption DEPOLYOPTION_* + PKGMGR_API HRESULT StageAppxPackageFromURI (LPCWSTR lpFileUri, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUriList _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), DWORD dwDeployOption _DEFAULT_INIT_VALUE_FORFUNC_ (DEPOLYOPTION_NONE), PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL)); + // ڲע½ ݴ浽ϵͳ + // dwDeployOption DEPOLYOPTION_* + PKGMGR_API HRESULT StageAppxPackageFromPath (LPCWSTR lpFileUri, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUriList _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), DWORD dwDeployOption _DEFAULT_INIT_VALUE_FORFUNC_ (DEPOLYOPTION_NONE), PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL)); + // ڲע½ ݴ浽ϵͳ ݴ֮Ϊضûע֮ǰô˷ + // dwDeployOption DEPOLYOPTION_* + PKGMGR_API HRESULT StageAppxUserData (LPCWSTR lpPackageFullName, PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL)); + // Ϊǰû㱨Ѱװİ + // °İ汾Ѱװİ汾ʱܸѰװİ ǰ汾İʧܡ + // ע⣺ļ·Ϊ DOS/NT 磺C:\Windows\... + // dwDeployOption DEPOLYOPTION_* + // ĴϢ free ͷ + PKGMGR_API HRESULT UpdateAppxPackageFromPath (LPCWSTR lpPkgPath, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUrlList _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), DWORD dwDeployOption _DEFAULT_INIT_VALUE_FORFUNC_ (DEPOLYOPTION_NONE), PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL)); + // Ϊǰû㱨Ѱװİ + // °İ汾Ѱװİ汾ʱܸѰװİ ǰ汾İʧܡ + // ע⣺ļ·Ϊ URI + // dwDeployOption DEPOLYOPTION_* + // ĴϢ free ͷ + PKGMGR_API HRESULT UpdateAppxPackageFromURI (LPCWSTR lpFileUri, PCREGISTER_PACKAGE_DEFENDENCIES alpDepFullNameList _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), DWORD dwDeployOption _DEFAULT_INIT_VALUE_FORFUNC_ (DEPOLYOPTION_NONE), PKGMRR_PROGRESSCALLBACK pfCallback _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL)); + // йΪκûװָ Ϣ + PKGMGR_API HRESULT FindAppxPackage (LPCWSTR lpPackageFullName, PKGMGR_FINDENUMCALLBACK pfCallback, void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL)); + // ȡ롣벻һУҸЧϢԴϸϢ + PKGMGR_API LPCWSTR GetPackageManagerLastErrorCode (); + // ȡϸϢdzõ + PKGMGR_API LPCWSTR GetPackageManagerLastErrorDetailMessage (); +#ifdef _DEFAULT_INIT_VALUE_ +#undef _DEFAULT_INIT_VALUE_ +#endif +#ifdef _DEFAULT_INIT_VALUE_FORFUNC_ +#undef _DEFAULT_INIT_VALUE_FORFUNC_ +#endif +#ifdef __cplusplus +} +#endif diff --git a/pkgmgr/pkgmgr.vcxproj b/pkgmgr/pkgmgr.vcxproj new file mode 100644 index 0000000..a291e39 --- /dev/null +++ b/pkgmgr/pkgmgr.vcxproj @@ -0,0 +1,96 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {8EAC0230-4990-4E41-8E0F-D641D1561396} + Win32Proj + pkgmgr + pkgmgr + + + + DynamicLibrary + true + Unicode + v120 + false + + + DynamicLibrary + false + Unicode + v120 + false + + + + + + + + + + + + $(VCINSTALLDIR)\vcpackages;$(VCInstallDir)atlmfc\lib;$(VCInstallDir)lib;$(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(ReferencePath) + + + $(VCINSTALLDIR)\vcpackages;$(VCInstallDir)atlmfc\lib;$(VCInstallDir)lib;$(WindowsSdkDir)\References\CommonConfiguration\Neutral;$(ReferencePath) + + + + + NotUsing + Level3 + Disabled + /ZW:nostdlib /FUplatform.winmd /FUwindows.winmd %(AdditionalOptions) + WIN32;_DEBUG;_WINDOWS;_USRDLL;PKGMGR_EXPORTS;%(PreprocessorDefinitions) + true + false + + + Windows + true + RequireAdministrator + + + + + NotUsing + Level3 + MaxSpeed + true + true + /ZW:nostdlib /FUplatform.winmd /FUWindows.winmd %(AdditionalOptions) + WIN32;NDEBUG;_WINDOWS;_USRDLL;PKGMGR_EXPORTS;%(PreprocessorDefinitions) + true + + + Windows + true + true + true + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pkgmgr/pkgmgr.vcxproj.filters b/pkgmgr/pkgmgr.vcxproj.filters new file mode 100644 index 0000000..b2849fa --- /dev/null +++ b/pkgmgr/pkgmgr.vcxproj.filters @@ -0,0 +1,42 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + 源文件 + + + 源文件 + + + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + \ No newline at end of file diff --git a/pkgmgr/raii.h b/pkgmgr/raii.h new file mode 100644 index 0000000..cc82c4f --- /dev/null +++ b/pkgmgr/raii.h @@ -0,0 +1,8 @@ +#pragma once +#include +struct raii +{ + std::function endtask = nullptr; + raii (std::function pFunc = nullptr): endtask (pFunc) {} + ~raii () { if (endtask) endtask (); } +}; \ No newline at end of file diff --git a/pkgmgr/stdafx.cpp b/pkgmgr/stdafx.cpp new file mode 100644 index 0000000..1945e44 --- /dev/null +++ b/pkgmgr/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : ֻ׼ļԴļ +// pkgmgr.pch ΪԤͷ +// stdafx.obj ԤϢ + +#include "stdafx.h" + +// TODO: STDAFX.H κĸͷļ +//ڴļ diff --git a/pkgmgr/stdafx.h b/pkgmgr/stdafx.h new file mode 100644 index 0000000..b363c26 --- /dev/null +++ b/pkgmgr/stdafx.h @@ -0,0 +1,30 @@ +// stdafx.h : ׼ϵͳļİļ +// Ǿʹõĵ +// ضĿİļ +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Windows ͷųʹõ +// Windows ͷļ: +#include + + + +// TODO: ڴ˴óҪͷļ +#using +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Management::Deployment; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include \ No newline at end of file diff --git a/pkgmgr/targetver.h b/pkgmgr/targetver.h new file mode 100644 index 0000000..416cebf --- /dev/null +++ b/pkgmgr/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// SDKDDKVer.h õ߰汾 Windows ƽ̨ + +// ҪΪǰ Windows ƽ̨Ӧó WinSDKVer.h +// _WIN32_WINNT ΪҪֵ֧ƽ̨Ȼٰ SDKDDKVer.h + +#include diff --git a/pkgmgr/version.h b/pkgmgr/version.h new file mode 100644 index 0000000..5091c21 --- /dev/null +++ b/pkgmgr/version.h @@ -0,0 +1,125 @@ +#pragma once +#include +#include +#include +#include +typedef uint64_t UINT64; +typedef int64_t INT64; +typedef uint16_t UINT16; +typedef struct version +{ + UINT16 major = 0, minor = 0, build = 0, revision = 0; + version (UINT64 value): + major ((value >> 0x30) & 0xFFFF), minor ((value >> 0x20) & 0xFFFF), + build ((value >> 0x10) & 0xFFFF), revision ((value) & 0xFFFF) {} + version (UINT16 major, UINT16 minor, UINT16 build, UINT16 revision): + major (major), minor (minor), build (build), revision (revision) {} + version (const std::wstring &verstr) { this->interpret (verstr); } + version (const std::string &verstr) { this->interpret (verstr); } + version () {} + version (const version &other): major (other.major), minor (other.minor), build (other.build), revision (other.revision) {} + version (version &&other): major (other.major), minor (other.minor), build (other.build), revision (other.revision) {} + version &operator = (const version &other) + { + if (this != &other) + { + major = other.major; + minor = other.minor; + build = other.build; + revision = other.revision; + } + return *this; + } + version &operator = (version &&other) + { + if (this != &other) + { + major = other.major; + minor = other.minor; + build = other.build; + revision = other.revision; + } + return *this; + } + version &operator = (UINT64 value) { this->data (value); return *this; } + UINT64 data () const { return (((UINT64)major) << 48) | (((UINT64)minor) << 32) | (((UINT64)build) << 16) | ((UINT64)revision); } + UINT64 data (UINT64 value) + { + major = (value >> 48) & 0xFFFF; + minor = (value >> 32) & 0xFFFF; + build = (value >> 16) & 0xFFFF; + revision = value & 0xFFFF; + return value; + } + std::wstring stringifyw () const + { + std::wstringstream ss; + ss << major << L'.' << minor << L'.' << build << L'.' << revision; + return ss.str (); + } + std::string stringify () const + { + std::stringstream ss; + ss << major << '.' << minor << '.' << build << '.' << revision; + return ss.str (); + } + version &interpret (const std::wstring &verstr) + { + auto result = split (verstr); + if (result.size () > 0) this->major = _wtoi (result [0].c_str ()); + if (result.size () > 1) this->minor = _wtoi (result [1].c_str ()); + if (result.size () > 2) this->build = _wtoi (result [2].c_str ()); + if (result.size () > 3) this->revision = _wtoi (result [3].c_str ()); + return *this; + } + version &interpret (const std::string &verstr) + { + auto result = split (verstr); + if (result.size () > 0) this->major = atoi (result [0].c_str ()); + if (result.size () > 1) this->minor = atoi (result [1].c_str ()); + if (result.size () > 2) this->build = atoi (result [2].c_str ()); + if (result.size () > 3) this->revision = atoi (result [3].c_str ()); + return *this; + } + bool empty () const { return *(UINT64 *)this == 0; } + friend bool operator == (const version &l, const version &r) { return *(UINT64 *)&l == *(UINT64 *)&r; } + friend bool operator == (const version &l, const UINT64 &r) { return l.data () == r; } + friend bool operator == (const UINT64 &r, const version &l) { return l.data () == r; } + friend bool operator < (const version &l, const version &r) { return l.data () < r.data (); } + friend bool operator > (const version &l, const version &r) { return l.data () > r.data (); } + friend bool operator <= (const version &l, const version &r) { return l.data () <= r.data (); } + friend bool operator >= (const version &l, const version &r) { return l.data () >= r.data (); } + friend bool operator != (const version &l, const version &r) { return *(UINT64 *)&l != *(UINT64 *)&r; } + explicit operator bool () const { return !this->empty (); } + bool operator ! () { return this->empty (); } + friend std::ostream &operator << (std::ostream &o, const version &v) { return o << v.major << '.' << v.minor << '.' << v.build << '.' << v.revision; } + friend std::wostream &operator << (std::wostream &o, const version &v) { return o << v.major << '.' << v.minor << '.' << v.build << '.' << v.revision; } + bool equals (const version &r) const { return *this == r; } + INT64 compare (const version &r) const { return this->data () - r.data (); } + static version parse (const std::wstring &value) { return version (value); } + static version parse (const std::string &value) { return version (value); } + static std::wstring stringifyw (const version &v) { return v.stringifyw (); } + static std::string stringify (const version &v) { return v.stringify (); } + static bool equals (const version &l, const version &r) { return l == r; } + static INT64 compare (const version &l, const version &r) { return l.data () - r.data (); } + static version decode (UINT64 value) { return version (value); } + static UINT64 encode (const version &v) { return v.data (); } + protected: + template std::vector split (const StringType &str, typename StringType::value_type delimiter1 = '.', typename StringType::value_type delimiter2 = ',') + { + std::vector result; + std::basic_stringstream ss (str); + StringType segment; + while (std::getline (ss, segment, delimiter1)) + { + size_t pos = 0; + while ((pos = segment.find (delimiter2)) != StringType::npos) + { + result.push_back (segment.substr (0, pos)); + segment.erase (0, pos + 1); + } + if (!segment.empty ()) result.push_back (segment); + } + return result; + } +} Version; \ No newline at end of file diff --git a/pkgread/localeex.h b/pkgread/localeex.h index b528d56..b1d5237 100644 --- a/pkgread/localeex.h +++ b/pkgread/localeex.h @@ -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); } \ No newline at end of file +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); +} diff --git a/pkgread/pkgread.cpp b/pkgread/pkgread.cpp index d01e03a..bfe1b99 100644 --- a/pkgread/pkgread.cpp +++ b/pkgread/pkgread.cpp @@ -5,6 +5,7 @@ #include "readobj.h" #include "pkgread.h" #include "localeex.h" +#include "themeinfo.h" #define ToHandleRead(_cpp_ptr_) reinterpret_cast (_cpp_ptr_) #define ToPtrPackage(_cpp_ptr_) reinterpret_cast (_cpp_ptr_) @@ -859,4 +860,313 @@ BOOL GetPackagePrerequisite (_In_ HPKGREAD hReader, _In_ LPCWSTR lpName, _Outptr } break; } return FALSE; -} \ No newline at end of file +} + +// Selector +std::wnstring SelectLanguageSuitPackageNameByLocaleCode (std::map &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 &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 &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 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 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 appfile; + if (FAILED (bread.random_application_package (&appfile))) return nullptr; + appxreader reader (appfile.p); + CComPtr 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 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 iappx; + if (FAILED (GetAppxPackageReader (ifs, &iappx))) return nullptr; + appxreader reader (iappx.p); + CComPtr 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 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 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 pread; + if (FAILED (bread.get_payload_package (lf, &pread))) return false; + CComPtr file = nullptr; + if (FAILED (pread->GetStream (&file))) return false; + else return true; + } break; + } + } + else + { + { + CComPtr 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 file; + if (FAILED (reslangpkg->GetStream (&file))) return false; + } + } + { + CComPtr 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 file; + if (FAILED (resscalepkg->GetStream (&file))) return false; + } + } + } + return true; +} +ULONG DestroyAppxFileStream (_In_ HANDLE hFileStream) +{ + if (!hFileStream) return 0; + IStream *ptr = reinterpret_cast (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 buffer (uliSize.QuadPart); + ULONG bytesRead; + pStream->Read (buffer.data (), static_cast (buffer.size ()), &bytesRead); + DWORD base64Size = 0; + if (!CryptBinaryToStringW (buffer.data (), bytesRead, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, nullptr, &base64Size)) return nullptr; + std::vector 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; +} diff --git a/pkgread/pkgread.h b/pkgread/pkgread.h index 4f09cd6..79a6898 100644 --- a/pkgread/pkgread.h +++ b/pkgread/pkgread.h @@ -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 лȡʵİָԴʡ + // һڷصIJָǷصԺʵѡڶڷصIJǷصԴ + // ָĶͬһôصĶͬһָ롣 + // 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 ݣΪָָIJ֡ + // ַΪ 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 #include #include #include #include #include +#include +#include +//#include "..\priformatcli\priformatcli.h" +const std::vector 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 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 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 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 endtask = nullptr; deconstr (std::function 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 { using base = std::map ; 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 diff --git a/pkgread/pkgread.rc b/pkgread/pkgread.rc new file mode 100644 index 0000000..66d27f3 Binary files /dev/null and b/pkgread/pkgread.rc differ diff --git a/pkgread/pkgread.vcxproj b/pkgread/pkgread.vcxproj index a4fa96c..46cf9b6 100644 --- a/pkgread/pkgread.vcxproj +++ b/pkgread/pkgread.vcxproj @@ -92,6 +92,7 @@ Windows true + urlmon.lib;crypt32.lib;%(AdditionalDependencies) @@ -122,6 +123,7 @@ true true true + urlmon.lib;crypt32.lib;%(AdditionalDependencies) @@ -145,18 +147,18 @@ - - + + @@ -185,6 +187,9 @@ + + + diff --git a/pkgread/pkgread.vcxproj.filters b/pkgread/pkgread.vcxproj.filters index 0ff98ee..4b5706c 100644 --- a/pkgread/pkgread.vcxproj.filters +++ b/pkgread/pkgread.vcxproj.filters @@ -33,9 +33,6 @@ 头文件 - - 头文件 - 头文件 @@ -54,7 +51,10 @@ 头文件 - + + 头文件 + + 头文件 @@ -72,4 +72,9 @@ + + + 资源文件 + + \ No newline at end of file diff --git a/pkgread/readobj.h b/pkgread/readobj.h index 5580e60..885e109 100644 --- a/pkgread/readobj.h +++ b/pkgread/readobj.h @@ -209,7 +209,6 @@ template class com_info_quote private: IComInterface &icom = nullptr; protected: - ComInterface *pointer () const noexcept { return icom; } template std::wstring get (_In_ Fn func) const { if (!icom) return L""; @@ -254,6 +253,7 @@ template 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 (&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 languages; + std::vector scales; + resource_content (const std::vector &langs): languages (langs) {} + resource_content (const std::vector &ss): scales (ss) {} + resource_content (const std::vector &langs, const std::vector &ss): languages (langs), scales (ss) {} + resource_content () = default; + } resvalue; + resource (const std::vector &languages): + restype (ResourceType::language), resvalue (languages) {} + resource (const std::vector &ss): + restype (ResourceType::scale), resvalue (ss) {} + resource (const std::vector &langs, const std::vector &ss): + restype (ResourceType::both), resvalue (langs, ss) {} + resource (): restype (ResourceType::unknown), resvalue () {} + }; class appx_iditems: virtual public com_info { using Base = com_info ; @@ -777,6 +805,33 @@ namespace appx_info } return cnt; } + size_t resource_info (std::map &output) const + { + output.clear (); + std::vector items; + enumerate (items); + for (auto &it : items) + { + std::wnstring fpath = it.file_name (); + auto qres = it.qualified_resources (); + std::vector langs; + std::vector scales; + qres.qualified_resources (&langs, &scales); + std::vector 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 @@ -1029,6 +1084,98 @@ class bundlereader: virtual public com_info_quote if (FAILED (hr)) return hr; return GetAppxPackageReader (ist, output); } + HRESULT random_application_package (_Outptr_ IAppxFile **output) const + { + CComPtr 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 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 afile; + return get_payload_package (fname, output); + } + HRESULT random_resource_package (_Outptr_ IAppxFile **output) const + { + CComPtr 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 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 afile; + return hr = get_payload_package (fname, output); + } + HRESULT random_application_package (_Outptr_ IStream **output) const + { + CComPtr 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 iaf; + HRESULT hr = S_OK; + if (FAILED (hr = random_resource_package (&iaf))) return hr; + return iaf->GetStream (output); + } size_t application_packages (std::function callback) const { CComPtr iditems; diff --git a/pkgread/resource.h b/pkgread/resource1.h similarity index 100% rename from pkgread/resource.h rename to pkgread/resource1.h diff --git a/pkgread/stdafx.h b/pkgread/stdafx.h index b4e958f..97be4a1 100644 --- a/pkgread/stdafx.h +++ b/pkgread/stdafx.h @@ -23,4 +23,13 @@ #include #include #include -#include \ No newline at end of file +#include +#include +#include + +#ifdef max +#undef max +#endif +#ifdef min +#undef min +#endif \ No newline at end of file diff --git a/pkgread/themeinfo.h b/pkgread/themeinfo.h new file mode 100644 index 0000000..8d3c712 --- /dev/null +++ b/pkgread/themeinfo.h @@ -0,0 +1,40 @@ +#pragma once +#include + +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; +}