diff --git a/appinstaller/appinstaller.rc b/appinstaller/appinstaller.rc index dd83c8f..3303a6f 100644 Binary files a/appinstaller/appinstaller.rc and b/appinstaller/appinstaller.rc differ diff --git a/appinstaller/appinstaller.vcxproj b/appinstaller/appinstaller.vcxproj index d6f58c1..caf425b 100644 --- a/appinstaller/appinstaller.vcxproj +++ b/appinstaller/appinstaller.vcxproj @@ -96,6 +96,7 @@ Windows true shlwapi.lib;version.lib;dwmapi.lib;$(OutDir)pkgread.lib;$(OutDir)pkgmgr.lib;$(OutDir)certmgr.lib;$(OutDir)priformatcli.lib;$(OutDir)notice.lib;%(AdditionalDependencies) + RequireAdministrator app.manifest @@ -132,6 +133,7 @@ true true shlwapi.lib;version.lib;dwmapi.lib;$(OutDir)pkgread.lib;$(OutDir)pkgmgr.lib;$(OutDir)certmgr.lib;$(OutDir)priformatcli.lib;$(OutDir)notice.lib;%(AdditionalDependencies) + RequireAdministrator app.manifest @@ -167,6 +169,7 @@ + @@ -190,6 +193,7 @@ + diff --git a/appinstaller/appinstaller.vcxproj.filters b/appinstaller/appinstaller.vcxproj.filters index f6c5ca5..9ac7b42 100644 --- a/appinstaller/appinstaller.vcxproj.filters +++ b/appinstaller/appinstaller.vcxproj.filters @@ -87,6 +87,9 @@ 头文件 + + 头文件 + diff --git a/appinstaller/appxinfo.h b/appinstaller/appxinfo.h index b047d6b..13a94d5 100644 --- a/appinstaller/appxinfo.h +++ b/appinstaller/appxinfo.h @@ -12,6 +12,7 @@ #include "nstring.h" #include "priformatcli.h" #include "pkgread.h" + static std::string ws2utf8 (const std::wstring &ws) { std::wstring_convert > conv; @@ -37,7 +38,7 @@ struct pkginfo // AppxBundle ԶԴΪܰ޷ AppxBundleԴӦðһͬ AppxBundle // PKGROLE_* ꡣ WORD role = 0; - struct + struct { std::wstring name, publisher, @@ -47,6 +48,39 @@ struct pkginfo VERSION version, realver; DWORD architecture; } identity; + // x86: 0 + // x64: 9 + // Arm: 5 + // Neutral: 11 + // Arm64: 12 + std::set get_architectures () const + { + std::set ret; + switch (type) + { + case PKGTYPE_APPX: { + switch (identity.architecture) + { + case PKG_ARCHITECTURE_X86: ret.insert (0); break; + case PKG_ARCHITECTURE_X64: ret.insert (9); break; + case PKG_ARCHITECTURE_ARM: ret.insert (5); break; + case PKG_ARCHITECTURE_ARM64: ret.insert (12); break; + case PKG_ARCHITECTURE_NEUTRAL: ret.insert (11); break; + } + } break; + case PKGTYPE_BUNDLE: { + if (identity.architecture & PKG_ARCHITECTURE_X86) ret.insert (0); + if (identity.architecture & PKG_ARCHITECTURE_X64) ret.insert (9); + if (identity.architecture & PKG_ARCHITECTURE_ARM) ret.insert (5); + if (identity.architecture & PKG_ARCHITECTURE_ARM64) ret.insert (12); + // ڼܹʷչԭǶԵġ + if (identity.architecture & (PKG_ARCHITECTURE_X86 | PKG_ARCHITECTURE_X64 | PKG_ARCHITECTURE_ARM)) + { ret.clear (); ret.insert (11); } + if (identity.architecture & PKG_ARCHITECTURE_NEUTRAL) { ret.clear (); ret.insert (11); } + } + } + return ret; + } struct { std::wstring display_name; @@ -91,6 +125,7 @@ struct pkginfo struct { VERSION os_min_version, os_max_version_tested; + std::wstring os_min_version_description, os_max_version_tested_description; } prerequisites; static pkginfo parse (const std::wstring &filepath) { @@ -128,6 +163,8 @@ struct pkginfo auto prer = pread.get_prerequisites (); pkg.prerequisites.os_min_version = prer.os_min_version (); pkg.prerequisites.os_max_version_tested = prer.os_max_version_tested (); + pkg.prerequisites.os_min_version_description = prer.os_min_version_description (); + pkg.prerequisites.os_max_version_tested_description = prer.os_max_version_tested_description (); } { auto apps = pread.get_applications (); @@ -299,10 +336,12 @@ struct pkginfo Value obj (kObjectType); obj.AddMember ("os_min_version", ver_to_json (prerequisites.os_min_version, alloc), alloc); obj.AddMember ("os_max_version_tested", ver_to_json (prerequisites.os_max_version_tested, alloc), alloc); + obj.AddMember ("os_min_version_description", Value (ws2utf8 (prerequisites.os_min_version_description).c_str (), alloc), alloc); + obj.AddMember ("os_max_version_tested_description", Value (ws2utf8 (prerequisites.os_max_version_tested_description).c_str (), alloc), alloc); doc.AddMember ("prerequisites", obj, alloc); } StringBuffer buffer; - Writer writer (buffer); + Writer writer (buffer); doc.Accept (writer); std::string utf8 = buffer.GetString (); std::wstring_convert > conv; diff --git a/appinstaller/cmdargs.h b/appinstaller/cmdargs.h index 1a14889..9837544 100644 --- a/appinstaller/cmdargs.h +++ b/appinstaller/cmdargs.h @@ -7,6 +7,7 @@ #include "rctools.h" #include "filepath.h" #include "raii.h" +#include "resource.h" // ǰ׺統ǰ׺Ϊ-"/"ʱҿ롰-args"/args""args" ǵЧ #define CMDARG_IGNOREPREFIXS 0b001 @@ -24,12 +25,14 @@ struct cmdarg std::wstring description; // ɰı DWORD flags; // ־ }; -#define CMDARG_PREFIXS_DEFAULT {L"-", L"/"} +#define CMDARG_PREFIXS_DEFAULT {L"/", L"-"} #define CMDARG_POSTFIXS_DEFAULT {} +#define CMDARG_HELP {CMDARG_PREFIXS_DEFAULT, {L"?", L"help", L"h"}, CMDARG_PREFIXS_DEFAULT, L"help", GetRCStringSW (IDS_CMDPARAM_HELP), CMDARG_IGNOREPREFIXS} std::vector g_argslist = { - {CMDARG_PREFIXS_DEFAULT, {L"silent", L"quiet", L"passive"}, CMDARG_POSTFIXS_DEFAULT, L"silent", GetRCStringSW (0), CMDARG_IGNOREPREFIXS}, - {CMDARG_PREFIXS_DEFAULT, {L"verysilent", L"veryquiet"}, CMDARG_POSTFIXS_DEFAULT, L"verysilent", GetRCStringSW (0), CMDARG_IGNOREPREFIXS}, - {CMDARG_PREFIXS_DEFAULT, {L"multiple", L"filelist"}, {L"="}, L"multiple", GetRCStringSW (0), CMDARG_IGNOREPREFIXS | CMDARG_ENABLEPARAMS} + CMDARG_HELP, + {CMDARG_PREFIXS_DEFAULT, {L"silent", L"quiet", L"passive"}, CMDARG_POSTFIXS_DEFAULT, L"silent", GetRCStringSW (IDS_CMDPARAM_SILENT), CMDARG_IGNOREPREFIXS}, + {CMDARG_PREFIXS_DEFAULT, {L"verysilent", L"veryquiet"}, CMDARG_POSTFIXS_DEFAULT, L"verysilent", GetRCStringSW (IDS_CMDPARAM_VERYSILENT), CMDARG_IGNOREPREFIXS}, + {CMDARG_PREFIXS_DEFAULT, {L"multiple", L"filelist"}, {L"="}, L"multiple", GetRCStringSW (IDS_CMDPARAM_MULTIPLE), CMDARG_IGNOREPREFIXS | CMDARG_ENABLEPARAMS} }; bool IsFile (const std::wstring &path) { diff --git a/appinstaller/localeex.h b/appinstaller/localeex.h new file mode 100644 index 0000000..e19646b --- /dev/null +++ b/appinstaller/localeex.h @@ -0,0 +1,248 @@ +#pragma once +#include +#include +#include "typestrans.h" + +#undef GetLocaleInfo +std::string GetLocaleInfoA (LCID code, LCTYPE type) +{ + char buf [LOCALE_NAME_MAX_LENGTH] = {0}; + GetLocaleInfoA (code, type, buf, LOCALE_NAME_MAX_LENGTH); + return buf; +} +std::wstring GetLocaleInfoW (LCID code, LCTYPE type) +{ + WCHAR buf [LOCALE_NAME_MAX_LENGTH] = {0}; + GetLocaleInfoW (code, type, buf, LOCALE_NAME_MAX_LENGTH); + return buf; +} +void GetLocaleInfo (LCID code, LCTYPE type, std::wstring &output) +{ + output = GetLocaleInfoW (code, type); +} +void GetLocaleInfo (LCID code, LCTYPE type, std::string &output) +{ + output = GetLocaleInfoA (code, type); +} +int GetLocaleInfoEx (std::wstring lpLocaleName, LCTYPE type, std::wstring &output) +{ + WCHAR buf [LOCALE_NAME_MAX_LENGTH] = {0}; + int res = GetLocaleInfoEx (lpLocaleName.c_str (), type, buf, LOCALE_NAME_MAX_LENGTH); + if (&output) output = std::wstring (buf); + return res; +} + +#undef SetLocaleInfo +BOOL SetLocaleInfoA (LCID code, LCTYPE type, const std::string &lcData) +{ + return SetLocaleInfoA (code, type, lcData.c_str ()); +} +BOOL SetLocaleInfoW (LCID code, LCTYPE type, const std::wstring &lcData) +{ + return SetLocaleInfoW (code, type, lcData.c_str ()); +} +BOOL SetLocaleInfo (LCID code, LCTYPE type, const std::wstring &lcData) +{ + return SetLocaleInfoW (code, type, lcData); +} +BOOL SetLocaleInfo (LCID code, LCTYPE type, const std::string &lcData) +{ + return SetLocaleInfoA (code, type, lcData); +} + +std::string GetLocaleRestrictedCodeFromLcidA (LCID lcid) +{ + return GetLocaleInfoA (lcid, 89); +} +std::wstring GetLocaleRestrictedCodeFromLcidW (LCID lcid) +{ + return GetLocaleInfoW (lcid, 89); +} +void GetLocaleRestrictedCodeFromLcid (LCID lcid, std::string &ret) +{ + ret = GetLocaleRestrictedCodeFromLcidA (lcid); +} +void GetLocaleRestrictedCodeFromLcid (LCID lcid, std::wstring &ret) +{ + ret = GetLocaleRestrictedCodeFromLcidW (lcid); +} + +std::string GetLocaleElaboratedCodeFromLcidA (LCID lcid) +{ + return GetLocaleInfoA (lcid, 90); +} +std::wstring GetLocaleElaboratedCodeFromLcidW (LCID lcid) +{ + return GetLocaleInfoW (lcid, 90); +} +void GetLocaleElaboratedCodeFromLcid (LCID lcid, std::wstring &ret) +{ + ret = GetLocaleElaboratedCodeFromLcidW (lcid); +} +void GetLocaleElaboratedCodeFromLcid (LCID lcid, std::string &ret) +{ + ret = GetLocaleElaboratedCodeFromLcidA (lcid); +} + +LCID LocaleCodeToLcidW (const std::wstring &localeCode) +{ +#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 (const std::string &localeCode) +{ + std::wstring lcWide = StringToWString (std::string (localeCode)); + return LocaleCodeToLcidW (lcWide.c_str ()); +} +LCID LocaleCodeToLcid (const std::wstring &loccode) +{ + return LocaleCodeToLcidW (loccode.c_str ()); +} +LCID LocaleCodeToLcid (const std::string &loccode) +{ + return LocaleCodeToLcidA (loccode.c_str ()); +} + +std::string GetLocaleRestrictedCodeA (LPCSTR lc) +{ + return GetLocaleInfoA (LocaleCodeToLcidA (lc), 89); +} +std::string GetLocaleRestrictedCodeA (const std::string &lc) +{ + return GetLocaleInfoA (LocaleCodeToLcidA (lc.c_str ()), 89); +} +std::wstring GetLocaleRestrictedCodeW (LPCWSTR lc) +{ + return GetLocaleInfoW (LocaleCodeToLcidW (lc), 89); +} +std::wstring GetLocaleRestrictedCodeW (const std::wstring &lc) +{ + return GetLocaleInfoW (LocaleCodeToLcidW (lc.c_str ()), 89); +} +std::wstring GetLocaleRestrictedCode (const std::wstring &lc) { return GetLocaleRestrictedCodeW (lc); } +std::string GetLocaleRestrictedCode (const std::string &lc) { return GetLocaleRestrictedCodeA (lc); } + +std::string GetLocaleElaboratedCodeA (LPCSTR lc) +{ + return GetLocaleInfoA (LocaleCodeToLcidA (lc), 90); +} +std::string GetLocaleElaboratedCodeA (const std::string &lc) +{ + return GetLocaleInfoA (LocaleCodeToLcidA (lc.c_str ()), 90); +} +std::wstring GetLocaleElaboratedCodeW (LPCWSTR lc) +{ + return GetLocaleInfoW (LocaleCodeToLcidW (lc), 90); +} +std::wstring GetLocaleElaboratedCodeW (const std::wstring &lc) +{ + return GetLocaleInfoW (LocaleCodeToLcidW (lc.c_str ()), 90); +} +std::wstring GetLocaleElaboratedCode (const std::wstring &lc) { return GetLocaleElaboratedCodeW (lc); } +std::string GetLocaleElaboratedCode (const std::string &lc) { return GetLocaleElaboratedCodeA (lc); } + +std::string LcidToLocaleCodeA (LCID lcid, char divide = '-') +{ + return GetLocaleRestrictedCodeFromLcidA (lcid) + divide + GetLocaleElaboratedCodeFromLcidA (lcid); +} +std::wstring LcidToLocaleCodeW (LCID lcid, WCHAR divide = L'-') +{ +#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) + try + { + WCHAR buf [LOCALE_NAME_MAX_LENGTH] = {0}; + LCIDToLocaleName (lcid, buf, LOCALE_NAME_MAX_LENGTH, 0); + return buf; + } + catch (const std::exception &e) {} + return GetLocaleRestrictedCodeFromLcidW (lcid) + divide + GetLocaleElaboratedCodeFromLcidW (lcid); +#else + return GetLocaleRestrictedCodeFromLcidW (lcid) + divide + GetLocaleElaboratedCodeFromLcidW (lcid); +#endif +} +std::wstring LcidToLocaleCode (LCID lcid, WCHAR divide = L'-') { return LcidToLocaleCodeW (lcid, divide); } +std::string LcidToLocaleCode (LCID lcid, char divide = '-') { return LcidToLocaleCodeA (lcid, divide); } + +std::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/appinstaller/main.cpp b/appinstaller/main.cpp index cd52474..6e900a0 100644 --- a/appinstaller/main.cpp +++ b/appinstaller/main.cpp @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include #include "cmdargs.h" #include "themeinfo.h" #include "mpstr.h" @@ -14,6 +17,10 @@ #include "ieshell.h" #include "resmap.h" #include "appxinfo.h" +#include "localeex.h" +#include "pkgmgr.h" +#include "notice.h" +#include "certmgr.h" using namespace System; using namespace System::Runtime::InteropServices; @@ -24,6 +31,13 @@ using namespace System::Runtime::InteropServices; #define DEBUGMODE false #endif #define JS_SAFE [MarshalAs (UnmanagedType::SafeArray, SafeArraySubType = VarEnum::VT_VARIANT)] +enum class CMDPARAM: DWORD +{ + NONE = 0b000, + SILENT = 0b001, + VERYSILENT = 0b011, + MULTIPLE = 0b100 +}; LPCWSTR g_lpAppId = L"Microsoft.DesktopAppInstaller"; auto &g_identity = g_lpAppId; @@ -49,8 +63,21 @@ resxmldoc g_scaleres ( CombinePath (GetProgramRootDirectoryW (), L"VisualElementsManifest.xml") ); WORD g_wcmdflags = 0; -std::set g_pkgfiles; +std::vector g_pkgfiles; std::vector g_pkginfo; +std::wstring g_lastfile; +struct package_installresult +{ + HRESULT result = S_OK; + std::wstring error; + std::wstring reason; + bool succeeded () const { return SUCCEEDED (result); } + bool failed () const { return FAILED (result); } + package_installresult (HRESULT result, const std::wstring &err, const std::wstring &msg): result (result), reason (msg), error (err) {} + package_installresult (HRESULT result, const std::wstring &msg): result (result), reason (msg) {} + package_installresult () = default; +}; +std::map g_pkgresult; HRESULT GetWebBrowser2Interface (System::Windows::Forms::WebBrowser ^fwb, IWebBrowser2 **output) { @@ -245,36 +272,167 @@ public ref class SplashForm: public System::Windows::Forms::Form } } }; -bool ReadPackagesTask () +System::String ^FormatString (System::String ^fmt, ... array ^args) { return System::String::Format (fmt, args); } +std::wstring HResultToMessage (HRESULT hr) { - std::set noread; - std::set hasread; - for (auto &it : g_pkgfiles) + _com_error err (hr); + auto msgptr = err.ErrorMessage (); + return msgptr ? msgptr : L""; +} +String ^ EscapeToInnerXml (String ^str) +{ + using namespace System::Xml; + auto doc = gcnew System::Xml::XmlDocument (); + doc->LoadXml (""); + auto root = doc->FirstChild; + root->InnerText = str; + return root->InnerXml; +} +std::wstring EscapeToInnerXml (const std::wstring &str) { return MPStringToStdW (EscapeToInnerXml (CStringToMPString (str))); } +enum class InstallType +{ + normal, + update, + reinstall +}; +inline std::wstring ToStdWString (const std::wstring &str) { return str; } +size_t ExploreFile (HWND hParent, std::vector &results, LPWSTR lpFilter = L"Windows Store App Package (*.appx; *.appxbundle)\0*.appx;*.appxbundle", DWORD dwFlags = OFN_EXPLORER | OFN_ALLOWMULTISELECT | OFN_PATHMUSTEXIST, const std::wstring &swWndTitle = std::wstring (L"Please select the file(-s): "), const std::wstring &swInitDir = GetFileDirectoryW (g_lastfile)) +{ + results.clear (); + const DWORD BUFFER_SIZE = 65536; // 64KB + std::vector buffer (BUFFER_SIZE, 0); + OPENFILENAME ofn; + ZeroMemory (&ofn, sizeof (ofn)); + ofn.hwndOwner = hParent; + ofn.lpstrFile = (LPWSTR)buffer.data (); + ofn.nMaxFile = BUFFER_SIZE; + ofn.lpstrFilter = lpFilter; + ofn.nFilterIndex = 1; + ofn.lpstrTitle = swWndTitle.c_str (); + ofn.Flags = dwFlags; + ofn.lpstrInitialDir = swInitDir.c_str (); + ofn.lStructSize = sizeof (ofn); + if (GetOpenFileNameW (&ofn)) { - bool isfind = false; - for (auto &rit : g_pkginfo) + LPCWSTR p = buffer.data (); + std::wstring dir = p; + p += dir.length () + 1; + if (*p == 0) results.push_back (dir); + else { - if (rit.filepath == it) + while (*p) { - isfind == true; - hasread.insert (it); - break; + std::wstring fullPath = dir + L"\\" + p; + results.push_back (fullPath); + p += wcslen (p) + 1; } } - if (!isfind) noread.insert (it); + if (!results.empty ()) g_lastfile = results.back (); } - for (auto &it : noread) + return results.size (); +} +public delegate void InstallProgressCallbackDelegate (DWORD progress); +#pragma managed(push, off) +void NativeProgressCallback (DWORD progress, void* context) +{ + (void)progress; + (void)context; +} +#pragma managed(pop) +static void ManagedThunk (DWORD progress, void *context) +{ + if (context == nullptr) return; + GCHandle handle = GCHandle::FromIntPtr (IntPtr (context)); + auto cb = (InstallProgressCallbackDelegate ^)handle.Target; + if (cb != nullptr) cb (progress); +} +HRESULT AddAppxPackageFromPath ( + const std::wstring &pkgpath, + const std::vector &deplist, + DWORD deployoption, + InstallProgressCallbackDelegate ^callback, + std::wstring &errorcode, + std::wstring &detailmsg +) +{ + std::vector bytes (sizeof (REGISTER_PACKAGE_DEFENDENCIES) + sizeof (LPWSTR) * deplist.size ()); + auto lpdeplist = (PREGISTER_PACKAGE_DEFENDENCIES)bytes.data (); + lpdeplist->dwSize = (DWORD)deplist.size (); + for (size_t i = 0; i < deplist.size (); ++i) + lpdeplist->alpDepUris [i] = (LPWSTR)deplist [i].c_str (); + GCHandle handle; + void *ctx = nullptr; + PKGMRR_PROGRESSCALLBACK pfnCallback = nullptr; + if (callback != nullptr) { - auto pi = pkginfo::parse (it); - if (pi.valid) - { - hasread.insert (it); - g_pkginfo.push_back (pi); - } + handle = GCHandle::Alloc (callback); + ctx = (void *)GCHandle::ToIntPtr (handle).ToPointer (); + pfnCallback = (PKGMRR_PROGRESSCALLBACK)&ManagedThunk; // й thunk native } - g_pkgfiles.clear (); - for (auto &it : hasread) g_pkgfiles.insert (it); - return hasread.size (); + LPWSTR lperr = nullptr, lpmsg = nullptr; + destruct relt ([&] () { + if (lperr) PackageManagerFreeString (lperr); + if (lpmsg) PackageManagerFreeString (lpmsg); + lperr = nullptr; + lpmsg = nullptr; + }); + HRESULT hr = AddAppxPackageFromPath ( + pkgpath.c_str (), + lpdeplist, + deployoption, + pfnCallback, + ctx, + &lperr, + &lpmsg + ); + if (callback != nullptr && handle.IsAllocated) handle.Free (); + errorcode = lperr ? lperr : L""; + detailmsg = lpmsg ? lpmsg : L""; + return hr; +} +HRESULT UpdateAppxPackageFromPath ( + const std::wstring &pkgpath, + const std::vector &deplist, + DWORD deployoption, + InstallProgressCallbackDelegate ^callback, + std::wstring &errorcode, + std::wstring &detailmsg +) +{ + std::vector bytes (sizeof (REGISTER_PACKAGE_DEFENDENCIES) + sizeof (LPWSTR) * deplist.size ()); + auto lpdeplist = (PREGISTER_PACKAGE_DEFENDENCIES)bytes.data (); + lpdeplist->dwSize = (DWORD)deplist.size (); + for (size_t i = 0; i < deplist.size (); ++i) + lpdeplist->alpDepUris [i] = (LPWSTR)deplist [i].c_str (); + GCHandle handle; + void *ctx = nullptr; + PKGMRR_PROGRESSCALLBACK pfnCallback = nullptr; + if (callback != nullptr) + { + handle = GCHandle::Alloc (callback); + ctx = (void *)GCHandle::ToIntPtr (handle).ToPointer (); + pfnCallback = (PKGMRR_PROGRESSCALLBACK)&ManagedThunk; // й thunk native + } + LPWSTR lperr = nullptr, lpmsg = nullptr; + destruct relt ([&] () { + if (lperr) PackageManagerFreeString (lperr); + if (lpmsg) PackageManagerFreeString (lpmsg); + lperr = nullptr; + lpmsg = nullptr; + }); + HRESULT hr = UpdateAppxPackageFromPath ( + pkgpath.c_str (), + lpdeplist, + deployoption, + pfnCallback, + ctx, + &lperr, + &lpmsg + ); + if (callback != nullptr && handle.IsAllocated) handle.Free (); + errorcode = lperr ? lperr : L""; + detailmsg = lpmsg ? lpmsg : L""; + return hr; } [ComVisible (true)] public ref class MainHtmlWnd: public System::Windows::Forms::Form @@ -284,6 +442,9 @@ public ref class MainHtmlWnd: public System::Windows::Forms::Form private: WebBrowser ^webui; SplashForm ^splash; + String ^pagetag = "splash"; + InstallType insmode = InstallType::normal; + size_t nowinstall = 0; public: [ComVisible (true)] ref class IBridge @@ -292,6 +453,30 @@ public ref class MainHtmlWnd: public System::Windows::Forms::Form MainHtmlWnd ^wndinst = nullptr; public: IBridge (MainHtmlWnd ^wnd): wndinst (wnd) {} + ref class _I_HResult + { + private: + HRESULT hr = S_OK; + String ^errorcode = ""; + String ^detailmsg = ""; + public: + _I_HResult (HRESULT hres) + { + hr = hres; + detailmsg = CStringToMPString (HResultToMessage (hres)); + } + _I_HResult (HRESULT hres, String ^error, String ^message) + { + hr = hres; + errorcode = error; + detailmsg = message; + } + property HRESULT HResult { HRESULT get () { return hr; }} + property String ^ErrorCode { String ^get () { return errorcode; }} + property String ^Message { String ^get () { return detailmsg; }} + property bool Succeeded { bool get () { return SUCCEEDED (hr); }} + property bool Failed { bool get () { return FAILED (hr); }} + }; ref class _I_System { private: @@ -333,6 +518,29 @@ public ref class MainHtmlWnd: public System::Windows::Forms::Form void ShowSplash () { if (wndinst->SplashScreen->IsHandleCreated) wndinst->SplashScreen->Show (); else wndinst->SplashScreen->ReInit (); } void FadeAwaySplash () { wndinst->SplashScreen->FadeAway (); } void FadeOutSplash () { wndinst->SplashScreen->FadeOut (); } + property String ^ThemeColor { String ^get () { return ColorToHtml (GetDwmThemeColor ()); } } + property bool DarkMode { bool get () { return IsAppInDarkMode (); }} + property String ^HighContrast + { + String ^get () + { + auto highc = GetHighContrastTheme (); + switch (highc) + { + case HighContrastTheme::None: return "none"; + break; + case HighContrastTheme::Black: return "black"; + break; + case HighContrastTheme::White: return "white"; + break; + case HighContrastTheme::Other: return "high"; + break; + default: return "none"; + break; + } + return "none"; + } + } }; ref class _I_Resources { @@ -414,9 +622,26 @@ public ref class MainHtmlWnd: public System::Windows::Forms::Form String ^ToString () override { return Stringify (); } bool Valid () { return Major != 0 && Minor != 0 && Build != 0 && Revision != 0; } }; + ref class _I_Locale + { + public: + property String ^CurrentLocale { String ^get () { return CStringToMPString (GetComputerLocaleCodeW ()); } } + property LCID CurrentLCID { LCID get () { return LocaleCodeToLcid (GetComputerLocaleCodeW ()); } } + String ^ToLocaleName (LCID lcid) { return CStringToMPString (LcidToLocaleCodeW (lcid)); } + LCID ToLCID (String ^localename) { return LocaleCodeToLcidW (MPStringToStdW (localename)); } + Object ^LocaleInfo (LCID lcid, LCTYPE lctype) { return CStringToMPString (GetLocaleInfoW (lcid, lctype)); } + Object ^LocaleInfoEx (String ^localeName, LCTYPE lctype) + { + std::wstring output = L""; + int ret = GetLocaleInfoEx (MPStringToStdW (localeName), lctype, output); + if (output.empty ()) return ret; + else return CStringToMPString (output); + } + }; private: _I_UI ^ui = gcnew _I_UI (wndinst); _I_Resources ^ires = gcnew _I_Resources (); + _I_Locale ^locale = gcnew _I_Locale (); public: _I_System (MainHtmlWnd ^wnd): wndinst (wnd) {} property _I_UI ^UI { _I_UI ^get () { return ui; } } @@ -448,6 +673,7 @@ public ref class MainHtmlWnd: public System::Windows::Forms::Form #pragma warning(pop) } } + property _I_Locale ^Locale { _I_Locale ^get () { return locale; }} property bool IsWindows10 { bool get () @@ -475,6 +701,26 @@ public ref class MainHtmlWnd: public System::Windows::Forms::Form void set (int value) { return wndinst->PageScale = value; } } property int Version { int get () { return GetInternetExplorerVersionMajor (); }} + String ^ParseHtmlColor (String ^color) + { + auto dcolor = Drawing::ColorTranslator::FromHtml (color); + { + rapidjson::Document doc; + doc.SetObject (); + auto &alloc = doc.GetAllocator (); + doc.AddMember ("r", (uint16_t)dcolor.R, alloc); + doc.AddMember ("g", (uint16_t)dcolor.G, alloc); + doc.AddMember ("b", (uint16_t)dcolor.B, alloc); + doc.AddMember ("a", (uint16_t)dcolor.A, alloc); + rapidjson::StringBuffer buffer; + rapidjson::Writer writer (buffer); + doc.Accept (writer); + std::string utf8 = buffer.GetString (); + std::wstring_convert > conv; + return CStringToMPString (conv.from_bytes (utf8)); + } + return "{}"; + } }; ref class _I_Storage { @@ -509,11 +755,85 @@ public ref class MainHtmlWnd: public System::Windows::Forms::Form } String ^ToLower (String ^src) { return CStringToMPString (StringToLower (MPStringToStdW (src))); } String ^ToUpper (String ^src) { return CStringToMPString (StringToUpper (MPStringToStdW (src))); } + String ^Format (String ^fmt, ... array ^args) { return FormatString (fmt, args); } + String ^FormatInnerHTML (String ^fmt, ... array ^args) + { + std::wstring ihtml = EscapeToInnerXml (MPStringToStdW (fmt)); + auto pih = CStringToMPString (ihtml); + auto newargs = gcnew array (args->Length); + for (size_t i = 0; i < args->Length; i ++) + { + auto %p = newargs [i]; + p = Format ("{0}", EscapeToInnerXml (Format ("{0}", args [i]))); + } + return Format (pih, newargs); + } }; ref class _I_Package { public: - + ref class _I_Package_Manager + { + public: + _I_Package_Manager () {} + }; + private: + _I_Package_Manager ^mgr = gcnew _I_Package_Manager (); + public: + String ^GetPackagesToJson () + { + rapidjson::Document doc; + doc.SetArray (); + auto &alloc = doc.GetAllocator (); + for (auto &it : g_pkginfo) + { + rapidjson::Value member (rapidjson::kStringType); + member.SetString (ws2utf8 (it.filepath).c_str (), alloc); + doc.PushBack (member, alloc); + } + rapidjson::StringBuffer buffer; + rapidjson::Writer writer (buffer); + doc.Accept (writer); + std::string utf8 = buffer.GetString (); + std::wstring_convert > conv; + return CStringToMPString (conv.from_bytes (utf8)); + } + String ^GetPackageInfoToJson (String ^filepath) + { + std::wstring fpath = MPStringToStdW (filepath); + for (auto &it : g_pkginfo) + { + if (PathEquals (it.filepath, fpath)) + { + return CStringToMPString (it.parseJson ()); + } + } + return "{}"; + } + property _I_Package_Manager ^Manager { _I_Package_Manager ^get () { return mgr; }} + String ^GetCapabilityDisplayName (String ^capabilityName) + { + return CStringToMPString (GetPackageCapabilityDisplayName (MPStringToStdW (capabilityName))); + } + _I_HResult ^GetPackageInstallResult (String ^filepath) + { + std::wstring path = MPStringToStdW (filepath); + if (g_pkgresult.find (path) == g_pkgresult.end ()) return nullptr; + auto &pres = g_pkgresult.at (path); + return gcnew _I_HResult ( + pres.result, + CStringToMPString (pres.error), + CStringToMPString (pres.reason) + ); + } + }; + ref class _I_Window + { + private: + MainHtmlWnd ^wndinst = nullptr; + public: + _I_Window (MainHtmlWnd ^wnd): wndinst (wnd) {} + Object ^CallEvent (String ^name, ... array ^args) { return wndinst->CallEvent (name, args [0]); } }; private: _I_System ^system = gcnew _I_System (wndinst); @@ -521,39 +841,50 @@ public ref class MainHtmlWnd: public System::Windows::Forms::Form _I_Storage ^storage = gcnew _I_Storage (wndinst); _I_String ^str = gcnew _I_String (); _I_Package ^pkg = gcnew _I_Package (); + _I_Window ^wnd = gcnew _I_Window (wndinst); public: property _I_System ^System { _I_System ^get () { return system; }} property _I_IEFrame ^IEFrame { _I_IEFrame ^get () { return ieframe; }} property _I_Storage ^Storage { _I_Storage ^get () { return storage; }} property _I_String ^String { _I_String ^get () { return str; }} property _I_Package ^Package { _I_Package ^get () { return pkg; }} + property _I_Window ^Window { _I_Window ^get () { return wnd; }} }; protected: property WebBrowser ^WebUI { WebBrowser ^get () { return this->webui; } } property SplashForm ^SplashScreen { SplashForm ^get () { return this->splash; } } property int DPIPercent { int get () { return GetDPI (); }} property double DPI { double get () { return DPIPercent * 0.01; }} + property String ^PageTag { String ^get () { return GetPage (); } void set (String ^tag) { SetPage (tag); }} void InitSize () { unsigned ww = 0, wh = 0; auto &ini = g_initfile; auto setsect = ini ["Settings"]; - if (setsect [L"SavePosAndSizeBeforeCancel"].read_bool ()) + auto savepos = setsect [L"AppInstaller:SavePosAndSizeBeforeCancel"]; + auto lastw = setsect [L"AppInstaller:LastWidth"]; + auto lasth = setsect [L"AppInstaller:LastHeight"]; + auto defw = setsect [L"AppInstaller:DefaultWidth"]; + auto defh = setsect [L"AppInstaller:DefaultHeight"]; + auto minw = setsect [L"AppInstaller:MinimumWidth"]; + auto minh = setsect [L"AppInstaller:MinimumHeight"]; + auto lasts = setsect [L"AppInstaller:LastWndState"]; + if (savepos.read_bool ()) { - ww = setsect [L"LastWidth"].read_uint (setsect [L"DefaultWidth"].read_uint (rcInt (IDS_DEFAULTWIDTH))); - wh = setsect [L"LastHeight"].read_uint (setsect [L"DefaultHeight"].read_uint (rcInt (IDS_DEFAULTHEIGHT))); + ww = lastw.read_uint (defw.read_uint (rcInt (IDS_DEFAULTWIDTH))); + wh = lastw.read_uint (defh.read_uint (rcInt (IDS_DEFAULTHEIGHT))); } else { - ww = setsect [L"DefaultWidth"].read_uint (rcInt (IDS_DEFAULTWIDTH)); - wh = setsect [L"DefaultHeight"].read_uint (rcInt (IDS_DEFAULTHEIGHT)); + ww = defw.read_uint (rcInt (IDS_DEFAULTWIDTH)); + wh = defw.read_uint (rcInt (IDS_DEFAULTHEIGHT)); } this->MinimumSize = System::Drawing::Size ( - setsect [L"MinimumWidth"].read_uint (rcInt (IDS_MINWIDTH)) * DPI, - setsect [L"MinimumHeight"].read_uint (rcInt (IDS_MINHIEHGT)) * DPI + minw.read_uint (rcInt (IDS_MINWIDTH)) * DPI, + minh.read_uint (rcInt (IDS_MINHIEHGT)) * DPI ); this->ClientSize = System::Drawing::Size (ww * DPI, wh * DPI); - this->WindowState = (System::Windows::Forms::FormWindowState)setsect [L"LastWndState"].read_int ((int)System::Windows::Forms::FormWindowState::Normal); + this->WindowState = (System::Windows::Forms::FormWindowState)lasts.read_int ((int)System::Windows::Forms::FormWindowState::Normal); } void Init () { @@ -585,8 +916,15 @@ public ref class MainHtmlWnd: public System::Windows::Forms::Form ExecScript ("Windows.UI.DPI.mode = 1"); ExecScript ("Bridge.Frame.scale = Bridge.Frame.scale * Bridge.UI.dpi"); - // splash->FadeOut (); + auto &ini = g_initfile; + auto setsect = ini ["Settings"]; + auto lwr = setsect [L"AppInstaller:LaunchWhenReady"]; + bool launchwhenready = lwr.read_bool (true); + if (g_wcmdflags & (DWORD)CMDPARAM::SILENT) launchwhenready = false; + InvokeCallScriptFunction ("setLaunchWhenReady", launchwhenready, g_wcmdflags & (DWORD)CMDPARAM::SILENT); + SetPage ("splash"); splash->FadeAway (); + ThreadPackageLoadTask (); } } void OnCreate (System::Object ^sender, System::EventArgs ^e) @@ -632,9 +970,417 @@ public ref class MainHtmlWnd: public System::Windows::Forms::Form "}) ();" ); } + System::Threading::Thread ^ThreadPackageLoadTask () + { + auto thread = gcnew Threading::Thread (gcnew Threading::ThreadStart (this, &MainHtmlWnd::PackageLoadTask)); + thread->IsBackground = true; + thread->Start (); + return thread; + } void PackageLoadTask () { - if (!g_pkginfo.size ()) + bool res = ReadPackagesTask (gcnew Action (this, &MainHtmlWnd::ReadPackageCallback)); + InvokeCallScriptFunction ("setSplashPageStatusText", ""); + if (res) + { + String ^fmt = GetRCStringCli (IDS_PREINSTALL_TITLE); + String ^btn1 = GetRCStringCli (IDS_PREINSTALL_TINSTALL); + String ^btn2 = GetRCStringCli (IDS_PREINSTALL_CANCEL); + if (g_pkginfo.size () == 1) + { + try + { + const auto &pi = *g_pkginfo.begin (); + const std::wstring + &name = pi.identity.name, + &publisher = pi.identity.publisher, + &family = pi.identity.package_family_name, + &fullname = pi.identity.package_full_name; + std::vector fpkgs; + std::wstring err, msg; + HRESULT hr = GetAppxPackages (family, fpkgs, err, msg); + bool isfind = false; + find_pkginfo findpkg; + if (fpkgs.size () > 0) + { + for (auto &it : fpkgs) + { + if (it.identity.name != pi.identity.name) continue; + auto archs = pi.get_architectures (); + for (auto &arch : archs) + { + if (arch == it.identity.architecture) + { + isfind = true; + findpkg = it; + break; + } + else if (arch == 11 || it.identity.architecture == 11) + { + isfind = true; + findpkg = it; + break; + } + } + if (isfind) break; + if (it.properties.resource_package && pi.properties.resource_package && it.identity.resource_id == pi.identity.resource_id) + { + isfind = true; + findpkg = it; + break; + } + if (archs.size () == 0 && it.identity.architecture == (WORD)-1) + { + isfind = true; + findpkg = it; + break; + } + } + } + if (isfind) + { + version fver = findpkg.identity.version, + pver (pi.identity.realver.major, pi.identity.realver.minor, pi.identity.realver.build, pi.identity.realver.revision); + if (pver > fver) // ģʽ + { + insmode = InstallType::update; + fmt = GetRCStringCli (IDS_PREINSTALL_TUPDATE); + btn1 = GetRCStringCli (IDS_PREINSTALL_CUPDATE); + btn2 = GetRCStringCli (IDS_PREINSTALL_CANCEL); + } + else if (pver == fver) + { + insmode = InstallType::reinstall; + fmt = GetRCStringCli (IDS_PREINSTALL_TREINSTALL); + btn1 = GetRCStringCli (IDS_PREINSTALL_CREINSTALL); + btn2 = GetRCStringCli (IDS_SUCCESS_LAUNCH); + } + else + { + insmode = InstallType::reinstall; + fmt = GetRCStringCli (IDS_PREINSTALL_HASINSTALLED); + btn1 = GetRCStringCli (IDS_PREINSTALL_CREINSTALL); + btn2 = GetRCStringCli (IDS_SUCCESS_LAUNCH); + } + } + } + catch (...) {} + } + InvokeCallScriptFunction ("noticeLoadPreinstallPage", g_pkginfo.size () > 1); + InvokeCallScriptFunction ("setPreinstallPagePkgTitleFormatSingle", fmt); + InvokeCallScriptFunction ("setControlButtonState", 1, btn1, true, false); + InvokeCallScriptFunction ("setControlButtonState", 2, btn2, true, false); + pagetag = "preinstall"; + if (g_wcmdflags & (DWORD)CMDPARAM::SILENT) ThreadPackageInstallTask (); + } + else + { + InvokeCallScriptFunction ("noticeLoadSelectPage", g_pkginfo.size () > 1); + pagetag = "select"; + } + } + void ReadPackageCallback (String ^lpPath) + { + size_t pkgfilelen = g_pkgfiles.size (); + if (pkgfilelen > 1) + { + InvokeCallScriptFunction ( + "setSplashPageStatusText", + System::String::Format (GetRCStringCli (IDS_SPLASH_MLOAD), lpPath) + ); + } + } + bool ReadPackagesTask (System::Action ^callback) + { + std::vector noread; + std::vector hasread; + for (auto &it : g_pkgfiles) + { + bool isfind = false; + for (auto &rit : g_pkginfo) + { + if (rit.filepath == it) + { + isfind == true; + push_unique (hasread, it); + break; + } + } + if (!isfind) push_unique (noread, it); + } + for (auto &it : noread) + { + try { if (callback) callback (gcnew String (it.c_str ())); } + catch (Exception ^e) { if (DEBUGMODE) OutputDebugStringW (MPStringToPtrW (e->Message)); } + auto pi = pkginfo::parse (it); + if (pi.valid) + { + push_unique (hasread, pi.filepath); + g_pkginfo.push_back (pi); + } + } + g_pkgfiles.clear (); + for (auto &it : hasread) push_unique (g_pkgfiles, it); + return hasread.size (); + } + void InstallProgressCallback (DWORD dwProgress) + { + InvokeCallScriptFunction ("setInstallingProgress", dwProgress); + InvokeCallScriptFunction ("setInstallingStatus", String::Format (GetRCStringCli (IDS_INSTALLING_SINSTALLING_PROGRESS), dwProgress)); + } + void InstallProgressCallbackMultiple (DWORD dwProgress) + { + double progress = (dwProgress * 0.01 + nowinstall) / (double)g_pkginfo.size () * 100; + InvokeCallScriptFunction ("setInstallingProgress", progress); + InvokeCallScriptFunction ("setInstallingStatus", String::Format (GetRCStringCli (IDS_INSTALLING_MSINSTALLING_PROGRESS), dwProgress, nowinstall + 1, g_pkginfo.size ())); + } + System::Threading::Thread ^ThreadPackageInstallTask () + { + auto thread = gcnew Threading::Thread (gcnew Threading::ThreadStart (this, &MainHtmlWnd::PackageInstallTask)); + thread->IsBackground = true; + thread->Start (); + return thread; + } + void PackageInstallTask () + { + InvokeCallScriptFunction ("noticeLoadInstallingPage", g_pkginfo.size () > 1); + std::vector blankdeplist; + if (g_pkginfo.size () == 1) + { + auto &pi = *g_pkginfo.begin (); + InvokeCallScriptFunction ("setInstallingStatus", GetRCStringCli (IDS_INSTALLING_SLOADCER)); + LoadCertFromSignedFile (pi.filepath.c_str ()); + InvokeCallScriptFunction ("setInstallingStatus", GetRCStringCli (IDS_INSTALLING_SINSTALLING)); + InvokeCallScriptFunction ("setInstallingProgress", 0); + package_installresult pir; + if (insmode == InstallType::update) + { + pir.result = UpdateAppxPackageFromPath (pi.filepath, blankdeplist, DEPOLYOPTION_NONE, gcnew InstallProgressCallbackDelegate (this, &MainHtmlWnd::InstallProgressCallback), pir.error, pir.reason); + if (FAILED (pir.result)) + pir.result = AddAppxPackageFromPath (pi.filepath, blankdeplist, DEPOLYOPTION_NONE, gcnew InstallProgressCallbackDelegate (this, &MainHtmlWnd::InstallProgressCallback), pir.error, pir.reason); + } + else + { + pir.result = AddAppxPackageFromPath (pi.filepath, blankdeplist, DEPOLYOPTION_NONE, gcnew InstallProgressCallbackDelegate (this, &MainHtmlWnd::InstallProgressCallback), pir.error, pir.reason); + } + g_pkgresult [pi.filepath] = pir; + if (pir.succeeded ()) + { + InvokeCallScriptFunction ("noticeLoadInstallSuccessPage", false); + pagetag = "installsuccess"; + CreateToastNoticeWithImgBase64 ( + g_identity, + MPStringToStdW ( + System::String::Format ( + GetRCStringCli (IDS_SUCCESS_TITLE), + CStringToMPString (pi.properties.display_name) + ) + ), + pi.properties.logo_base64 + ); + ThreadPackageSuccessInstallCountTask (); + } + else + { + InvokeCallScriptFunction ("noticeLoadInstallFailedPage", false); + pagetag = "installfailed"; + CreateToastNotice2WithImgBase64 ( + g_identity, + MPStringToStdW ( + System::String::Format ( + GetRCStringCli (IDS_FAILED_STITLE), + CStringToMPString (pi.properties.display_name) + ) + ), + pir.reason, + pi.properties.logo_base64 + ); + } + } + else + { + for (nowinstall = 0; nowinstall < g_pkginfo.size (); nowinstall ++) + { + auto &it = g_pkginfo.at (nowinstall); + InvokeCallScriptFunction ("setInstallingPackageInfoMultiple", CStringToMPString (it.filepath)); + InvokeCallScriptFunction ( + "setInstallingStatus", + String::Format ( + GetRCStringCli (IDS_INSTALLING_MLOADCER), + nowinstall + 1, + g_pkginfo.size () + ) + ); + LoadCertFromSignedFile (it.filepath.c_str ()); + InvokeCallScriptFunction ( + "setInstallingStatus", + String::Format ( + GetRCStringCli (IDS_INSTALLING_MPKGNAME), + nowinstall + 1, + g_pkginfo.size () + ) + ); + package_installresult pir; + pir.result = AddAppxPackageFromPath ( + it.filepath, + blankdeplist, + DEPOLYOPTION_NONE, + gcnew InstallProgressCallbackDelegate (this, &MainHtmlWnd::InstallProgressCallbackMultiple), + pir.error, + pir.reason + ); + g_pkgresult [it.filepath] = pir; + } + bool allsuccess = true; + for (auto &it : g_pkgresult) + { + allsuccess = allsuccess && it.second.succeeded (); + if (!allsuccess) break; + } + if (allsuccess) + { + InvokeCallScriptFunction ("noticeLoadInstallSuccessPage", true); + pagetag = "installsuccess"; + CreateToastNotice (g_identity, GetRCStringSW (IDS_SUCCESS_MTITLE), L""); + ThreadPackageSuccessInstallCountTask (); + } + else + { + InvokeCallScriptFunction ("noticeLoadInstallFailedPage", true); + CreateToastNotice (g_identity, GetRCStringSW (IDS_FAILED_MTITLE), L""); + pagetag = "installfailed"; + } + } + } + System::Threading::Thread ^ThreadPackageSuccessInstallCountTask () + { + auto thread = gcnew Threading::Thread (gcnew Threading::ThreadStart (this, &MainHtmlWnd::PackageSuccessInstallCountTask)); + thread->IsBackground = true; + thread->Start (); + return thread; + } + void PackageSuccessInstallCountTask () + { + System::Threading::Thread::Sleep (System::TimeSpan (0, 0, 5)); + this->InvokeClose (); + } + void InvokeClose () + { + if (this->InvokeRequired) this->Invoke (gcnew Action (this, &MainHtmlWnd::Close)); + else this->Close (); + } + String ^GetPage () { return pagetag; } + String ^SetPage (String ^tag) + { + InvokeCallScriptFunction ("setPage", tag, g_pkginfo.size () > 1); + return pagetag = tag; + } +#define nequals(_str1_, _str2_) IsNormalizeStringEquals (ToStdWString (_str1_), ToStdWString (_str2_)) + void OnPress_Button1 () + { + std::wstring current = MPStringToStdW (pagetag); + if (nequals (current, L"select")) + { + std::vector files; + std::wstring item1 = GetRCStringSW (IDS_SELECT_DLGAPPX), + item1type = L"*.appx;*.appxbundle", + item2 = GetRCStringSW (IDS_SELECT_DLGALL), + item2type = L"*.*"; + std::vector buf (item1.capacity () + item1type.capacity () + item2.capacity () + item2type.capacity () + 5); + strcpynull (buf.data (), item1.c_str (), buf.size ()); + strcpynull (buf.data (), item1type.c_str (), buf.size ()); + strcpynull (buf.data (), item2.c_str (), buf.size ()); + strcpynull (buf.data (), item2type.c_str (), buf.size ()); + ExploreFile ( + this->InvokeGetHWND (), + files, + buf.data (), + OFN_EXPLORER | OFN_ALLOWMULTISELECT | OFN_PATHMUSTEXIST, + GetRCStringSW (IDS_SELECT_DLGTITLE) + ); + if (files.empty ()) return; + for (auto &it : files) g_pkgfiles.push_back (it); + this->PageTag = "loading"; + ThreadPackageLoadTask (); + return; + } + else if (nequals (current, L"preinstall")) + { + if (g_pkginfo.size () == 1) + { + switch (insmode) + { + case InstallType::reinstall: + ThreadPackageInstallTask (); + break; + default: + case InstallType::normal: + case InstallType::update: + ThreadPackageInstallTask (); + break; + } + } + else ThreadPackageInstallTask (); + return; + } + else if (nequals (current, L"installsuccess")) + { + + } + else if (nequals (current, L"installfailed")) this->Close (); + return; + System::Windows::Forms::MessageBox::Show ("Button1 ¼"); + } + void OnPress_Button2 () + { + std::wstring current = MPStringToStdW (pagetag); + if (nequals (current, L"select")) + { + this->Close (); + return; + } + else if (nequals (current, L"preinstall")) + { + if (g_pkginfo.size () == 1) + { + switch (insmode) + { + case InstallType::reinstall: { + auto &pi = *g_pkginfo.begin (); + if (pi.applications.size () == 1) ActivateAppxApplication (pi.identity.package_family_name + L"!" + pi.applications.at (0).at (L"Id")); + + } break; + default: + case InstallType::normal: + case InstallType::update: + this->Close (); + break; + } + } + else + { + this->Close (); + } + return; + } + else if (nequals (current, L"installfailed")) this->Close (); + return; + System::Windows::Forms::MessageBox::Show ("Button2 ¼"); + } +#ifdef nequals +#undef nequals +#endif + IntPtr GetHWnd () { return this->Handle; } + delegate IntPtr GetHwndDelegate (); + HWND InvokeGetHWND () + { + if (this->InvokeRequired) + { + GetHwndDelegate ^del = gcnew GetHwndDelegate (this, &MainHtmlWnd::GetHWnd); + IntPtr result = safe_cast (this->Invoke (del)); + return static_cast (result.ToPointer ()); + } + else return static_cast (this->Handle.ToPointer ()); } public: MainHtmlWnd () @@ -681,6 +1427,13 @@ public ref class MainHtmlWnd: public System::Windows::Forms::Form return nullptr; } Object ^ExecScript (... array ^alpScript) { return InvokeCallScriptFunction ("eval", alpScript); } + Object ^CallEvent (String ^funcName, Object ^e) + { + std::wstring fname = MPStringToStdW (funcName); + if (IsNormalizeStringEquals (fname.c_str (), L"OnPress_Button1")) OnPress_Button1 (); + else if (IsNormalizeStringEquals (fname.c_str (), L"OnPress_Button2")) OnPress_Button2 (); + return nullptr; + } property int PageScale { int get () @@ -713,59 +1466,30 @@ using MainWnd = MainHtmlWnd; std::vector LoadFileListW (const std::wstring &filePath) { std::vector result; - HANDLE hFile = CreateFileW ( - filePath.c_str (), - GENERIC_READ, - FILE_SHARE_READ, - nullptr, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - nullptr); - - if (hFile == INVALID_HANDLE_VALUE) return result; - LARGE_INTEGER fileSize {}; - if (!GetFileSizeEx (hFile, &fileSize) || fileSize.QuadPart == 0) + std::wifstream file (filePath); + if (!file.is_open ()) return result; + file.imbue (std::locale (file.getloc (), new std::codecvt_utf8_utf16 )); + std::wstring line; + while (std::getline (file, line)) { - CloseHandle (hFile); - return result; - } - DWORD size = static_cast (fileSize.QuadPart); - std::vector buf; - std::wstring buffer; - buffer.resize (size / sizeof (wchar_t) + 2 + 2); - DWORD readBytes = 0; - ReadFile (hFile, buf.data (), size, &readBytes, nullptr); - buffer += buf.data (); - CloseHandle (hFile); - buffer [readBytes / sizeof (wchar_t)] = L'\0'; - size_t start = 0; - while (true) - { - size_t pos = buffer.find (L'\n', start); - std::wstring line; - if (pos == std::wstring::npos) - { - line = buffer.substr (start); - } - else - { - line = buffer.substr (start, pos - start); - start = pos + 1; - } if (!line.empty () && line.back () == L'\r') line.pop_back (); - if (!line.empty ()) result.push_back (line); - if (pos == std::wstring::npos) break; + if (!line.empty () && !std::wnstring::empty (line) && IsFileExists (line)) result.push_back (line); } return result; } -enum class CMDPARAM: DWORD + +std::wstring GenerateCmdHelper () { - NONE = 0b000, - SILENT = 0b001, - VERYSILENT = 0b011, - MULTIPLE = 0b100 -}; -DWORD CmdMapsToFlags (std::map cmdpairs, std::set &files, std::set &uris) + std::wstring ret = GetRCStringSW (IDS_CMDTIP_PRETEXT) + L"\r\n"; + for (auto &it : g_argslist) + { + ret += L"\r\n"; + ret += L"\t" + (it.prefixs.size () ? it.prefixs.at (0) : L"") + it.commands.at (0) + L"\r\n"; + ret += L"\t" + it.description + L"\r\n"; + } + return ret; +} +DWORD CmdMapsToFlags (std::map cmdpairs, std::vector &files = std::vector (), std::vector &uris = std::vector ()) { DWORD dwret = 0; for (auto &it : cmdpairs) @@ -773,10 +1497,10 @@ DWORD CmdMapsToFlags (std::map cmdpairs, std::set cmdpairs, std::set cmdpairs, std::set 1) dwret |= (DWORD)CMDPARAM::MULTIPLE; return dwret; } + HRESULT SetCurrentAppUserModelID (PCWSTR appID) { typedef HRESULT (WINAPI *SetAppUserModelIDFunc)(PCWSTR); @@ -840,15 +1565,22 @@ int APIENTRY wWinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCm std::wnstring rootdir = GetProgramRootDirectoryW (); if (!PathEquals (currdir, rootdir)) SetCurrentDirectoryW (rootdir.c_str ()); } - CoInitializeEx (NULL, COINIT_MULTITHREADED); + CoInitializeEx (NULL, COINIT_MULTITHREADED | COINIT_APARTMENTTHREADED); destruct relco ([] () { CoUninitialize (); }); { std::map pair_cmdkv; ParseCmdLine (lpCmdLine, pair_cmdkv); - std::set uris; - g_wcmdflags = CmdMapsToFlags (pair_cmdkv, g_pkgfiles, uris); + for (auto pair : pair_cmdkv) + { + if (pair.first.key == std::wnstring (L"help")) + { + MessageBox (nullptr, GenerateCmdHelper ().c_str (), GetRCStringSW (IDS_WINTITLE).c_str (), 0); + return 0; + } + } + g_wcmdflags = CmdMapsToFlags (pair_cmdkv, g_pkgfiles); } System::Windows::Forms::Application::EnableVisualStyles (); System::Windows::Forms::Application::SetCompatibleTextRenderingDefault (false); diff --git a/appinstaller/resmap.h b/appinstaller/resmap.h index 4f6ec57..3133189 100644 --- a/appinstaller/resmap.h +++ b/appinstaller/resmap.h @@ -38,7 +38,7 @@ std::map g_nameToId = { MAKENAMEIDMAP (IDS_LAUNCHWHENREADY), MAKENAMEIDMAP (IDS_SUCCESS_TITLE), MAKENAMEIDMAP (IDS_SUCCESS_MTITLE), - MAKENAMEIDMAP (IDS_FAILED_TITLE), + MAKENAMEIDMAP (IDS_FAILED_MTITLE), MAKENAMEIDMAP (IDS_FAILED_REASONNAME), MAKENAMEIDMAP (IDS_SUCCESS_LAUNCH), MAKENAMEIDMAP (IDS_COMMAND_CANCEL), @@ -48,6 +48,35 @@ std::map g_nameToId = { MAKENAMEIDMAP (IDS_DEFAULTWIDTH), MAKENAMEIDMAP (IDS_DEFAULTHEIGHT), MAKENAMEIDMAP (IDS_MINWIDTH), - MAKENAMEIDMAP (IDS_MINHIEHGT) + MAKENAMEIDMAP (IDS_MINHIEHGT), + MAKENAMEIDMAP (IDS_SPLASH_MLOAD), + MAKENAMEIDMAP (IDS_MOREINFO_IDNAME), + MAKENAMEIDMAP (IDS_MOREINFO_IDPUBLISHER), + MAKENAMEIDMAP (IDS_MOREINFO_IDVERSION), + MAKENAMEIDMAP (IDS_MOREINFO_IDFAMILY), + MAKENAMEIDMAP (IDS_MOREINFO_IDFULL), + MAKENAMEIDMAP (IDS_MOREINFO_IDARCH), + MAKENAMEIDMAP (IDS_MOREINFO_PROPFREAMWORK), + MAKENAMEIDMAP (IDS_MOREINFO_PROPRESPKG), + MAKENAMEIDMAP (IDS_MOREINFO_PROPYES), + MAKENAMEIDMAP (IDS_MOREINFO_PROPNO), + MAKENAMEIDMAP (IDS_MOREINFO_INFOSYS), + MAKENAMEIDMAP (IDS_MOREINFO_INFOSYS_VALUE), + MAKENAMEIDMAP (IDS_MOREINFO_INFOLANG), + MAKENAMEIDMAP (IDS_MOREINFO_ID), + MAKENAMEIDMAP (IDS_MOREINFO_PROP), + MAKENAMEIDMAP (IDS_MOREINFO_INFO), + MAKENAMEIDMAP (IDS_CMDPARAM_HELP), + MAKENAMEIDMAP (IDS_CMDTIP_PRETEXT), + MAKENAMEIDMAP (IDS_DEFAULTWIDTH), + MAKENAMEIDMAP (IDS_DEFAULTHEIGHT), + MAKENAMEIDMAP (IDS_MINWIDTH), + MAKENAMEIDMAP (IDS_MINHIEHGT), + MAKENAMEIDMAP (IDS_INSTALLING_MLOADCER), + MAKENAMEIDMAP (IDS_FAILED_MSUCCESS), + MAKENAMEIDMAP (IDS_FAILED_STITLE) }; +#ifdef MAKENAMEIDMAP +#undef MAKENAMEIDMAP +#endif \ No newline at end of file diff --git a/appinstaller/resource.h b/appinstaller/resource.h index 9a29546..58b4eb5 100644 Binary files a/appinstaller/resource.h and b/appinstaller/resource.h differ diff --git a/appinstaller/themeinfo.h b/appinstaller/themeinfo.h index d1c4fe3..c9670b7 100644 --- a/appinstaller/themeinfo.h +++ b/appinstaller/themeinfo.h @@ -47,16 +47,14 @@ System::Drawing::Color GetDwmThemeColor () BOOL opaqueBlend = FALSE; // DwmGetColorizationColor ȡ Aero ɫ HRESULT hr = DwmGetColorizationColor (&color, &opaqueBlend); - if (SUCCEEDED (hr)) { + if (SUCCEEDED (hr)) + { BYTE r = (BYTE)((color & 0x00FF0000) >> 16); BYTE g = (BYTE)((color & 0x0000FF00) >> 8); BYTE b = (BYTE)(color & 0x000000FF); return System::Drawing::Color::FromArgb (r, g, b); } - else { - // ȡʧܣĬɫ - return System::Drawing::Color::FromArgb (0, 120, 215); - } + else return System::Drawing::Color::FromArgb (0, 120, 215); // ȡʧܣĬɫ } String ^ColorToHtml (System::Drawing::Color color) { diff --git a/appinstaller/typestrans.h b/appinstaller/typestrans.h index 7abde9b..cba9e5f 100644 --- a/appinstaller/typestrans.h +++ b/appinstaller/typestrans.h @@ -8,11 +8,13 @@ #include #include #include +#include #else #include #include #include #include +#include #endif unsigned _wtou (const wchar_t *str) { diff --git a/notice/dllmain.cpp b/notice/dllmain.cpp index 86ed57f..062bafe 100644 --- a/notice/dllmain.cpp +++ b/notice/dllmain.cpp @@ -10,13 +10,13 @@ BOOL APIENTRY DllMain( HMODULE hModule, { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: - CoInitializeEx (NULL, COINIT_MULTITHREADED); - RoInitialize (RO_INIT_MULTITHREADED); + // CoInitializeEx (NULL, COINIT_MULTITHREADED); + // RoInitialize (RO_INIT_MULTITHREADED); break; case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: - CoUninitialize (); - RoUninitialize (); + // CoUninitialize (); + // RoUninitialize (); break; } return TRUE; diff --git a/notice/notice.cpp b/notice/notice.cpp index 2e79fc9..156deb7 100644 --- a/notice/notice.cpp +++ b/notice/notice.cpp @@ -25,7 +25,31 @@ std::wstring GetFullPathName (const std::wstring &lpFileName) if (result == 0) return L""; return std::wstring (buffer.data (), result); } - +LPWSTR AllocWideString (const std::wstring &str) +{ + size_t size = (str.length () + 1) * sizeof (WCHAR); + LPWSTR buf = (LPWSTR)CoTaskMemAlloc (size); + if (!buf) return nullptr; + ZeroMemory (buf, size); + wcscpy (buf, str.c_str ()); + return buf; +} +// +LPWSTR AllocWideString (LPCWSTR str) +{ + if (!str) return nullptr; + size_t size = (wcslen (str) + 1) * sizeof (WCHAR); + LPWSTR buf = (LPWSTR)CoTaskMemAlloc (size); + if (!buf) return nullptr; + ZeroMemory (buf, size); + wcscpy (buf, str); + return buf; +} +#define _wcsdup AllocWideString +#define free CoTaskMemFree +#define malloc CoTaskMemAlloc +#define realloc CoTaskMemRealloc +#define calloc(_cnt_, _size_) CoTaskMemAlloc (_cnt_ * _size_) struct destruct { std::function endtask = nullptr; @@ -243,6 +267,7 @@ Windows::Data::Xml::Dom::XmlDocument ^SimpleToastNoticeXml2 (const std::wstring { case 1: templatename = L"ToastText01"; break; // case 3: templatename = L"ToastText02"; break; // + + case 6: case 5: templatename = L"ToastImageAndText01"; break; // ͼ + case 7: templatename = L"ToastImageAndText02"; break; // ͼ + + default: templatename = L"ToastText01"; break; @@ -342,12 +367,12 @@ HRESULT CreateToastNoticeFromXml (const std::wstring &lpIdName, Windows::Data::X else notifier = ToastMgr::CreateToastNotifier (); auto &xmldoc = pIXml; auto toast = ref new Toast (xmldoc); - toast->Activated += ref new Windows::Foundation::TypedEventHandler < - Windows::UI::Notifications::ToastNotification ^, - Platform::Object ^ - > ([=] (Windows::UI::Notifications::ToastNotification ^sender, Platform::Object ^args) { - if (pfCallback) pfCallback (pCustom); - }); + //toast->Activated += ref new Windows::Foundation::TypedEventHandler < + // Windows::UI::Notifications::ToastNotification ^, + // Platform::Object ^ + //> ([=] (Windows::UI::Notifications::ToastNotification ^sender, Platform::Object ^args) { + // if (pfCallback) pfCallback (pCustom); + //}); notifier->Show (toast); return hr = S_OK; } @@ -445,7 +470,7 @@ std::wstring IStreamToTempFile (IStream *p, const std::wstring &ext = L".tmp") if (FAILED (hr)) throw Platform::Exception::CreateException (hr); LARGE_INTEGER liZero = {}; stream->Seek (liZero, STREAM_SEEK_SET, nullptr); - HANDLE hFile = CreateFileW (outpath.c_str (), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, nullptr); + HANDLE hFile = CreateFileW (outpath.c_str (), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, nullptr); const size_t bufsize = 4096; BYTE buf [bufsize] = {0}; ULONG bytesRead = 0; @@ -554,3 +579,71 @@ HRESULT CreateShortcutWithAppIdW (LPCWSTR pszShortcutPath, LPCWSTR pszTargetPath else pPersistFile = nullptr; return hr; } + +void NoticeApiFreeString (LPWSTR lpstr) +{ + if (!lpstr) return; + CoTaskMemFree (lpstr); +} + +size_t Base64ToBytes (const std::wstring &base64OrDataUri, std::vector &retbytes) +{ + retbytes.clear (); + std::wstring base64 = base64OrDataUri; + size_t commaPos = base64.find (L','); + if (commaPos != std::wstring::npos) base64 = base64.substr (commaPos + 1); + DWORD binLen = 0; + if (!CryptStringToBinaryW (base64.c_str (), static_cast (base64.length ()), CRYPT_STRING_BASE64, nullptr, &binLen, nullptr, nullptr)) + return 0; + retbytes.resize (binLen); + if (!CryptStringToBinaryW (base64.c_str (), static_cast (base64.length ()), CRYPT_STRING_BASE64, retbytes.data (), &binLen, nullptr, nullptr)) + { + retbytes.clear (); + return 0; // ʧ + } + return binLen; +} +HRESULT BytesToIStream (const std::vector &data, IStream **ppStream) +{ + if (!ppStream) return E_POINTER; + *ppStream = nullptr; + HGLOBAL hMem = GlobalAlloc (GMEM_MOVEABLE, data.size ()); + if (!hMem) return E_OUTOFMEMORY; + void *pMem = GlobalLock (hMem); + if (!pMem) + { + GlobalFree (hMem); + return E_FAIL; + } + memcpy (pMem, data.data (), data.size ()); + GlobalUnlock (hMem); + HRESULT hr = CreateStreamOnHGlobal (hMem, TRUE, ppStream); + if (FAILED (hr)) GlobalFree (hMem); + return hr; +} +HRESULT CreateToastNoticeWithImgBase64 (LPCWSTR lpIdName, LPCWSTR lpText, LPCWSTR lpImgBase64, NOTICE_ACTIVECALLBACK pfCallback, void *pCustom, LPWSTR *lpExceptMsg) +{ + IStream *ist = nullptr; + destruct relt ([&ist] () { + if (ist) ist->Release (); + ist = nullptr; + }); + std::vector bytes; + Base64ToBytes (lpImgBase64 ? lpImgBase64 : L"", bytes); + if (bytes.size ()) + { if (FAILED (BytesToIStream (bytes, &ist))) ist = nullptr; } + return CreateToastNoticeWithIStream (lpIdName, lpText, ist, pfCallback, pCustom, lpExceptMsg); +} +HRESULT CreateToastNotice2WithImgBase64 (LPCWSTR lpIdName, LPCWSTR lpTitle, LPCWSTR lpText, LPCWSTR lpImgBase64, NOTICE_ACTIVECALLBACK pfCallback, void *pCustom, LPWSTR *lpExceptMsg) +{ + IStream *ist = nullptr; + destruct relt ([&ist] () { + if (ist) ist->Release (); + ist = nullptr; + }); + std::vector bytes; + Base64ToBytes (lpImgBase64 ? lpImgBase64 : L"", bytes); + if (bytes.size ()) + { if (FAILED (BytesToIStream (bytes, &ist))) ist = nullptr; } + return CreateToastNoticeWithIStream2 (lpIdName, lpTitle, lpText, ist, pfCallback, pCustom, lpExceptMsg); +} \ No newline at end of file diff --git a/notice/notice.h b/notice/notice.h index 7991e53..078d78f 100644 --- a/notice/notice.h +++ b/notice/notice.h @@ -31,16 +31,16 @@ extern "C" // οhttps://learn.microsoft.com/zh-cn/previous-versions/windows/apps/hh761494(v=win.10) // ͨ Toast ֪ͨȡ XML ģ塣 // ϻ᷵һĬģ壨ֻһ text ڵ㡣ҪĻԼӣ - // ע⣺صָҪԼ free ͷ + // ע⣺صָҪԼ NoticeApiFreeString ͷ NOTICE_API LPWSTR GetToastNoticeXml (LPCWSTR lpTemplateName); // ȡһ򵥵 Toast ֪ͨ XML ĵһDZġڶΪͼƬ URIfile:/// // ڶΪ NULL ȥβյijΪ 0 ı򲻻ʹôͼƬģ塣 - // ע⣺صָҪԼͨ free ͷ + // ע⣺صָҪԼͨ NoticeApiFreeString ͷ NOTICE_API LPWSTR GenerateSimpleToastNoticeXml (LPCWSTR lpText, LPCWSTR lpImagePath); // ȡһ򵥵 Toast ֪ͨ XML ĵһDZġΪͼƬ URIfile:/// // Ϊ NULL ȥβյijΪ 0 ı򲻻ʹôͼƬģ塣 // ڶΪ NULL ıΪʱʹģ - // ע⣺صָҪԼͨ free ͷ + // ע⣺صָҪԼͨ NoticeApiFreeString ͷ NOTICE_API LPWSTR GenerateSimpleToastNoticeXml2 (LPCWSTR lpTitle, LPCWSTR lpText, LPCWSTR lpImagePath); // ʾһ Toast ֪ͨ // 1 ΪDZζſԴ NULL ıǽӦ @@ -48,7 +48,7 @@ extern "C" // Windows 10 Ѿȥ // pfCallback Ϊ Toast ֪ͨ󴥷Ļصע⣺ڲãҲһóɹ // pCustom ԴԶݲڻصʹ - // lpExceptMsg 쳣Ϣȡָ free ͷš + // lpExceptMsg 쳣Ϣȡָ NoticeApiFreeString ͷš NOTICE_API HRESULT CreateToastNoticeFromXmlDocument (LPCWSTR lpIdName, LPCWSTR lpXmlString, NOTICE_ACTIVECALLBACK pfCallback, void *pCustom, LPWSTR *lpExceptMsg); // һ򵥵 Toast ֪֧ͨһıһͼƬͼƬҪΪ NULL ı // һЩ CreateToastNoticeFromXmlDocument еͬһ¡ @@ -71,6 +71,15 @@ extern "C" // ݷʽ // ðװԭĴΪҪ AppUserID ʹ Toast ֪ͨȻֻ Windows 8.x УWindows 10 ûˣ NOTICE_API HRESULT CreateShortcutWithAppIdW (LPCWSTR pszShortcutPath, LPCWSTR pszTargetPath, LPCWSTR pszAppId); + // notice.dll ȡĶַ̬ɴͷš + NOTICE_API void NoticeApiFreeString (LPWSTR lpstr); + // һ򵥵 Toast ֪֧ͨıһͼƬͼƬ data uri ֻ Base64 ַ NULL + // һЩ CreateToastNoticeFromXmlDocument еͬһ¡ + NOTICE_API HRESULT CreateToastNoticeWithImgBase64 (LPCWSTR lpIdName, LPCWSTR lpText, LPCWSTR lpImgBase64, NOTICE_ACTIVECALLBACK pfCallback, void *pCustom, LPWSTR *lpExceptMsg); + // һ򵥵 Toast ֪֧ͨıһͼƬͼƬ data uri ֻ Base64 ַ NULL + // lpText Ϊ NULL ıʱ CreateToastNoticeWithIStream һ¡ + // һЩ CreateToastNoticeFromXmlDocument еͬһ¡ + NOTICE_API HRESULT CreateToastNotice2WithImgBase64 (LPCWSTR lpIdName, LPCWSTR lpTitle, LPCWSTR lpText, LPCWSTR lpImgBase64, NOTICE_ACTIVECALLBACK pfCallback, void *pCustom, LPWSTR *lpExceptMsg); #ifdef _DEFAULT_INIT_VALUE_ #undef _DEFAULT_INIT_VALUE_ #endif @@ -80,3 +89,117 @@ extern "C" #ifdef __cplusplus } #endif + +#ifdef __cplusplus +#include +#include +namespace notice +{ + // using LPWSTR = wchar_t *; + struct destruct + { + using funcend = std::function ; + funcend endtask = nullptr; + destruct (funcend endtask): endtask (endtask) {} + ~destruct () { if (endtask) endtask (); } + destruct (destruct &) = delete; + }; + struct autostr + { + LPWSTR lpstr = nullptr; + destruct reltask = [this] () { + if (lpstr) NoticeApiFreeString (lpstr); + lpstr = nullptr; + }; + autostr (LPWSTR str = nullptr): lpstr (str) {} + operator LPWSTR () const { return lpstr; } + operator std::wstring () const { return lpstr ? lpstr : L""; } + std::wstring get_string () { return lpstr ? lpstr : L""; } + }; + using qwstring = std::wstring &; + using qcwstring = const std::wstring &; + struct hresult + { + HRESULT hr = S_OK; + std::wstring message = L""; + operator HRESULT () const { return hr; } + operator std::wstring () const { return message; } + hresult (HRESULT hr = S_OK, qcwstring msg = L""): hr (hr), message (msg) {} + }; +} +std::wstring GetToastNoticeXml (notice::qcwstring template_name) { return notice::autostr (GetToastNoticeXml (template_name.c_str ())).get_string (); } +std::wstring GenerateSimpleToastNoticeXml (notice::qcwstring text, notice::qcwstring imgurl = L"") { return notice::autostr (GenerateSimpleToastNoticeXml (text.c_str (), imgurl.c_str ())).get_string (); } +std::wstring GenerateSimpleToastNoticeXml (notice::qcwstring title, notice::qcwstring text, notice::qcwstring imgurl) { return notice::autostr (GenerateSimpleToastNoticeXml2 (title.c_str (), text.c_str (), imgurl.c_str ())).get_string (); } +std::wstring GenerateSimpleToastNoticeXml2 (notice::qcwstring title, notice::qcwstring text = L"", notice::qcwstring imgurl = L"") { return GenerateSimpleToastNoticeXml2 (title, text, imgurl); } +void ToastNoticeEventCallback (void *pCustom) +{ + if (pCustom) + { + using cbfunc = std::function ; + auto func = reinterpret_cast (pCustom); + if (func) (*func)(); + } +} +notice::hresult CreateToastNoticeFromXmlDocument (notice::qcwstring idname, notice::qcwstring xmlstring, std::function callback = nullptr) +{ + notice::autostr exp; + notice::hresult hr; + hr.hr = CreateToastNoticeFromXmlDocument (idname.c_str (), xmlstring.c_str (), &ToastNoticeEventCallback, &callback, &exp.lpstr); + hr.message = exp.get_string (); + return hr; +} +notice::hresult CreateToastNotice (notice::qcwstring idname, notice::qcwstring text, notice::qcwstring imgpath, std::function callback = nullptr) +{ + notice::autostr exp; + notice::hresult hr; + hr.hr = CreateToastNotice (idname.c_str (), text.c_str (), imgpath.c_str (), &ToastNoticeEventCallback, &callback, &exp.lpstr); + hr.message = exp.get_string (); + return hr; +} +notice::hresult CreateToastNotice (notice::qcwstring idname, notice::qcwstring title, notice::qcwstring text, notice::qcwstring imgpath, std::function callback = nullptr) +{ + notice::autostr exp; + notice::hresult hr; + hr.hr = CreateToastNotice2 (idname.c_str (), title.c_str (), text.c_str (), imgpath.c_str (), &ToastNoticeEventCallback, &callback, &exp.lpstr); + hr.message = exp.get_string (); + return hr; +} +notice::hresult CreateToastNotice2 (notice::qcwstring idname, notice::qcwstring title, notice::qcwstring text = L"", notice::qcwstring imgpath = L"", std::function callback = nullptr) { return CreateToastNotice (idname, title, text, imgpath, callback); } +notice::hresult CreateToastNoticeWithIStream (notice::qcwstring idname, notice::qcwstring text, IStream *imgstream, std::function callback = nullptr) +{ + notice::autostr exp; + notice::hresult hr; + hr.hr = CreateToastNoticeWithIStream (idname.c_str (), text.c_str (), imgstream, &ToastNoticeEventCallback, &callback, &exp.lpstr); + hr.message = exp.get_string (); + return hr; +} +notice::hresult CreateToastNoticeWithIStream2 (notice::qcwstring idname, notice::qcwstring title, notice::qcwstring text = L"", IStream *imgstream = nullptr, std::function callback = nullptr) +{ + notice::autostr exp; + notice::hresult hr; + hr.hr = CreateToastNoticeWithIStream2 (idname.c_str (), title.c_str (), text.c_str (), imgstream, &ToastNoticeEventCallback, &callback, &exp.lpstr); + hr.message = exp.get_string (); + return hr; +} +notice::hresult CreateToastNoticeWithIStream (notice::qcwstring idname, notice::qcwstring title, notice::qcwstring text, IStream *imgstream, std::function callback = nullptr) { return CreateToastNoticeWithIStream2 (idname, title, text, imgstream, callback); } +notice::hresult CreateToastNotice (notice::qcwstring idname, notice::qcwstring xmlstring, std::function callback) { return CreateToastNoticeFromXmlDocument (idname, xmlstring, callback); } +notice::hresult CreateToastNotice (notice::qcwstring idname, notice::qcwstring text, IStream *imgstream, std::function callback = nullptr) { return CreateToastNoticeWithIStream (idname, text, imgstream, callback); } +notice::hresult CreateToastNotice (notice::qcwstring idname, notice::qcwstring title, notice::qcwstring text, IStream *imgstream, std::function callback = nullptr) { return CreateToastNoticeWithIStream2 (idname, title, text, imgstream, callback); } +HRESULT CreateShortcutWithAppIdW (notice::qcwstring shortcut_path, notice::qcwstring targetpath, notice::qcwstring appid) { return CreateShortcutWithAppIdW (shortcut_path.c_str (), targetpath.c_str (), appid.c_str ()); } +HRESULT CreateToastNoticeWithImgBase64 (notice::qcwstring idname, notice::qcwstring text, notice::qcwstring imgbase64, std::function callback = nullptr) +{ + notice::autostr exp; + notice::hresult hr; + hr.hr = CreateToastNoticeWithImgBase64 (idname.c_str (), text.c_str (), imgbase64.c_str (), &ToastNoticeEventCallback, &callback, &exp.lpstr); + hr.message = exp.get_string (); + return hr; +} +HRESULT CreateToastNotice2WithImgBase64 (notice::qcwstring idname, notice::qcwstring title, notice::qcwstring text, notice::qcwstring imgbase64, std::function callback = nullptr) +{ + notice::autostr exp; + notice::hresult hr; + hr.hr = CreateToastNotice2WithImgBase64 (idname.c_str (), title.c_str (), text.c_str (), imgbase64.c_str (), &ToastNoticeEventCallback, &callback, &exp.lpstr); + hr.message = exp.get_string (); + return hr; +} +#endif \ No newline at end of file diff --git a/notice/notice.vcxproj b/notice/notice.vcxproj index 159c401..002ccfd 100644 --- a/notice/notice.vcxproj +++ b/notice/notice.vcxproj @@ -61,7 +61,7 @@ Windows true RequireAdministrator - shlwapi.lib;%(AdditionalDependencies) + shlwapi.lib;crypt32.lib;%(AdditionalDependencies) @@ -80,7 +80,7 @@ true true true - shlwapi.lib;%(AdditionalDependencies) + shlwapi.lib;crypt32.lib;%(AdditionalDependencies) diff --git a/notice/stdafx.h b/notice/stdafx.h index 58d4bc9..4be5223 100644 --- a/notice/stdafx.h +++ b/notice/stdafx.h @@ -32,8 +32,13 @@ #include #include #include +#include +#include +#include +#include #using using namespace Microsoft::WRL; using namespace ABI::Windows::UI::Notifications; using namespace ABI::Windows::Data::Xml::Dom; using namespace Microsoft::WRL::Wrappers; +#include \ No newline at end of file diff --git a/pkgmgr/dllmain.cpp b/pkgmgr/dllmain.cpp index 740bca6..044235d 100644 --- a/pkgmgr/dllmain.cpp +++ b/pkgmgr/dllmain.cpp @@ -10,13 +10,13 @@ BOOL APIENTRY DllMain( HMODULE hModule, { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: - CoInitializeEx (NULL, COINIT_MULTITHREADED | COINIT_APARTMENTTHREADED); - RoInitialize (RO_INIT_MULTITHREADED); + // CoInitializeEx (NULL, COINIT_MULTITHREADED | COINIT_APARTMENTTHREADED); + // RoInitialize (RO_INIT_MULTITHREADED); break; case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: - CoUninitialize (); - RoUninitialize (); + // CoUninitialize (); + // RoUninitialize (); break; } return TRUE; diff --git a/pkgmgr/pkgmgr.cpp b/pkgmgr/pkgmgr.cpp index e26c0fb..9855ba9 100644 --- a/pkgmgr/pkgmgr.cpp +++ b/pkgmgr/pkgmgr.cpp @@ -20,7 +20,33 @@ std::wstring GetFullPathName (const std::wstring &lpFileName) std::wstring g_swExceptionCode = L""; std::wstring g_swExceptionDetail = L""; +bool g_enableIterDeps = false; +LPWSTR AllocWideString (const std::wstring &str) +{ + size_t size = (str.length () + 1) * sizeof (WCHAR); + LPWSTR buf = (LPWSTR)CoTaskMemAlloc (size); + if (!buf) return nullptr; + ZeroMemory (buf, size); + wcscpy (buf, str.c_str ()); + return buf; +} +// +LPWSTR AllocWideString (LPCWSTR str) +{ + if (!str) return nullptr; + size_t size = (wcslen (str) + 1) * sizeof (WCHAR); + LPWSTR buf = (LPWSTR)CoTaskMemAlloc (size); + if (!buf) return nullptr; + ZeroMemory (buf, size); + wcscpy (buf, str); + return buf; +} +#define _wcsdup AllocWideString +#define free CoTaskMemFree +#define malloc CoTaskMemAlloc +#define realloc CoTaskMemRealloc +#define calloc(_cnt_, _size_) CoTaskMemAlloc (_cnt_ * _size_) struct destruct { std::function endtask = nullptr; @@ -57,15 +83,15 @@ template HRESULT RunPackageManagerOperation (TAsyncOp 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) { + depopt->Completed = ref new onprogresscomp ([&hCompEvt] (progressopt, Windows::Foundation::AsyncStatus) { SetEvent (hCompEvt); }); WaitForSingleObject (hCompEvt, INFINITE); switch (depopt->Status) { - case AsyncStatus::Completed: + case Windows::Foundation::AsyncStatus::Completed: return S_OK; - case AsyncStatus::Error: + case Windows::Foundation::AsyncStatus::Error: { auto depresult = depopt->GetResults (); auto errorcode = depopt->ErrorCode; @@ -77,11 +103,11 @@ template HRESULT RunPackageManagerOperation (TAsyncOp if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); return (HRESULT)errorcode.Value; } - case AsyncStatus::Canceled: + case Windows::Foundation::AsyncStatus::Canceled: g_swExceptionDetail = L"Installation Canceled"; if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); return E_ABORT; - case AsyncStatus::Started: + case Windows::Foundation::AsyncStatus::Started: g_swExceptionDetail = L"Installation is Running"; if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); return E_PENDING; @@ -185,7 +211,8 @@ void SidToAccountName (const std::wstring &sidString, std::wstring &stringSid) if (LookupAccountSidW (nullptr, sid, namebuf.data (), &nameCharCount, domainNameBuf.data (), &domainNameCharCount, &sidType)) { stringSid = domainNameBuf.data (); - stringSid += stringSid + L"\\" + namebuf.data (); + if (!stringSid.empty ()) stringSid += L"\\"; + stringSid += namebuf.data (); } } if (stringSid.length () == 0) stringSid = sidString; @@ -218,7 +245,7 @@ struct pkg_info std::wstring users = L""; std::wstring sids = L""; std::vector dependencies; - static pkg_info parse (Windows::ApplicationModel::Package ^pkg, Windows::Management::Deployment::PackageManager ^mgr) + static pkg_info parse (Windows::ApplicationModel::Package ^pkg, Windows::Management::Deployment::PackageManager ^mgr, bool iterdeps = true) { pkg_info pi; if (!pkg) throw ref new InvalidArgumentException ("No package found."); @@ -259,23 +286,30 @@ struct pkg_info std::wstring sid; WAPParseSetStringValue (sid, it->UserSecurityId); if (i) pi.sids += L';'; - pi.users += sid; + pi.sids += sid; } i ++; } } catch (...) {} - try + if (g_enableIterDeps && iterdeps) { - auto deps = pkg->Dependencies; - for (auto it : deps) + try { - auto deppkg = pkg_info::parse (it, mgr); - deppkg.dependencies.clear (); - pi.dependencies.push_back (deppkg); + auto deps = pkg->Dependencies; + if (deps && deps->Size) + { + for (size_t i = 0; i < deps->Size; i ++) + { + auto it = deps->GetAt (i); + auto deppkg = pkg_info::parse (it, mgr, false); + deppkg.dependencies.clear (); + pi.dependencies.push_back (deppkg); + } + } } + catch (...) {} } - catch (...) {} return pi; #ifdef WAPParseSetStringValue #undef WAPParseSetStringValue @@ -319,6 +353,49 @@ struct pkg_info } }; [STAThread] +HRESULT ProcessFoundAppxPackages (Windows::Foundation::Collections::IIterable ^pkgarr, PackageManager ^pkgmgr, std::function pfCallback, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + g_swExceptionCode = L""; + g_swExceptionDetail = L""; + try + { + if (pkgarr) + { + for each (auto pkg in 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 FindAppxPackageByCallback (std::function pfCallback, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) { g_swExceptionCode = L""; @@ -327,12 +404,7 @@ HRESULT FindAppxPackageByCallback (std::function pfCallback, { 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; + return ProcessFoundAppxPackages (pkgarr, pkgmgr, pfCallback, pErrorCode, pDetailMsg); } catch (AccessDeniedException ^e) { @@ -632,6 +704,7 @@ LPCWSTR GetPackageManagerLastErrorDetailMessage () { return g_swExceptionDetail. HRESULT ActivateAppxApplication (LPCWSTR lpAppUserId, PDWORD pdwProcessId) { + if (FAILED (CoInitializeEx (NULL, COINIT_APARTMENTTHREADED))) return E_INVALIDARG; if (!lpAppUserId) return E_INVALIDARG; std::wstring strAppUserModelId (L""); if (lpAppUserId) strAppUserModelId += lpAppUserId; @@ -649,9 +722,112 @@ HRESULT ActivateAppxApplication (LPCWSTR lpAppUserId, PDWORD pdwProcessId) { // This call ensures that the app is launched as the foreground window hResult = CoAllowSetForegroundWindow (spAppActivationManager, NULL); + DWORD dwProgressId = 0; // Launch the app - if (SUCCEEDED (hResult)) hResult = spAppActivationManager->ActivateApplication (strAppUserModelId.c_str (), NULL, AO_NONE, pdwProcessId); + if (SUCCEEDED (hResult)) + hResult = spAppActivationManager->ActivateApplication (strAppUserModelId.c_str (), NULL, AO_NONE, &dwProgressId); + if (pdwProcessId) *pdwProcessId = dwProgressId; } } return hResult; -} \ No newline at end of file +} +[STAThread] +HRESULT FindAppxPackageByCallback (LPCWSTR lpPkgName, LPCWSTR lpPublisher, std::function pfCallback, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + g_swExceptionCode = L""; + g_swExceptionDetail = L""; + try + { + auto pkgmgr = ref new PackageManager (); + std::wstring pkgname = lpPkgName ? lpPkgName : L""; + std::wstring pkgpublisher = lpPublisher ? lpPublisher : L""; + auto refname = ref new Platform::String (pkgname.c_str ()), + refpublisher = ref new Platform::String (pkgpublisher.c_str ()); + auto pkgarr = pkgmgr->FindPackages (refname, refpublisher); + return ProcessFoundAppxPackages (pkgarr, pkgmgr, pfCallback, pErrorCode, pDetailMsg); + } + 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 FindAppxPackagesByIdentity (LPCWSTR lpPkgName, LPCWSTR lpPkgPublisher, PKGMGR_FINDENUMCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + return FindAppxPackageByCallback (lpPkgName, lpPkgPublisher, [&pCustom, &pfCallback] (pkg_info &pi) { + std::vector bytes; + pi.to_c_struct (bytes); + if (pfCallback) pfCallback ((FIND_PACKAGE_INFO *)bytes.data (), pCustom); + }, pErrorCode, pDetailMsg); +} +[STAThread] +HRESULT FindAppxPackageByCallback (LPCWSTR lpPkgFamilyName, std::function pfCallback, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + g_swExceptionCode = L""; + g_swExceptionDetail = L""; + try + { + auto pkgmgr = ref new PackageManager (); + std::wstring familyname = L""; + familyname += lpPkgFamilyName ? lpPkgFamilyName : L""; + auto reffamily = ref new Platform::String (familyname.c_str ()); + auto pkgarr = pkgmgr->FindPackages (reffamily); + return ProcessFoundAppxPackages (pkgarr, pkgmgr, pfCallback, pErrorCode, pDetailMsg); + } + 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 FindAppxPackagesByFamilyName (LPCWSTR lpPkgFamilyName, PKGMGR_FINDENUMCALLBACK pfCallback, void *pCustom, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + return FindAppxPackageByCallback (lpPkgFamilyName, [&pCustom, &pfCallback] (pkg_info &pi) { + std::vector bytes; + pi.to_c_struct (bytes); + if (pfCallback) pfCallback ((FIND_PACKAGE_INFO *)bytes.data (), pCustom); + }, pErrorCode, pDetailMsg); +} +void PackageManagerFreeString (LPWSTR lpString) { if (lpString) free (lpString); } \ No newline at end of file diff --git a/pkgmgr/pkgmgr.h b/pkgmgr/pkgmgr.h index 4919a92..ca53289 100644 --- a/pkgmgr/pkgmgr.h +++ b/pkgmgr/pkgmgr.h @@ -59,18 +59,23 @@ extern "C" #define DEPOLYOPTION_INSTALL_ALL_RESOURCES 0x00000020 // ʹĬΪ #define DEPOLYOPTION_NONE 0x00000000 + // ƴдˣֻܽʹ IDE עͣ +#define DEPLOYOPTION_FORCE_APP_SHUTDOWN DEPOLYOPTION_FORCE_APP_SHUTDOWN +#define DEPLOYOPTION_DEVELOPMENT_MODE DEPOLYOPTION_DEVELOPMENT_MODE +#define DEPLOYOPTION_INSTALL_ALL_RESOURCES DEPOLYOPTION_INSTALL_ALL_RESOURCES +#define DEPLOYOPTION_NONE DEPOLYOPTION_NONE // װһ 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)); + // ĴϢ PackageManagerFreeString ͷ + PKGMGR_API HRESULT AddAppxPackageFromPath (LPCWSTR lpPkgPath, PCREGISTER_PACKAGE_DEFENDENCIES alpDepUrlList _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), DWORD dwDeployOption _DEFAULT_INIT_VALUE_FORFUNC_ (DEPLOYOPTION_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)); + // ĴϢ PackageManagerFreeString ͷ + PKGMGR_API HRESULT AddAppxPackageFromURI (LPCWSTR lpFileUri, PCREGISTER_PACKAGE_DEFENDENCIES alpDepFullNameList _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), DWORD dwDeployOption _DEFAULT_INIT_VALUE_FORFUNC_ (DEPLOYOPTION_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 { @@ -122,13 +127,13 @@ extern "C" // ͨصȡаϢصԶݡصֵжǷɹ // ú PowerShell Get-AppxPackage // ע⣺صаϢ޷޸ģҲͷšźִԶͷšҪڻصпһݡ - // ĴϢ free ͷ + // ĴϢ PackageManagerFreeString ͷ 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 ͷ + // ĴϢ PackageManagerFreeString ͷ 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 ͷ + // ĴϢ PackageManagerFreeString ͷ 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)); // עӦð @@ -167,13 +172,13 @@ extern "C" // °İ汾Ѱװİ汾ʱܸѰװİ ǰ汾İʧܡ // ע⣺ļ·Ϊ DOS/NT 磺C:\Windows\... // dwDeployOption DEPOLYOPTION_* - // ĴϢ free ͷ + // ĴϢ PackageManagerFreeString ͷ 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 ͷ + // ĴϢ PackageManagerFreeString ͷ 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)); @@ -183,6 +188,12 @@ extern "C" PKGMGR_API LPCWSTR GetPackageManagerLastErrorDetailMessage (); // Metro UI Ӧ PKGMGR_API HRESULT ActivateAppxApplication (LPCWSTR lpAppUserId, PDWORD pdwProcessId); + // ṩİͷ߼ + PKGMGR_API HRESULT FindAppxPackagesByIdentity (LPCWSTR lpPkgName, LPCWSTR lpPkgPublisher, 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 HRESULT FindAppxPackagesByFamilyName (LPCWSTR lpPkgFamilyName, 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.dll صĶַ̬ + PKGMGR_API void PackageManagerFreeString (LPWSTR lpString); #ifdef _DEFAULT_INIT_VALUE_ #undef _DEFAULT_INIT_VALUE_ #endif @@ -192,3 +203,470 @@ extern "C" #ifdef __cplusplus } #endif + +#ifdef __cplusplus +#include +#include +#include +#include +void IAsyncProgressCallback (DWORD dwProgress, void *pCustom) +{ + using cbfunc = std::function ; + if (auto func = reinterpret_cast (pCustom)) (*func)(dwProgress); +} +HRESULT AddAppxPackageFromPath ( + const std::wstring &pkgpath, + const std::vector &deplist = std::vector (), + DWORD deployoption = DEPOLYOPTION_NONE, // ʹ DEPOLYOPTION_* ǰ׺ + std::function callback = nullptr, + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + std::vector bytes (sizeof (REGISTER_PACKAGE_DEFENDENCIES) + sizeof (LPWSTR) * deplist.size ()); + auto lpdeplist = (PREGISTER_PACKAGE_DEFENDENCIES)bytes.data (); + lpdeplist->dwSize = deplist.size (); + for (size_t i = 0; i < deplist.size (); i ++) lpdeplist->alpDepUris [i] = (LPWSTR)deplist [i].c_str (); + LPWSTR lperr = nullptr, lpmsg = nullptr; + HRESULT hr = AddAppxPackageFromPath (pkgpath.c_str (), lpdeplist, deployoption, &IAsyncProgressCallback, &callback, &lperr, &lpmsg); + errorcode = lperr ? lperr : L""; + detailmsg = lpmsg ? lpmsg : L""; + if (lperr) PackageManagerFreeString (lperr); + if (lpmsg) PackageManagerFreeString (lpmsg); + return hr; +} +HRESULT AddAppxPackageFromURI ( + const std::wstring &pkguri, + const std::vector &deplist = std::vector (), + DWORD deployoption = DEPOLYOPTION_NONE, // ʹ DEPOLYOPTION_* ǰ׺ + std::function callback = nullptr, + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + std::vector bytes (sizeof (REGISTER_PACKAGE_DEFENDENCIES) + sizeof (LPWSTR) * deplist.size ()); + auto lpdeplist = (PREGISTER_PACKAGE_DEFENDENCIES)bytes.data (); + lpdeplist->dwSize = deplist.size (); + for (size_t i = 0; i < deplist.size (); i ++) lpdeplist->alpDepUris [i] = (LPWSTR)deplist [i].c_str (); + LPWSTR lperr = nullptr, lpmsg = nullptr; + HRESULT hr = AddAppxPackageFromURI (pkguri.c_str (), lpdeplist, deployoption, &IAsyncProgressCallback, &callback, &lperr, &lpmsg); + errorcode = lperr ? lperr : L""; + detailmsg = lpmsg ? lpmsg : L""; + if (lperr) PackageManagerFreeString (lperr); + if (lpmsg) PackageManagerFreeString (lpmsg); + return hr; +} +struct find_pkginfo +{ + bool isvalid = false; + struct + { + std::wstring + name, + publisher, + publisher_id, + full_name, + family_name, + resource_id; + UINT64 version = 0; + // x86: 0 + // x64: 9 + // Arm: 5 + // Neutral: 11 + // Arm64: 12 + // Unknown: 65535(-1) + WORD architecture = -1; + } identity; + struct + { + std::wstring + display_name, + description, + publisher, + logo_uri; + bool is_framework = false, + resource_package = false; + } properties; + bool is_bundle = false; + bool is_development_mode = false; + std::wstring install_location; + std::vector + users, + sids; +#define safestring(_pstr_) (_pstr_ ? _pstr_ : L"") + static find_pkginfo parse (LPCFIND_PACKAGE_INFO fpi) + { + if (!fpi) return find_pkginfo (); + find_pkginfo fpkg; + fpkg.identity.name += safestring (fpi->piIdentity.lpName); + fpkg.identity.publisher += safestring (fpi->piIdentity.lpPublisher); + fpkg.identity.publisher_id += safestring (fpi->piIdentity.lpPublisherId); + fpkg.identity.family_name += safestring (fpi->piIdentity.lpFamilyName); + fpkg.identity.full_name += safestring (fpi->piIdentity.lpFullName); + fpkg.identity.resource_id += safestring (fpi->piIdentity.lpResourceId); + fpkg.identity.version = fpi->piIdentity.qwVersion; + fpkg.identity.architecture = fpi->piIdentity.wProcessArchitecture; + fpkg.properties.display_name += safestring (fpi->piProperties.lpDisplayName); + fpkg.properties.description += safestring (fpi->piProperties.lpDescription); + fpkg.properties.publisher += safestring (fpi->piProperties.lpPublisher); + fpkg.properties.logo_uri += safestring (fpi->piProperties.lpLogoUri); + fpkg.properties.is_framework = fpi->piProperties.bIsFramework; + fpkg.properties.resource_package = fpi->piProperties.bIsResourcePackage; + fpkg.is_bundle = fpi->piProperties.bIsBundle; + fpkg.is_development_mode = fpi->piProperties.bIsDevelopmentMode; + fpkg.install_location += safestring (fpi->lpInstallLocation); + std::wstring users; + users += safestring (fpi->lpUsers); + std::wstring sids; + sids += safestring (fpi->lpSIDs); + std::wstring part = L""; + for (size_t i = 0; i < users.length (); i ++) + { + auto &wch = users [i]; + if (wch == L';' || wch == L'0') + { + if (!part.empty ()) fpkg.users.push_back (part); + part = L""; + continue; + } + part += wch; + } + if (!part.empty ()) fpkg.users.push_back (part); + part = L""; + for (size_t i = 0; i < sids.length (); i ++) + { + auto &wch = sids [i]; + if (wch == L';' || wch == L'0') + { + if (!part.empty ()) fpkg.sids.push_back (part); + part = L""; + continue; + } + part += wch; + } + if (!part.empty ()) fpkg.sids.push_back (part); + fpkg.isvalid = true; + return fpkg; + } +#ifdef safestring +#undef safestring +#endif +}; +void IAsyncFindEnumCallback (LPCFIND_PACKAGE_INFO pNowItem, void *pCustom) +{ + if (pNowItem) + { + try + { + auto fpkg = find_pkginfo::parse (pNowItem); + if (fpkg.isvalid) + { + using cbfunc = std::function ; + auto func = reinterpret_cast (pCustom); + if (func) (*func)(fpkg); + } + } + catch (const std::exception &e) + { + OutputDebugStringA (e.what ()); + } + } +} +HRESULT GetAppxPackages ( + std::function callback, + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + LPWSTR lperr = nullptr, lpmsg = nullptr; + HRESULT hr = GetAppxPackages (&IAsyncFindEnumCallback, &callback, &lperr, &lpmsg); + errorcode = lperr ? lperr : L""; + detailmsg = lpmsg ? lpmsg : L""; + if (lperr) PackageManagerFreeString (lperr); + if (lpmsg) PackageManagerFreeString (lpmsg); + return hr; +} +HRESULT GetAppxPackages ( + std::vector &out_pkgs, + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + return GetAppxPackages ([&] (const find_pkginfo &fpi) { + out_pkgs.push_back (fpi); + }, errorcode, detailmsg); +} +HRESULT GetAppxPackages ( + const std::wstring &package_family_name, + std::function callback, + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + LPWSTR lperr = nullptr, lpmsg = nullptr; + HRESULT hr = FindAppxPackagesByFamilyName (package_family_name.c_str (), &IAsyncFindEnumCallback, &callback, &lperr, &lpmsg); + errorcode = lperr ? lperr : L""; + detailmsg = lpmsg ? lpmsg : L""; + if (lperr) PackageManagerFreeString (lperr); + if (lpmsg) PackageManagerFreeString (lpmsg); + return hr; +} +HRESULT GetAppxPackages ( + const std::wstring &package_family_name, + std::vector &out_pkgs, + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + return GetAppxPackages (package_family_name , [&] (const find_pkginfo &fpi) { + out_pkgs.push_back (fpi); + }, errorcode, detailmsg); +} +HRESULT GetAppxPackages ( + const std::wstring &package_id_name, + const std::wstring &package_id_publisher, + std::function callback, + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + LPWSTR lperr = nullptr, lpmsg = nullptr; + HRESULT hr = FindAppxPackagesByIdentity (package_id_name.c_str (), package_id_publisher.c_str (), &IAsyncFindEnumCallback, &callback, &lperr, &lpmsg); + errorcode = lperr ? lperr : L""; + detailmsg = lpmsg ? lpmsg : L""; + if (lperr) PackageManagerFreeString (lperr); + if (lpmsg) PackageManagerFreeString (lpmsg); + return hr; +} +HRESULT GetAppxPackages ( + const std::wstring &package_id_name, + const std::wstring &package_id_publisher, + std::vector &out_pkgs, + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + return GetAppxPackages (package_id_name, package_id_publisher, [&] (const find_pkginfo &fpi) { + out_pkgs.push_back (fpi); + }, errorcode, detailmsg); +} +HRESULT FindAppxPackage ( + const std::wstring &package_fullname, + std::function callback, + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + LPWSTR lperr = nullptr, lpmsg = nullptr; + HRESULT hr = FindAppxPackage (package_fullname.c_str (), &IAsyncFindEnumCallback, &callback, &lperr, &lpmsg); + errorcode = lperr ? lperr : L""; + detailmsg = lpmsg ? lpmsg : L""; + if (lperr) PackageManagerFreeString (lperr); + if (lpmsg) PackageManagerFreeString (lpmsg); + return hr; +} +HRESULT FindAppxPackage ( + const std::wstring &package_fullname, + find_pkginfo &out_pkginf, + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + return FindAppxPackage (package_fullname, [&] (const find_pkginfo &fpkg) { + out_pkginf = fpkg; + }, errorcode, detailmsg); +} +HRESULT RemoveAppxPackage ( + const std::wstring &package_fullname, + std::function callback = nullptr, + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + LPWSTR lperr = nullptr, lpmsg = nullptr; + HRESULT hr = RemoveAppxPackage (package_fullname.c_str (), &IAsyncProgressCallback, &callback, &lperr, &lpmsg); + errorcode = lperr ? lperr : L""; + detailmsg = lpmsg ? lpmsg : L""; + if (lperr) PackageManagerFreeString (lperr); + if (lpmsg) PackageManagerFreeString (lpmsg); + return hr; +} +HRESULT CleanupAppxPackage ( + const std::wstring &package_name, + const std::wstring &user_sid, + std::function callback = nullptr, + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + LPWSTR lperr = nullptr, lpmsg = nullptr; + HRESULT hr = CleanupAppxPackage (package_name.c_str (), user_sid.c_str (), &IAsyncProgressCallback, &callback, &lperr, &lpmsg); + errorcode = lperr ? lperr : L""; + detailmsg = lpmsg ? lpmsg : L""; + if (lperr) PackageManagerFreeString (lperr); + if (lpmsg) PackageManagerFreeString (lpmsg); + return hr; +} +HRESULT RegisterAppxPackageByPath ( + const std::wstring &manifest_path, + const std::vector &depurilist = std::vector (), + DWORD deployoption = DEPOLYOPTION_NONE, // ʹ DEPOLYOPTION_* ǰ׺ + std::function callback = nullptr, + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + std::vector bytes (sizeof (REGISTER_PACKAGE_DEFENDENCIES) + sizeof (LPWSTR) * depurilist.size ()); + auto lpdeplist = (PREGISTER_PACKAGE_DEFENDENCIES)bytes.data (); + lpdeplist->dwSize = depurilist.size (); + for (size_t i = 0; i < depurilist.size (); i ++) lpdeplist->alpDepUris [i] = (LPWSTR)depurilist [i].c_str (); + LPWSTR lperr = nullptr, lpmsg = nullptr; + HRESULT hr = RegisterAppxPackageByPath (manifest_path.c_str (), lpdeplist, deployoption, &IAsyncProgressCallback, &callback, &lperr, &lpmsg); + errorcode = lperr ? lperr : L""; + detailmsg = lpmsg ? lpmsg : L""; + if (lperr) PackageManagerFreeString (lperr); + if (lpmsg) PackageManagerFreeString (lpmsg); + return hr; +} +HRESULT RegisterAppxPackageByUri ( + const std::wstring &manifest_uri, + const std::vector &deplist = std::vector (), + DWORD deployoption = DEPOLYOPTION_NONE, // ʹ DEPOLYOPTION_* ǰ׺ + std::function callback = nullptr, + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + std::vector bytes (sizeof (REGISTER_PACKAGE_DEFENDENCIES) + sizeof (LPWSTR) * deplist.size ()); + auto lpdeplist = (PREGISTER_PACKAGE_DEFENDENCIES)bytes.data (); + lpdeplist->dwSize = deplist.size (); + for (size_t i = 0; i < deplist.size (); i ++) lpdeplist->alpDepUris [i] = (LPWSTR)deplist [i].c_str (); + LPWSTR lperr = nullptr, lpmsg = nullptr; + HRESULT hr = RegisterAppxPackageByUri (manifest_uri.c_str (), lpdeplist, deployoption, &IAsyncProgressCallback, &callback, &lperr, &lpmsg); + errorcode = lperr ? lperr : L""; + detailmsg = lpmsg ? lpmsg : L""; + if (lperr) PackageManagerFreeString (lperr); + if (lpmsg) PackageManagerFreeString (lpmsg); + return hr; +} +HRESULT RegisterAppxPackageByFullName ( + const std::wstring &package_full_name, + const std::vector &deplist = std::vector (), + DWORD deployoption = DEPOLYOPTION_NONE, // ʹ DEPOLYOPTION_* ǰ׺ + std::function callback = nullptr, + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + std::vector bytes (sizeof (REGISTER_PACKAGE_DEFENDENCIES) + sizeof (LPWSTR) * deplist.size ()); + auto lpdeplist = (PREGISTER_PACKAGE_DEFENDENCIES)bytes.data (); + lpdeplist->dwSize = deplist.size (); + for (size_t i = 0; i < deplist.size (); i ++) lpdeplist->alpDepUris [i] = (LPWSTR)deplist [i].c_str (); + LPWSTR lperr = nullptr, lpmsg = nullptr; + HRESULT hr = RegisterAppxPackageByFullName (package_full_name.c_str (), lpdeplist, deployoption, &IAsyncProgressCallback, &callback, &lperr, &lpmsg); + errorcode = lperr ? lperr : L""; + detailmsg = lpmsg ? lpmsg : L""; + if (lperr) PackageManagerFreeString (lperr); + if (lpmsg) PackageManagerFreeString (lpmsg); + return hr; +} +HRESULT StageAppxPackageFromURI ( + const std::wstring &file_uri, + const std::vector &deplist = std::vector (), + DWORD deployoption = DEPOLYOPTION_NONE, // ʹ DEPOLYOPTION_* ǰ׺ + std::function callback = nullptr, + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + std::vector bytes (sizeof (REGISTER_PACKAGE_DEFENDENCIES) + sizeof (LPWSTR) * deplist.size ()); + auto lpdeplist = (PREGISTER_PACKAGE_DEFENDENCIES)bytes.data (); + lpdeplist->dwSize = deplist.size (); + for (size_t i = 0; i < deplist.size (); i ++) lpdeplist->alpDepUris [i] = (LPWSTR)deplist [i].c_str (); + LPWSTR lperr = nullptr, lpmsg = nullptr; + HRESULT hr = StageAppxPackageFromURI (file_uri.c_str (), lpdeplist, deployoption, &IAsyncProgressCallback, &callback, &lperr, &lpmsg); + errorcode = lperr ? lperr : L""; + detailmsg = lpmsg ? lpmsg : L""; + if (lperr) PackageManagerFreeString (lperr); + if (lpmsg) PackageManagerFreeString (lpmsg); + return hr; +} +HRESULT StageAppxPackageFromPath ( + const std::wstring &file_path, + const std::vector &deplist = std::vector (), + DWORD deployoption = DEPOLYOPTION_NONE, // ʹ DEPOLYOPTION_* ǰ׺ + std::function callback = nullptr, + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + std::vector bytes (sizeof (REGISTER_PACKAGE_DEFENDENCIES) + sizeof (LPWSTR) * deplist.size ()); + auto lpdeplist = (PREGISTER_PACKAGE_DEFENDENCIES)bytes.data (); + lpdeplist->dwSize = deplist.size (); + for (size_t i = 0; i < deplist.size (); i ++) lpdeplist->alpDepUris [i] = (LPWSTR)deplist [i].c_str (); + LPWSTR lperr = nullptr, lpmsg = nullptr; + HRESULT hr = StageAppxPackageFromURI (file_path.c_str (), lpdeplist, deployoption, &IAsyncProgressCallback, &callback, &lperr, &lpmsg); + errorcode = lperr ? lperr : L""; + detailmsg = lpmsg ? lpmsg : L""; + if (lperr) PackageManagerFreeString (lperr); + if (lpmsg) PackageManagerFreeString (lpmsg); + return hr; +} +HRESULT StageAppxUserData ( + const std::wstring &package_full_name, + std::function callback = nullptr, + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + LPWSTR lperr = nullptr, lpmsg = nullptr; + HRESULT hr = StageAppxUserData (package_full_name.c_str (), &IAsyncProgressCallback, &callback, &lperr, &lpmsg); + errorcode = lperr ? lperr : L""; + detailmsg = lpmsg ? lpmsg : L""; + if (lperr) PackageManagerFreeString (lperr); + if (lpmsg) PackageManagerFreeString (lpmsg); + return hr; +} +HRESULT UpdateAppxPackageFromPath ( + const std::wstring &file_path, + const std::vector &deplist = std::vector (), + DWORD deployoption = DEPOLYOPTION_NONE, // ʹ DEPOLYOPTION_* ǰ׺ + std::function callback = nullptr, + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + std::vector bytes (sizeof (REGISTER_PACKAGE_DEFENDENCIES) + sizeof (LPWSTR) * deplist.size ()); + auto lpdeplist = (PREGISTER_PACKAGE_DEFENDENCIES)bytes.data (); + lpdeplist->dwSize = deplist.size (); + for (size_t i = 0; i < deplist.size (); i ++) lpdeplist->alpDepUris [i] = (LPWSTR)deplist [i].c_str (); + LPWSTR lperr = nullptr, lpmsg = nullptr; + HRESULT hr = UpdateAppxPackageFromPath (file_path.c_str (), lpdeplist, deployoption, &IAsyncProgressCallback, &callback, &lperr, &lpmsg); + errorcode = lperr ? lperr : L""; + detailmsg = lpmsg ? lpmsg : L""; + if (lperr) PackageManagerFreeString (lperr); + if (lpmsg) PackageManagerFreeString (lpmsg); + return hr; +} +HRESULT UpdateAppxPackageFromURI ( + const std::wstring &file_uri, + const std::vector &deplist = std::vector (), + DWORD deployoption = DEPOLYOPTION_NONE, // ʹ DEPOLYOPTION_* ǰ׺ + std::function callback = nullptr, + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + std::vector bytes (sizeof (REGISTER_PACKAGE_DEFENDENCIES) + sizeof (LPWSTR) * deplist.size ()); + auto lpdeplist = (PREGISTER_PACKAGE_DEFENDENCIES)bytes.data (); + lpdeplist->dwSize = deplist.size (); + for (size_t i = 0; i < deplist.size (); i ++) lpdeplist->alpDepUris [i] = (LPWSTR)deplist [i].c_str (); + LPWSTR lperr = nullptr, lpmsg = nullptr; + HRESULT hr = UpdateAppxPackageFromURI (file_uri.c_str (), lpdeplist, deployoption, &IAsyncProgressCallback, &callback, &lperr, &lpmsg); + errorcode = lperr ? lperr : L""; + detailmsg = lpmsg ? lpmsg : L""; + if (lperr) PackageManagerFreeString (lperr); + if (lpmsg) PackageManagerFreeString (lpmsg); + return hr; +} +HRESULT SetAppxPackageStatus ( + const std::wstring &package_full_name, + DWORD status, // PACKAGESTATUS_* ǰ׺ + std::wstring &errorcode = std::wstring (), + std::wstring &detailmsg = std::wstring () +) { + LPWSTR lperr = nullptr, lpmsg = nullptr; + HRESULT hr = SetAppxPackageStatus (package_full_name.c_str (), status, &lperr, &lpmsg); + errorcode = lperr ? lperr : L""; + detailmsg = lpmsg ? lpmsg : L""; + if (lperr) PackageManagerFreeString (lperr); + if (lpmsg) PackageManagerFreeString (lpmsg); + return hr; +} +HRESULT ActivateAppxApplication ( + const std::wstring &app_user_id, + PDWORD ret_processid = nullptr +) { + return ActivateAppxApplication (app_user_id.c_str (), ret_processid); +} +#endif \ No newline at end of file diff --git a/pkgmgr/stdafx.h b/pkgmgr/stdafx.h index dea2cf7..db2dd4a 100644 --- a/pkgmgr/stdafx.h +++ b/pkgmgr/stdafx.h @@ -15,9 +15,6 @@ // TODO: ڴ˴óҪͷļ #using -using namespace Platform; -using namespace Windows::Foundation; -using namespace Windows::Management::Deployment; #include #include #include @@ -30,4 +27,7 @@ using namespace Windows::Management::Deployment; #include #include #include -#include \ No newline at end of file +#include +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Management::Deployment; diff --git a/pkgread/dllmain.cpp b/pkgread/dllmain.cpp index 16b23e9..c63aef3 100644 --- a/pkgread/dllmain.cpp +++ b/pkgread/dllmain.cpp @@ -10,10 +10,10 @@ BOOL APIENTRY DllMain( HMODULE hModule, { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: - CoInitializeEx (NULL, COINIT_MULTITHREADED); break; + // CoInitializeEx (NULL, COINIT_MULTITHREADED); break; case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: - CoUninitialize (); + // CoUninitialize (); break; } return TRUE; diff --git a/pkgread/filepath.h b/pkgread/filepath.h new file mode 100644 index 0000000..eb7c12a --- /dev/null +++ b/pkgread/filepath.h @@ -0,0 +1,871 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include "strcmp.h" +#include "version.h" +#include "module.h" +typedef version S_VERSION; +template constexpr T Max (T l, T r) { return l > r ? l : r; } +template constexpr T Max (T l, T m, T r) { return Max (Max (l, r), m); } +template constexpr T Max (T l, T ml, T mr, T r) { return Max (Max (l, ml), Max (mr, r)); } +template std::basic_string replace_substring +( + const std::basic_string &str, + const std::basic_string &from, + const std::basic_string &to +) +{ + if (from.empty ()) return str; + std::basic_string result; + size_t pos = 0; + size_t start_pos; + while ((start_pos = str.find (from, pos)) != std::basic_string::npos) + { + result.append (str, pos, start_pos - pos); + result.append (to); + pos = start_pos + from.length (); + } + result.append (str, pos, str.length () - pos); + return result; +} +std::string GetProgramRootDirectoryA (HMODULE hModule hModule_DefaultParam) +{ + char path [MAX_PATH]; + if (GetModuleFileNameA (hModule, path, MAX_PATH)) + { + std::string dir (path); + size_t pos = dir.find_last_of ("\\/"); + if (pos != std::string::npos) + { + dir = dir.substr (0, pos); + } + return dir; + } + return ""; +} +std::wstring GetProgramRootDirectoryW (HMODULE hModule hModule_DefaultParam) +{ + wchar_t path [MAX_PATH]; + if (GetModuleFileNameW (hModule, path, MAX_PATH)) + { + std::wstring dir (path); + size_t pos = dir.find_last_of (L"\\/"); + if (pos != std::wstring::npos) + { + dir = dir.substr (0, pos); + } + return dir; + } + return L""; +} +std::string EnsureTrailingSlash (const std::string &path) +{ + if (path.empty ()) return path; // ·ֱӷ + + char lastChar = path.back (); + if (lastChar == '\\' || lastChar == '/') + return path; // зֱָӷ + // ϵͳԭ·ʽʵķָ + char separator = (path.find ('/') != std::string::npos) ? '/' : '\\'; + return path + separator; +} +std::wstring EnsureTrailingSlash (const std::wstring &path) +{ + if (path.empty ()) return path; + + wchar_t lastChar = path.back (); + if (lastChar == L'\\' || lastChar == L'/') + return path; + + wchar_t separator = (path.find (L'/') != std::wstring::npos) ? L'/' : L'\\'; + return path + separator; +} +bool IsFileExistsW (LPCWSTR filename) +{ + DWORD dwAttrib = GetFileAttributesW (filename); + return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); +} +bool IsFileExistsA (LPCSTR filename) +{ + DWORD dwAttrib = GetFileAttributesA (filename); + return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); +} +bool IsFileExists (LPWSTR filePath) { return IsFileExistsW (filePath); } +bool IsFileExists (LPCSTR filePath) { return IsFileExistsA (filePath); } +bool IsFileExists (const std::string &filePath) { return IsFileExistsA (filePath.c_str ()); } +bool IsFileExists (const std::wstring &filePath) { return IsFileExistsW (filePath.c_str ()); } +bool IsDirectoryExistsA (LPCSTR path) +{ + DWORD attributes = GetFileAttributesA (path); + return (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY)); +} +bool IsDirectoryExistsW (LPCWSTR path) +{ + DWORD attributes = GetFileAttributesW (path); + return (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY)); +} +bool IsDirectoryExists (const std::string &path) { return IsDirectoryExistsA (path.c_str ()); } +bool IsDirectoryExists (const std::wstring &path) { return IsDirectoryExistsW (path.c_str ()); } +bool IsDirectoryExists (LPCSTR path) { return IsDirectoryExistsA (path); } +bool IsDirectoryExists (LPCWSTR path) { return IsDirectoryExistsW (path); } +bool IsPathExistsW (LPCWSTR filename) +{ + DWORD dwAttrib = GetFileAttributesW (filename); + return (dwAttrib != INVALID_FILE_ATTRIBUTES); +} +bool IsPathExistsA (LPCSTR filename) +{ + DWORD dwAttrib = GetFileAttributesA (filename); + return (dwAttrib != INVALID_FILE_ATTRIBUTES); +} +bool IsPathExists (const std::string &path) { return IsPathExistsA (path.c_str ()); } +bool IsPathExists (const std::wstring &path) { return IsPathExistsW (path.c_str ()); } +bool IsPathExists (LPCSTR path) { return IsPathExistsA (path); } +bool IsPathExists (LPCWSTR path) { return IsPathExistsW (path); } +std::string NormalizePath (const std::string &path) +{ + if (!path.empty () && path.back () == '\\') + return path.substr (0, path.size () - 1); + return path.c_str (); +} +std::wstring NormalizePath (const std::wstring &path) +{ + if (!path.empty () && path.back () == L'\\') + return path.substr (0, path.size () - 1); + return path.c_str (); +} +std::vector EnumSubdirectories (const std::string &directory, bool includeParentPath) +{ + std::vector subdirs; + std::string normPath = NormalizePath (directory); + std::string searchPath = normPath + "\\*"; + WIN32_FIND_DATAA findData; + HANDLE hFind = FindFirstFileA (searchPath.c_str (), &findData); + if (hFind == INVALID_HANDLE_VALUE) return subdirs; + do + { + // "." ".." + if (strcmp (findData.cFileName, ".") == 0 || strcmp (findData.cFileName, "..") == 0) + continue; + // жǷΪĿ¼ + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (includeParentPath) + subdirs.push_back (normPath + "\\" + findData.cFileName); + else + subdirs.push_back (findData.cFileName); + } + } while (FindNextFileA (hFind, &findData)); + FindClose (hFind); + return subdirs; +} +std::vector EnumSubdirectories (const std::wstring &directory, bool includeParentPath) +{ + std::vector subdirs; + std::wstring normPath = NormalizePath (directory); + std::wstring searchPath = normPath + L"\\*"; + WIN32_FIND_DATAW findData; + HANDLE hFind = FindFirstFileW (searchPath.c_str (), &findData); + if (hFind == INVALID_HANDLE_VALUE) return subdirs; + do + { + if (wcscmp (findData.cFileName, L".") == 0 || wcscmp (findData.cFileName, L"..") == 0) + continue; + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (includeParentPath) + subdirs.push_back (normPath + L"\\" + findData.cFileName); + else + subdirs.push_back (findData.cFileName); + } + } while (FindNextFileW (hFind, &findData)); + FindClose (hFind); + return subdirs; +} +std::string GetCurrentProgramPathA (HMODULE hModule hModule_DefaultParam) +{ + std::vector buf (Max (MAX_PATH, GetModuleFileNameA (hModule, nullptr, 0)) + 1); + GetModuleFileNameA (hModule, buf.data (), buf.capacity ()); + return buf.data (); +} +std::wstring GetCurrentProgramPathW (HMODULE hModule hModule_DefaultParam) +{ + std::vector buf (Max (MAX_PATH, GetModuleFileNameW (hModule, nullptr, 0)) + 1); + GetModuleFileNameW (hModule, buf.data (), buf.capacity ()); + return buf.data (); +} +std::string GetCurrentProgramNameA (HMODULE hModule hModule_DefaultParam) { return PathFindFileNameA (GetCurrentProgramPathA (hModule).c_str ()); } +std::wstring GetCurrentProgramNameW (HMODULE hModule hModule_DefaultParam) { return PathFindFileNameW (GetCurrentProgramPathW (hModule).c_str ()); } +S_VERSION GetExeFileVersion (LPCSTR lpszFilePath) +{ + S_VERSION ver (0); + DWORD dummy; + DWORD size = GetFileVersionInfoSizeA (lpszFilePath, &dummy); + std::vector pVersionInfo (size); + if (!GetFileVersionInfoA (lpszFilePath, 0, size, pVersionInfo.data ())) + { + return ver; + } + VS_FIXEDFILEINFO* pFileInfo = nullptr; + UINT len = 0; + if (!VerQueryValueA (pVersionInfo.data (), "\\", (LPVOID *)&pFileInfo, &len)) + { + return ver; + } + if (len == 0 || pFileInfo == nullptr) + { + return ver; + } + ver = S_VERSION ( + HIWORD (pFileInfo->dwFileVersionMS), + LOWORD (pFileInfo->dwFileVersionMS), + HIWORD (pFileInfo->dwFileVersionLS), + LOWORD (pFileInfo->dwFileVersionLS) + ); + return ver; +} +S_VERSION GetExeFileVersion (LPCWSTR lpswFilePath) +{ + S_VERSION ver (0); + DWORD dummy; + DWORD size = GetFileVersionInfoSizeW (lpswFilePath, &dummy); + std::vector pVersionInfo (size); + if (!GetFileVersionInfoW (lpswFilePath, 0, size, pVersionInfo.data ())) + { + return ver; + } + VS_FIXEDFILEINFO* pFileInfo = nullptr; + UINT len = 0; + if (!VerQueryValueA (pVersionInfo.data (), "\\", (LPVOID *)&pFileInfo, &len)) + { + return ver; + } + if (len == 0 || pFileInfo == nullptr) + { + return ver; + } + ver = S_VERSION ( + HIWORD (pFileInfo->dwFileVersionMS), + LOWORD (pFileInfo->dwFileVersionMS), + HIWORD (pFileInfo->dwFileVersionLS), + LOWORD (pFileInfo->dwFileVersionLS) + ); + return ver; +} +S_VERSION GetExeFileVersion (std::wstring objswFilePath) +{ + return GetExeFileVersion (objswFilePath.c_str ()); +} +S_VERSION GetExeFileVersion (std::string objszFilePath) +{ + return GetExeFileVersion (objszFilePath.c_str ()); +} +// õǰ̵ĻRunPathProgramPath +void SetupInstanceEnvironment (HMODULE hModule hModule_DefaultParam) +{ + // RunPathΪǰĿ¼޽βбܣ + std::vector currentDir (Max (GetCurrentDirectoryW (0, nullptr), MAX_PATH) + 1); + DWORD len = GetCurrentDirectoryW (currentDir.capacity (), currentDir.data ()); + if (len > 0) + { + std::wstring runPath (currentDir.data ()); + if (!runPath.empty () && (runPath.back () == L'\\' || runPath.back () == L'/')) + { + runPath.pop_back (); + } + SetEnvironmentVariableW (L"RunPath", runPath.c_str ()); + } + // ProgramPathΪĿ¼޽βбܣ + std::vector modulePath (Max (GetModuleFileNameW (hModule, nullptr, 0), MAX_PATH) + 1); + len = GetModuleFileNameW (hModule, modulePath.data (), MAX_PATH); + if (len > 0 && len < MAX_PATH) + { + wchar_t* lastSlash = wcsrchr (modulePath.data (), L'\\'); + if (!lastSlash) lastSlash = wcsrchr (modulePath.data (), L'/'); + if (lastSlash) *lastSlash = L'\0'; + std::wstring programPath (modulePath.data ()); + if (!programPath.empty () && (programPath.back () == L'\\' || programPath.back () == L'/')) + { + programPath.pop_back (); + } + SetEnvironmentVariableW (L"ProgramPath", programPath.c_str ()); + } +} +// ַչ +std::wstring ProcessEnvVars (const std::wstring &input) +{ + DWORD requiredSize = ExpandEnvironmentStringsW (input.c_str (), nullptr, 0); + if (requiredSize == 0) return input; + std::wstring buffer (requiredSize, L'\0'); + if (!ExpandEnvironmentStringsW (input.c_str (), &buffer [0], requiredSize)) + { + return input; + } + buffer.resize (requiredSize - 1); // ȥַֹ + return buffer.c_str (); +} +std::wstring ProcessEnvVars (LPCWSTR input) +{ + return ProcessEnvVars (std::wstring (input)); +} +// ANSIַչ +std::string ProcessEnvVars (const std::string &input) +{ + DWORD requiredSize = ExpandEnvironmentStringsA (input.c_str (), nullptr, 0); + if (requiredSize == 0) return input; + std::string buffer (requiredSize, '\0'); + if (!ExpandEnvironmentStringsA (input.c_str (), &buffer [0], requiredSize)) + { + return input; + } + buffer.resize (requiredSize - 1); // ȥַֹ + return buffer.c_str (); +} +std::string ProcessEnvVars (LPCSTR input) +{ + return ProcessEnvVars (std::string (input)); +} +std::string GetCurrentDirectoryA () +{ + std::vector buf (Max (GetCurrentDirectoryA (0, nullptr), MAX_PATH) + 1); + GetCurrentDirectoryA (buf.size (), buf.data ()); + return buf.data (); +} +std::wstring GetCurrentDirectoryW () +{ + std::vector buf (Max (GetCurrentDirectoryW (0, nullptr), MAX_PATH) + 1); + GetCurrentDirectoryW (buf.size (), buf.data ()); + return buf.data (); +} +std::wstring GetFileDirectoryW (const std::wstring &filePath) +{ + std::vector buf (filePath.capacity () + 1); + lstrcpyW (buf.data (), filePath.c_str ()); + PathRemoveFileSpecW (buf.data ()); + return buf.data (); +} +std::string GetFileDirectoryA (const std::string &filePath) +{ + std::vector buf (filePath.capacity () + 1); + lstrcpyA (buf.data (), filePath.c_str ()); + PathRemoveFileSpecA (buf.data ()); + return buf.data (); +} +size_t EnumerateFilesW (const std::wstring &directory, const std::wstring &filter, + std::vector &outFiles, bool recursive = false) +{ + std::wstring searchPath = directory; + if (!searchPath.empty () && searchPath.back () != L'\\') + { + searchPath += L'\\'; + } + searchPath += filter; + WIN32_FIND_DATAW findData; + HANDLE hFind = FindFirstFileW (searchPath.c_str (), &findData); + if (hFind != INVALID_HANDLE_VALUE) + { + do { + if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + outFiles.push_back (directory + L"\\" + findData.cFileName); + } + } while (FindNextFileW (hFind, &findData)); + FindClose (hFind); + } + if (recursive) { + std::wstring subDirSearchPath = directory + L"\\*"; + hFind = FindFirstFileW (subDirSearchPath.c_str (), &findData); + if (hFind != INVALID_HANDLE_VALUE) + { + do { + if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && + wcscmp (findData.cFileName, L".") != 0 && wcscmp (findData.cFileName, L"..") != 0) + { + EnumerateFilesW (directory + L"\\" + findData.cFileName, filter, outFiles, true); + } + } while (FindNextFileW (hFind, &findData)); + FindClose (hFind); + } + } + return outFiles.size (); +} +// ǷΪ Windows 豸СдУ +bool IsReservedName (const std::wstring &name) +{ + static const wchar_t* reserved [] = { + L"CON", L"PRN", L"AUX", L"NUL", L"COM1", L"COM2", L"COM3", L"COM4", L"COM5", L"COM6", L"COM7", L"COM8", L"COM9", + L"LPT1", L"LPT2", L"LPT3", L"LPT4", L"LPT5", L"LPT6", L"LPT7", L"LPT8", L"LPT9" + }; + std::wstring upperName = StringToUpper (name); + for (const auto& res : reserved) + { + if (upperName == res || (upperName.rfind (res, 0) == 0 && upperName.length () > wcslen (res) && upperName [wcslen (res)] == L'.')) + { + return true; + } + } + return false; +} +// Windows ļ淶 (Unicode) +bool IsValidWindowsNameW (LPCWSTR name) +{ + if (!name || !*name) return false; + std::wstring wname (name); + if (wname.find_first_of (L"<>:\"/\\|?*") != std::wstring::npos) return false; + if (IsReservedName (wname)) return false; + if (wname.back () == L' ' || wname.back () == L'.') return false; + return true; +} +// Windows ļ淶 (ANSI) +bool IsValidWindowsNameA (LPCSTR name) +{ + if (!name || !*name) return false; + std::string str (name); + if (str.find_first_of ("<>:\"/\\|?*") != std::string::npos) return false; + + // ת ANSI ַ + int len = MultiByteToWideChar (CP_ACP, 0, name, -1, NULL, 0); + if (len <= 0) return false; + std::wstring wname (len - 1, L'\0'); + MultiByteToWideChar (CP_ACP, 0, name, -1, &wname [0], len); + if (IsReservedName (wname)) return false; + if (str.back () == ' ' || str.back () == '.') return false; + return true; +} +bool IsValidWindowsName (LPCSTR name) { return IsValidWindowsNameA (name); } +bool IsValidWindowsName (LPCWSTR name) { return IsValidWindowsNameW (name); } +bool IsValidWindowsName (const std::wstring &name) { return IsValidWindowsName (name.c_str ()); } +bool IsValidWindowsName (const std::string &name) { return IsValidWindowsName (name.c_str ()); } +std::wstring GetRootFolderNameFromFilePath (const std::wstring &lpFilePath) +{ + std::vector szPath (Max (lpFilePath.length (), MAX_PATH) + 1); + if (!PathCanonicalizeW (szPath.data (), lpFilePath.c_str ())) return L""; + if (PathRemoveFileSpecW (szPath.data ()) == FALSE) return L""; + LPCWSTR pszFolder = PathFindFileNameW (szPath.data ()); + if (*pszFolder != L'\0') return std::wstring (pszFolder); + WCHAR rootName [3] = {szPath [0], L':', L'\0'}; + return std::wstring (rootName); +} +std::wstring GetSafeTimestampForFilename () +{ + ::FILETIME ft; + GetSystemTimeAsFileTime (&ft); + SYSTEMTIME st; + FileTimeToSystemTime (&ft, &st); + std::wstringstream wss; + wss << std::setfill (L'0') + << st.wYear + << std::setw (2) << st.wMonth + << std::setw (2) << st.wDay << L"_" + << std::setw (2) << st.wHour + << std::setw (2) << st.wMinute + << std::setw (2) << st.wSecond + << std::setw (3) << st.wMilliseconds; + return wss.str (); +} +size_t EnumFiles ( + const std::wstring &lpDir, + const std::wstring &lpFilter, + std::vector &aszOutput, + bool bOutputWithPath = false, + bool bSortByLetter = false, + bool bIncludeSubDir = false +) { + if (!bIncludeSubDir) aszOutput.clear (); + std::vector filters; + size_t start = 0; + while (start < lpFilter.length ()) + { + size_t pos = lpFilter.find (L'\\', start); + if (pos == std::wstring::npos) pos = lpFilter.length (); + filters.emplace_back (lpFilter.substr (start, pos - start)); + start = pos + 1; + } + + std::function enumDir; + enumDir = [&] (const std::wstring &physicalPath, std::wstring relativePath) + { + WIN32_FIND_DATAW ffd; + HANDLE hFind = FindFirstFileW ((physicalPath + L"\\*").c_str (), &ffd); + if (hFind == INVALID_HANDLE_VALUE) return; + do { + if (wcscmp (ffd.cFileName, L".") == 0 || + wcscmp (ffd.cFileName, L"..") == 0) continue; + const bool isDir = (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); + const std::wstring newPhysical = physicalPath + L"\\" + ffd.cFileName; + std::wstring newRelative = relativePath; + if (isDir) { + if (bIncludeSubDir) { + newRelative += ffd.cFileName; + newRelative += L"\\"; + enumDir (newPhysical, newRelative); + } + } + else + { + for (const auto &filter : filters) + { + if (PathMatchSpecW (ffd.cFileName, filter.c_str ())) + { + aszOutput.push_back + ( + bOutputWithPath ? newPhysical : (relativePath + ffd.cFileName) + ); + break; + } + } + } + } while (FindNextFileW (hFind, &ffd)); + FindClose (hFind); + }; + enumDir (lpDir, L""); + if (bSortByLetter) std::sort (aszOutput.begin (), aszOutput.end ()); + return aszOutput.size (); +} +std::wstring GetRelativePath ( + const std::wstring &pszBaseDir, + const std::wstring &pszFullPath, + DWORD cchRelative +) { + std::vector szBase (Max (pszBaseDir.length (), pszFullPath.length (), MAX_PATH) + 1); + wcscpy_s (szBase.data (), MAX_PATH, pszBaseDir.c_str ()); + if (szBase [wcslen (szBase.data ()) - 1] != L'\\') + { + wcscat_s (szBase.data (), MAX_PATH, L"\\"); + } + std::vector buf (Max (MAX_PATH, szBase.size ()) + 1); + BOOL res = PathRelativePathToW ( + buf.data (), + szBase.data (), + FILE_ATTRIBUTE_DIRECTORY, + pszFullPath.c_str (), + FILE_ATTRIBUTE_NORMAL + ); + if (res) return buf.data (); + else return L""; +} +size_t EnumDirectory ( + const std::wstring &lpDir, + std::vector &aszOutput, + bool bOutputWithPath = false, + bool bSortByLetter = false, + bool bIncludeSubDir = false +) { + aszOutput.clear (); + std::function enumDir; + enumDir = [&] (const std::wstring &physicalPath, const std::wstring &relativePath) { + WIN32_FIND_DATAW ffd; + HANDLE hFind = FindFirstFileW ((physicalPath + L"\\*").c_str (), &ffd); + if (hFind == INVALID_HANDLE_VALUE) return; + do + { + const std::wstring name = ffd.cFileName; + if (name == L"." || name == L"..") continue; + const bool isDir = (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + std::wstring newPhysical = physicalPath + L"\\" + name; + std::wstring newRelative = relativePath + name; + if (isDir) + { + if (bIncludeSubDir) enumDir (newPhysical, newRelative + L"\\"); + if (bOutputWithPath) aszOutput.push_back (newPhysical); + else aszOutput.push_back (newRelative); + } + } while (FindNextFileW (hFind, &ffd)); + FindClose (hFind); + }; + enumDir (lpDir, L""); + if (bSortByLetter) std::sort (aszOutput.begin (), aszOutput.end ()); + return aszOutput.size (); +} + +static DWORD CALLBACK ProgressRoutine ( + LARGE_INTEGER TotalFileSize, + LARGE_INTEGER TotalBytesTransferred, + LARGE_INTEGER /*StreamSize*/, + LARGE_INTEGER /*StreamBytesTransferred*/, + DWORD /*dwStreamNumber*/, + DWORD /*dwCallbackReason*/, + HANDLE /*hSourceFile*/, + HANDLE /*hDestinationFile*/, + LPVOID lpData +) { + auto *pCallback = reinterpret_cast *> (lpData); + if (pCallback && *pCallback) + { + int progress = static_cast ( + (TotalBytesTransferred.QuadPart * 100) / TotalFileSize.QuadPart + ); + (*pCallback) (progress); + } + return PROGRESS_CONTINUE; +} +bool RenameFileW ( + const std::wstring &lpSrcPath, + const std::wstring &lpDestPath, + std::function fProgress = nullptr +) { + LPPROGRESS_ROUTINE pRoutine = nullptr; + LPVOID pData = nullptr; + if (fProgress) + { + pRoutine = ProgressRoutine; + pData = &fProgress; + } + DWORD flags = MOVEFILE_COPY_ALLOWED; + BOOL ok = MoveFileWithProgressW ( + lpSrcPath.c_str (), + lpDestPath.c_str (), + pRoutine, + pData, + flags + ); + return ok != FALSE; +} +bool RenameFileA ( + const std::string &lpSrcPath, + const std::string &lpDestPath, + std::function fProgress = nullptr +) { + LPPROGRESS_ROUTINE pRoutine = nullptr; + LPVOID pData = nullptr; + if (fProgress) + { + pRoutine = ProgressRoutine; + pData = &fProgress; + } + DWORD flags = MOVEFILE_COPY_ALLOWED; + BOOL ok = MoveFileWithProgressA ( + lpSrcPath.c_str (), + lpDestPath.c_str (), + pRoutine, + pData, + flags + ); + return ok != FALSE; +} +bool RenameFileW (const std::wstring &lpSrcDir, const std::wstring &lpSrcName, const std::wstring &lpDestName, std::function fProgress = nullptr) +{ + struct BuildTask + { + LPWSTR src = nullptr, dest = nullptr; + ~BuildTask () + { + if (src != nullptr) + { + delete [] src; + src = nullptr; + } + if (dest != nullptr) + { + delete [] dest; + dest = nullptr; + } + } + }; + BuildTask bt; + bt.src = new WCHAR [lpSrcDir.length () + lpSrcName.length () + 2]; + bt.dest = new WCHAR [lpSrcDir.length () + lpDestName.length () + 2]; + PathCombineW (bt.src, lpSrcDir.c_str (), lpSrcName.c_str ()); + PathCombineW (bt.dest, lpSrcDir.c_str (), lpDestName.c_str ()); + return RenameFileW (bt.src, bt.dest, fProgress); +} +bool RenameFileA (const std::string &lpSrcDir, const std::string &lpSrcName, const std::string &lpDestName, std::function fProgress = nullptr) +{ + struct BuildTask + { + LPSTR src = nullptr, dest = nullptr; + ~BuildTask () + { + if (src != nullptr) + { + delete [] src; + src = nullptr; + } + if (dest != nullptr) + { + delete [] dest; + dest = nullptr; + } + } + }; + BuildTask bt; + bt.src = new CHAR [lpSrcDir.length () + lpSrcName.length () + 2]; + bt.dest = new CHAR [lpSrcDir.length () + lpDestName.length () + 2]; + PathCombineA (bt.src, lpSrcDir.c_str (), lpSrcName.c_str ()); + PathCombineA (bt.dest, lpSrcDir.c_str (), lpDestName.c_str ()); + return RenameFileA (bt.src, bt.dest, fProgress); +} +bool RenameFile (const std::wstring &lpSrcPath, const std::wstring &lpDestPath, std::function fProgress = nullptr) +{ + return RenameFileW (lpSrcPath, lpDestPath, fProgress); +} +bool RenameFile (const std::string &lpSrcPath, const std::string &lpDestPath, std::function fProgress = nullptr) +{ + return RenameFileA (lpSrcPath, lpDestPath, fProgress); +} +bool RenameFile (const std::wstring &lpSrcDir, const std::wstring &lpSrcName, const std::wstring &lpDestName, std::function fProgress = nullptr) +{ + return RenameFileW (lpSrcDir, lpSrcName, lpDestName, fProgress); +} +bool RenameFile (const std::string &lpSrcDir, const std::string &lpSrcName, const std::string &lpDestName, std::function fProgress = nullptr) +{ + return RenameFileA (lpSrcDir, lpSrcName, lpDestName, fProgress); +} +bool RenameDirectoryW ( + const std::wstring &lpSrcPath, + const std::wstring &lpDestPath, + std::function fProgress = nullptr +) { + LPPROGRESS_ROUTINE pRoutine = nullptr; + LPVOID pData = nullptr; + if (fProgress) + { + pRoutine = ProgressRoutine; + pData = &fProgress; + } + DWORD flags = MOVEFILE_COPY_ALLOWED; + BOOL ok = MoveFileWithProgressW ( + lpSrcPath.c_str (), + lpDestPath.c_str (), + pRoutine, + pData, + flags + ); + return ok != FALSE; +} +bool RenameDirectoryA ( + const std::string &lpSrcPath, + const std::string &lpDestPath, + std::function fProgress = nullptr +) { + LPPROGRESS_ROUTINE pRoutine = nullptr; + LPVOID pData = nullptr; + if (fProgress) + { + pRoutine = ProgressRoutine; + pData = &fProgress; + } + DWORD flags = MOVEFILE_COPY_ALLOWED; + BOOL ok = MoveFileWithProgressA ( + lpSrcPath.c_str (), + lpDestPath.c_str (), + pRoutine, + pData, + flags + ); + return ok != FALSE; +} +bool RenameDirectoryW ( + const std::wstring &lpParentDir, + const std::wstring &lpSrcName, + const std::wstring &lpDestName, + std::function fProgress = nullptr +) { + struct PathBuilder + { + LPWSTR src = nullptr; + LPWSTR dest = nullptr; + ~PathBuilder () + { + delete [] src; + delete [] dest; + } + } pb; + pb.src = new WCHAR [lpParentDir.length () + lpSrcName.length () + 2]; + pb.dest = new WCHAR [lpParentDir.length () + lpDestName.length () + 2]; + PathCombineW (pb.src, lpParentDir.c_str (), lpSrcName.c_str ()); + PathCombineW (pb.dest, lpParentDir.c_str (), lpDestName.c_str ()); + return RenameDirectoryW (pb.src, pb.dest, fProgress); +} +bool RenameDirectoryA ( + const std::string &lpParentDir, + const std::string &lpSrcName, + const std::string &lpDestName, + std::function fProgress = nullptr +) { + struct PathBuilder + { + LPSTR src = nullptr; + LPSTR dest = nullptr; + ~PathBuilder () + { + delete [] src; + delete [] dest; + } + } pb; + pb.src = new CHAR [lpParentDir.length () + lpSrcName.length () + 2]; + pb.dest = new CHAR [lpParentDir.length () + lpDestName.length () + 2]; + PathCombineA (pb.src, lpParentDir.c_str (), lpSrcName.c_str ()); + PathCombineA (pb.dest, lpParentDir.c_str (), lpDestName.c_str ()); + return RenameDirectoryA (pb.src, pb.dest, fProgress); +} +bool RenameDirectory ( + const std::wstring &src, + const std::wstring &dst, + std::function fProgress = nullptr +) { + return RenameDirectoryW (src, dst, fProgress); +} +bool RenameDirectory ( + const std::string &src, + const std::string &dst, + std::function fProgress = nullptr +) { + return RenameDirectoryA (src, dst, fProgress); +} +bool RenameDirectory ( + const std::wstring &parentDir, + const std::wstring &srcName, + const std::wstring &dstName, + std::function fProgress = nullptr +) { + return RenameDirectoryW (parentDir, srcName, dstName, fProgress); +} +bool RenameDirectory ( + const std::string &parentDir, + const std::string &srcName, + const std::string &dstName, + std::function fProgress = nullptr +) { + return RenameDirectoryA (parentDir, srcName, dstName, fProgress); +} +std::wstring CombinePath (const std::wstring &left, const std::wstring &right) +{ + std::vector buf (left.capacity () + right.capacity () + 2); + PathCombineW (buf.data (), left.c_str (), right.c_str ()); + return buf.data (); +} +#ifdef PathCommonPrefix +#undef PathCommonPrefix +#endif +std::wstring PathCommonPrefix (const std::wstring &file1, const std::wstring &file2) +{ + std::vector buf (Max (file1.capacity (), file2.capacity (), MAX_PATH) + 2); + PathCommonPrefixW (file1.c_str (), file2.c_str (), buf.data ()); + return buf.data (); +} +#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); +} +bool PathEquals (const std::wstring &path1, const std::wstring &path2) +{ + size_t maxlen = Max (path1.capacity () + 1, path2.capacity () + 1, MAX_PATH); + std::vector buf1 (maxlen), buf2 (maxlen); + PathCanonicalizeW (buf1.data (), path1.c_str ()); + PathCanonicalizeW (buf2.data (), path2.c_str ()); + return IsNormalizeStringEquals (buf1.data (), buf2.data ()); +} \ No newline at end of file diff --git a/pkgread/module.h b/pkgread/module.h new file mode 100644 index 0000000..4001903 --- /dev/null +++ b/pkgread/module.h @@ -0,0 +1,51 @@ +#pragma once +#include +#ifdef __cplusplus +#ifndef GetCurrentModule_bRefDefault +// C++ УGetCurrentModule Ĭֵ֮ǰ궨Ĭֵʱ˵Ⱥš= +// ÷磺HMODULE GetCurrentModule (BOOL bRef GetCurrentModule_bRefDefault) +#define GetCurrentModule_bRefDefault = FALSE +#endif +#else +#define GetCurrentModule_bRefDefault +#endif +HMODULE GetCurrentModule (BOOL bRef GetCurrentModule_bRefDefault) +{ + HMODULE hModule = NULL; + if (GetModuleHandleExW (bRef ? GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS : (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS + | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT), (LPCWSTR)GetCurrentModule, &hModule)) + { + return hModule; + } + return NULL; +} +HMODULE GetSelfModuleHandle () +{ + MEMORY_BASIC_INFORMATION mbi; + return ((::VirtualQuery (GetSelfModuleHandle, &mbi, sizeof (mbi)) != 0) + ? (HMODULE)mbi.AllocationBase : NULL); +} +#ifndef GetModuleHandleW_lpModuleNameDefault +#define GetModuleHandleW_lpModuleNameDefault NULL +#endif +#ifndef DEFAULT_HMODULE +#ifdef HMODULE_MODE_EXE +#define DEFAULT_HMODULE GetModuleHandleW (NULL) +#elif defined (HMODULE_MODE_DLL1) +#define DEFAULT_HMODULE GetCurrentModule () +#elif defined (HMODULE_MODE_DLL2) +#define DEFAULT_HMODULE GetSelfModuleHandle () +#else +#define DEFAULT_HMODULE GetModuleHandleW (GetModuleHandleW_lpModuleNameDefault) +#endif +#endif +#undef GetModuleHandleW_lpModuleNameDefault +#ifdef __cplusplus +#ifndef hModule_DefaultParam +// C++ Уʹô˺ꡰhModule_DefaultParamڸһЩβζĬֵ֮ǰ궨Ĭֵʱ˵Ⱥš= +// ÷磺std::wstring GetRCStringSW (UINT resID, HMODULE hModule hModule_DefaultParam) +#define hModule_DefaultParam = DEFAULT_HMODULE +#endif +#else +#define hModule_DefaultParam +#endif \ No newline at end of file diff --git a/pkgread/packages.config b/pkgread/packages.config index a7a422e..c2da1c1 100644 --- a/pkgread/packages.config +++ b/pkgread/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/pkgread/pkgread.cpp b/pkgread/pkgread.cpp index 99ddf38..ff4436d 100644 --- a/pkgread/pkgread.cpp +++ b/pkgread/pkgread.cpp @@ -1171,3 +1171,46 @@ LPWSTR StreamToBase64W (_In_ HANDLE hFileStream, _Out_writes_ (dwCharCount) LPWS if (lpBase64Head) *lpBase64Head = retptr + head; return retptr; } + +LPWSTR GetPackagePrerequistieSystemVersionName (_In_ HPKGREAD hReader, _In_ LPCWSTR lpName) +{ + auto ptr = ToPtrPackage (hReader); + if (!ptr) return nullptr; + switch (ptr->type ()) + { + case PackageType::single: { + auto read = ptr->appx_reader (); + auto pre = read.prerequisites (); + auto ver = pre.get_version (lpName ? lpName : L""); + auto str = GetPrerequistOSVersionDescription (ver); + return _wcsdup (str.c_str ()); + } break; + case PackageType::bundle: { + auto br = ptr->bundle_reader (); + CComPtr iaf; + if (FAILED (br.random_application_package (&iaf))) return nullptr; + CComPtr ist; + if (FAILED (iaf->GetStream (&ist))) return nullptr; + CComPtr iar; + if (FAILED (GetAppxPackageReader (ist, &iar))) return nullptr; + appxreader read (iar.p); + auto pre = read.prerequisites (); + auto ver = pre.get_version (lpName ? lpName : L""); + auto str = GetPrerequistOSVersionDescription (ver); + return _wcsdup (str.c_str ()); + } + default: + break; + } + return nullptr; +} + +LPWSTR GetPackageCapabilityDisplayName (LPCWSTR lpCapabilityName) +{ + if (!lpCapabilityName) return nullptr; + std::wnstring capname = (lpCapabilityName ? lpCapabilityName : L""); + if (capname.empty ()) return nullptr; + std::wstring ret = GetCapabilityDisplayName (capname); + if (IsNormalizeStringEmpty (ret)) return nullptr; + else return _wcsdup (ret.c_str ()); +} \ No newline at end of file diff --git a/pkgread/pkgread.h b/pkgread/pkgread.h index 79a6898..07cc6d9 100644 --- a/pkgread/pkgread.h +++ b/pkgread/pkgread.h @@ -251,6 +251,7 @@ extern "C" PKGREAD_API BOOL GetPackagePrerequisite (_In_ HPKGREAD hReader, _In_ LPCWSTR lpName, _Outptr_ VERSION *pVerRet); #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_) + PKGREAD_API LPWSTR GetPackagePrerequistieSystemVersionName (_In_ HPKGREAD hReader, _In_ LPCWSTR lpName); // File Stream // Appx лȡ Appx еļļ @@ -282,6 +283,9 @@ extern "C" 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); + // ȡʾ internetClient Ӧ Internet ӡصӦϵͳԵı + // ע⣺صַһҪͨ free ͷš + PKGREAD_API LPWSTR GetPackageCapabilityDisplayName (LPCWSTR lpCapabilityName); #ifdef _DEFAULT_INIT_VALUE_ #undef _DEFAULT_INIT_VALUE_ #endif @@ -320,6 +324,35 @@ const std::vector g_filepathitems = L"Wide310x150Logo", L"Executable" }; +std::map g_capnamemap; +std::wstring GetPackageCapabilityDisplayName (const std::wstring &capname) +{ + try + { + if (g_capnamemap.find (capname) != g_capnamemap.end () && !g_capnamemap.at (capname).empty ()) return g_capnamemap.at (capname); + else + { + LPWSTR lpstr = GetPackageCapabilityDisplayName (capname.c_str ()); + std::wstring ret = L""; + ret += lpstr ? lpstr : L""; + if (lpstr) free (lpstr); + lpstr = nullptr; + g_capnamemap [capname] = ret; + return ret; + } + } + catch (...) + { + LPWSTR lpstr = GetPackageCapabilityDisplayName (capname.c_str ()); + std::wstring ret = L""; + ret += lpstr ? lpstr : L""; + if (lpstr) free (lpstr); + lpstr = nullptr; + g_capnamemap [capname] = ret; + return ret; + } + return L""; +} class package_reader { private: @@ -984,6 +1017,17 @@ class package_reader } VERSION os_min_version () const { return get_version (PKG_PREREQUISITE_OS_MIN_VERSION); } VERSION os_max_version_tested () const { return get_version (PKG_PREREQUISITE_OS_MAX_VERSION_TESTED); } + std::wstring get_description (const std::wstring &name) const + { + LPWSTR lpstr = GetPackagePrerequistieSystemVersionName (hReader, name.c_str ()); + deconstr relt ([&lpstr] () { + if (lpstr) free (lpstr); + lpstr = nullptr; + }); + return lpstr ? lpstr : L""; + } + std::wstring os_min_version_description () const { return get_description (PKG_PREREQUISITE_OS_MIN_VERSION); } + std::wstring os_max_version_tested_description () const { return get_description (PKG_PREREQUISITE_OS_MAX_VERSION_TESTED); } }; package_reader (): hReader (CreatePackageReader ()) {} package_reader (const std::wstring &fpath): hReader (CreatePackageReader ()) diff --git a/pkgread/pkgread.rc b/pkgread/pkgread.rc index 0856007..d8e7986 100644 Binary files a/pkgread/pkgread.rc and b/pkgread/pkgread.rc differ diff --git a/pkgread/pkgread.vcxproj b/pkgread/pkgread.vcxproj index 46cf9b6..5d2b7fb 100644 --- a/pkgread/pkgread.vcxproj +++ b/pkgread/pkgread.vcxproj @@ -86,13 +86,13 @@ Use Level3 Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;PKGREAD_EXPORTS;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;_USRDLL;PKGREAD_EXPORTS;HMODULE_MODE_DLL1;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true Windows true - urlmon.lib;crypt32.lib;%(AdditionalDependencies) + urlmon.lib;crypt32.lib;version.lib;xmllite.lib;%(AdditionalDependencies) @@ -115,7 +115,7 @@ MaxSpeed true true - WIN32;NDEBUG;_WINDOWS;_USRDLL;PKGREAD_EXPORTS;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;_USRDLL;PKGREAD_EXPORTS;HMODULE_MODE_DLL1;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true @@ -123,7 +123,7 @@ true true true - urlmon.lib;crypt32.lib;%(AdditionalDependencies) + urlmon.lib;crypt32.lib;version.lib;xmllite.lib;%(AdditionalDependencies) @@ -148,17 +148,22 @@ + + + + + @@ -185,12 +190,19 @@ - + - + + + + + 这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 + + + \ No newline at end of file diff --git a/pkgread/pkgread.vcxproj.filters b/pkgread/pkgread.vcxproj.filters index 4b5706c..e061920 100644 --- a/pkgread/pkgread.vcxproj.filters +++ b/pkgread/pkgread.vcxproj.filters @@ -57,6 +57,21 @@ 头文件 + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + @@ -69,12 +84,12 @@ 源文件 - - - 资源文件 + + + \ No newline at end of file diff --git a/pkgread/rctools.h b/pkgread/rctools.h new file mode 100644 index 0000000..8e6a12b --- /dev/null +++ b/pkgread/rctools.h @@ -0,0 +1,121 @@ +#pragma once +#include +#include +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "typestrans.h" +#include "module.h" + +// صָǿһҪ free ͷ +LPWSTR GetRCStringW (UINT resID, HMODULE hModule hModule_DefaultParam) +{ + std::vector buf (256); + size_t cnt = 0; +CopyStringLoop_GetRCStringW: + { + size_t len = LoadStringW (hModule, resID, buf.data (), buf.size ()); + if (cnt > 1625) return _wcsdup (buf.data ()); + if (len >= buf.size () - 1) + { + buf.resize (buf.size () + 20); + cnt ++; + goto CopyStringLoop_GetRCStringW; + } + else return _wcsdup (buf.data ()); + } +} +// صָǿһҪ free ͷ +LPSTR GetRCStringA (UINT resID, HMODULE hModule hModule_DefaultParam) +{ + std::vector buf (256); + size_t cnt = 0; +CopyStringLoop_GetRCStringA: + { + size_t len = LoadStringA (hModule, resID, buf.data (), buf.size ()); + if (cnt > 1625) return _strdup (buf.data ()); + if (len >= buf.size () - 1) + { + buf.resize (buf.size () + 20); + cnt ++; + goto CopyStringLoop_GetRCStringA; + } + else return _strdup (buf.data ()); + } +} + +HICON LoadRCIcon (UINT resID, HMODULE hModule hModule_DefaultParam) +{ + return (HICON)LoadImageW (hModule, MAKEINTRESOURCEW (resID), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); +} +HRSRC FindResourceByName (LPCWSTR resourceName, LPCWSTR resourceType, HMODULE hModule hModule_DefaultParam) +{ + return FindResourceW (hModule, resourceName, resourceType); +} +#ifdef __cplusplus +#include +std::wstring GetRCStringSW (UINT resID, HMODULE hModule hModule_DefaultParam) +{ + std::vector buf (256); + size_t cnt = 0; +CopyStringLoop_GetRCStringSW: + { + size_t len = LoadStringW (hModule, resID, buf.data (), buf.size ()); + if (cnt > 1625) return buf.data (); + if (len >= buf.size () - 1) + { + buf.resize (buf.size () + 20); + cnt ++; + goto CopyStringLoop_GetRCStringSW; + } + else return buf.data (); + } +} +std::string GetRCStringSA (UINT resID, HMODULE hModule hModule_DefaultParam) +{ + std::vector buf (256); + size_t cnt = 0; +CopyStringLoop_GetRCStringSA: + { + size_t len = LoadStringA (hModule, resID, buf.data (), buf.size ()); + if (cnt > 1625) return buf.data (); + if (len >= buf.size () - 1) + { + buf.resize (buf.size () + 20); + cnt ++; + goto CopyStringLoop_GetRCStringSA; + } + else return buf.data (); + } +} +#endif +#if defined (__cplusplus) && defined (__cplusplus_cli) +using namespace System; +String ^GetRCStringCli (UINT resID, HMODULE hModule hModule_DefaultParam) +{ + std::vector buf (256); + size_t cnt = 0; +CopyStringLoop_GetRCStringCli: + { + size_t len = LoadStringW (hModule, resID, buf.data (), buf.size ()); + if (cnt > 1625) return gcnew String (buf.data ()); + if (len >= buf.size () - 1) + { + buf.resize (buf.size () + 20); + cnt ++; + goto CopyStringLoop_GetRCStringCli; + } + else return gcnew String (buf.data ()); + } +} +#define GetRCIntValue(_UINT__resID_) toInt (GetRCStringCli (_UINT__resID_)) +#define GetRCDoubleValue(_UINT__resID_) toDouble (GetRCStringCli (_UINT__resID_)) +#define GetRCBoolValue(_UINT__resID_) toBool (GetRCStringCli (_UINT__resID_)) +#define GetRCDateTimeValue(_UINT__resID_) toDateTime (GetRCStringCli (_UINT__resID_)) +#define rcString(resID) GetRCStringCli (resID) +#define rcInt(resID) GetRCIntValue (resID) +#define rcDouble(resID) GetRCDoubleValue (resID) +#define rcBool(resID) GetRCBoolValue (resID) +#define rcDTime(resID) GetRCDateTimeValue (resID) +#define rcIcon(resID) LoadRCIcon (resID) +#endif \ No newline at end of file diff --git a/pkgread/readobj.h b/pkgread/readobj.h index 885e109..e85597c 100644 --- a/pkgread/readobj.h +++ b/pkgread/readobj.h @@ -9,27 +9,14 @@ #include #include #include +#include #include "dynarr.h" #include "version.h" #include "stringres.h" #include "norstr.h" #include "raii.h" #include "priformatcli.h" - -bool IsFileExistsW (LPCWSTR filename) -{ - DWORD dwAttrib = GetFileAttributesW (filename); - return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); -} -bool IsFileExistsA (LPCSTR filename) -{ - DWORD dwAttrib = GetFileAttributesA (filename); - return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); -} -bool IsFileExists (LPWSTR filePath) { return IsFileExistsW (filePath); } -bool IsFileExists (LPCSTR filePath) { return IsFileExistsA (filePath); } -bool IsFileExists (std::string filePath) { return IsFileExistsA (filePath.c_str ()); } -bool IsFileExists (std::wstring filePath) { return IsFileExistsW (filePath.c_str ()); } +#include "filepath.h" HRESULT GetBundleReader (_In_ LPCWSTR inputFileName, _Outptr_ IAppxBundleReader** bundleReader) { @@ -615,9 +602,53 @@ namespace appx_info { using Base = com_info ; APPX_CAPABILITIES cflags; + std::vector cnames; public: using Base::Base; - appx_capabs (IAppxManifestDeviceCapabilitiesEnumerator *devicec, APPX_CAPABILITIES capa): cflags (capa), com_info (devicec) {} + appx_capabs (IAppxManifestDeviceCapabilitiesEnumerator *devicec, APPX_CAPABILITIES capa, IAppxManifestReader *&r): cflags (capa), com_info (devicec) + { + if (!r) return; + CComPtr xmlstream; + if (FAILED (r->GetStream (&xmlstream))) return; + CComPtr xmlreader; + if (FAILED (CreateXmlReader (__uuidof (IXmlReader), (void **)&xmlreader, nullptr))) return; + xmlreader->SetInput (xmlstream.p); + XmlNodeType nodeType; + bool inPackage = false; + bool inCapabilities = false; + HRESULT hr = S_OK; + auto &reader = xmlreader; + while (SUCCEEDED (hr = xmlreader->Read (&nodeType)) && hr == S_OK) + { + if (nodeType == XmlNodeType_Element) + { + LPCWSTR localName = nullptr; + reader->GetLocalName (&localName, nullptr); + // + if (!inPackage && _wcsicmp (localName, L"Package") == 0) inPackage = true; + // + else if (inPackage && !inCapabilities && _wcsicmp (localName, L"Capabilities") == 0) inCapabilities = true; + // + else if (inCapabilities && _wcsicmp (localName, L"Capability") == 0) + { + if (SUCCEEDED (reader->MoveToAttributeByName (L"Name", nullptr))) + { + LPCWSTR value = nullptr; + reader->GetValue (&value, nullptr); + if (value && *value) cnames.push_back (value); + } + reader->MoveToElement (); + } + } + else if (nodeType == XmlNodeType_EndElement) + { + LPCWSTR localName = nullptr; + reader->GetLocalName (&localName, nullptr); + if (inCapabilities && _wcsicmp (localName, L"Capabilities") == 0) inCapabilities = false; + else if (inPackage && _wcsicmp (localName, L"Package") == 0) break; + } + } + } appx_capabs () = default; APPX_CAPABILITIES capabilities () const { return cflags; } size_t device_capabilities (_Out_ std::vector &output) const @@ -634,7 +665,8 @@ namespace appx_info size_t capabilities_names (_Out_ std::vector &output) const { output.clear (); - CapabilitiesFlagsToNames (cflags, output); + if (cnames.empty ()) CapabilitiesFlagsToNames (cflags, output); + else for (auto &it : cnames) output.push_back (it); return output.size (); } // ȡܺ豸ܵй @@ -889,8 +921,9 @@ class appxreader: virtual public com_info_quote { APPX_CAPABILITIES caps; IAppxManifestDeviceCapabilitiesEnumerator *ip = nullptr; - get_device_capabilities (&ip); - if (SUCCEEDED (get_capabilities (&caps))) return appx_info::appx_capabs (ip, caps); + CComPtr im; + if (SUCCEEDED (manifest (&im))) im->GetDeviceCapabilities (&ip); + if (SUCCEEDED (get_capabilities (&caps))) return appx_info::appx_capabs (ip, caps, im.p); return appx_info::appx_capabs (ip); } HRESULT get_dependencies (_Outptr_ IAppxManifestPackageDependenciesEnumerator **output) const { return get_from_manifest (&Manifest::GetPackageDependencies, output); } diff --git a/pkgread/resource1.h b/pkgread/resource1.h index 155cbf3..3d6996b 100644 Binary files a/pkgread/resource1.h and b/pkgread/resource1.h differ diff --git a/pkgread/strcmp.h b/pkgread/strcmp.h new file mode 100644 index 0000000..f3b7486 --- /dev/null +++ b/pkgread/strcmp.h @@ -0,0 +1,154 @@ +#pragma once +#include +#include "norstr.h" +#ifdef __cplusplus +#define ptrnull(ptr) (!(ptr)) +#else +#define ptrnull(ptr) ((ptr) == NULL) +#endif +#define ptrvalid(ptr) (!ptrnull (ptr)) +// char * WCHAR * ַβΪ NULLжǷΪǿַָЧҳȴ 0ǧҰָ룬һ +#define strvalid(strptr) (ptrvalid (strptr) && *(strptr)) +// char * WCHAR * ַβΪ NULLжǷΪַָΪ NULL 򳤶Ϊ 0ǧҰָ룬һ +#define strnull(strptr) (ptrnull (strptr) || !*(strptr)) +typedef std::wnstring strlabel, StringLabel; +std::wstring StringTrim (const std::wstring &str) { return std::wnstring::trim (str); } +std::string StringTrim (const std::string &str) { return std::nstring::trim (str); } +#define StringToUpper l0km::toupper +#define StringToLower l0km::tolower +int LabelCompare (const std::wstring &l1, const std::wstring &l2) +{ + return std::wnstring::compare (l1, l2); +} +int LabelCompare (const std::string &l1, const std::string &l2) +{ + return std::nstring::compare (l1, l2); +} +bool LabelEqual (const std::wstring &l1, const std::wstring &l2) +{ + return std::wnstring::equals (l1, l2); +} +bool LabelEqual (const std::string &l1, const std::string &l2) +{ + return std::wnstring::equals (l1, l2); +} +bool LabelEmpty (const std::wstring &str) { return std::wnstring::empty (str); } +bool LabelEmpty (const std::string &str) { return std::nstring::empty (str); } +#define LabelNoEmpty(_str_) (!LabelEmpty (_str_)) +int InStr (const std::string &text, const std::string &keyword, bool ignoreCase = false) +{ + std::string s1, s2; + if (ignoreCase) + { + s1 = StringToUpper (text); + s2 = StringToUpper (keyword); + } + else + { + s1 = text; + s2 = keyword; + } + const char *found = StrStrIA (s1.c_str (), s2.c_str ()); + if (!found) + { + return -1; + } + return found - text.c_str (); +} +int InStr (const std::wstring &text, const std::wstring &keyword, bool ignoreCase = false) +{ + std::wstring s1, s2; + if (ignoreCase) + { + s1 = StringToUpper (text); + s2 = StringToUpper (keyword); + } + else + { + s1 = text; + s2 = keyword; + } + const WCHAR *found = StrStrIW (s1.c_str (), s2.c_str ()); + if (!found) + { + return -1; + } + return found - text.c_str (); +} +bool StrInclude (const std::string &text, const std::string &keyword, bool ignoreCase = false) +{ + std::string s1, s2; + if (ignoreCase) + { + s1 = StringToUpper (text); + s2 = StringToUpper (keyword); + } + else + { + s1 = text; + s2 = keyword; + } + const char *found = StrStrIA (s1.c_str (), s2.c_str ()); + if (!found) return false; + return true; +} +bool StrInclude (const std::wstring &text, const std::wstring &keyword, bool ignoreCase = false) +{ + std::wstring s1, s2; + if (ignoreCase) + { + s1 = StringToUpper (text); + s2 = StringToUpper (keyword); + } + else + { + s1 = text; + s2 = keyword; + } + const WCHAR *found = StrStrIW (s1.c_str (), s2.c_str ()); + if (!found) return false; + return true; +} +// ú "\0\0" ַͨöԻеļ +LPCWSTR strcpynull (LPWSTR dest, LPCWSTR endwith, size_t bufsize) +{ + if (!dest || !endwith || bufsize == 0) + return dest; + if (dest [0] == L'\0' && bufsize > 1) + { + dest [1] = L'\0'; + } + size_t pos = 0; + while (pos < bufsize - 1) + { + if (dest [pos] == L'\0' && dest [pos + 1] == L'\0') + { + if (dest [0]) pos ++; + break; + } + pos ++; + } + size_t i = 0; + while (pos < bufsize - 1 && endwith [i] != L'\0') + { + dest [pos ++] = endwith [i ++]; + } + if (pos < bufsize) + { + dest [pos] = L'\0'; + } + return dest; +} +// ȡıߣע⣺ָıַ硰chijΪ2 +std::wstring GetStringLeft (const std::wstring &str, size_t length) +{ + std::vector buf (length + 1); + lstrcpynW (buf.data (), str.c_str (), length + 1); + return buf.data (); +} +// ȡıұ +std::wstring GetStringRight (const std::wstring &str, size_t length) +{ + if (length >= str.length ()) return str; + return str.substr (str.length () - length, length).c_str (); +} diff --git a/pkgread/stringres.h b/pkgread/stringres.h index fa3fb27..69ba372 100644 --- a/pkgread/stringres.h +++ b/pkgread/stringres.h @@ -1,10 +1,16 @@ #pragma once #include #include +#include +#include #include "version.h" #include "dynarr.h" #include "norstr.h" #include "syncutil.h" +#include "resource1.h" +#include "localeex.h" +#include "rctools.h" +#include "filepath.h" static const std::pair captable [] = { {APPX_CAPABILITY_INTERNET_CLIENT, L"internetClient"}, {APPX_CAPABILITY_INTERNET_CLIENT_SERVER, L"internetClientServer"}, @@ -123,4 +129,202 @@ bool RemoveApplicationAttributeItem (const std::wstring &lpstr) return appitems.size () < len1; } return false; +} + +#define MAKENAMEIDMAP(_Res_Name_) {#_Res_Name_, _Res_Name_} +std::map g_nameToId = { + MAKENAMEIDMAP (accessoryManager), + MAKENAMEIDMAP (activity), + MAKENAMEIDMAP (allJoyn), + MAKENAMEIDMAP (allowElevation), + MAKENAMEIDMAP (appDiagnostics), + MAKENAMEIDMAP (applicationData), + MAKENAMEIDMAP (applicationPackage), + MAKENAMEIDMAP (appLicensing), + MAKENAMEIDMAP (appointments), + MAKENAMEIDMAP (appointmentsSystem), + MAKENAMEIDMAP (appointmentSystem), + MAKENAMEIDMAP (authenticationManagerAuthentication), + MAKENAMEIDMAP (blockedChatMessages), + MAKENAMEIDMAP (bluetooth), + MAKENAMEIDMAP (bluetooth_genericAttributeProfile), + MAKENAMEIDMAP (bluetooth_rfcomm), + MAKENAMEIDMAP (broadFileSystemAccess), + MAKENAMEIDMAP (callHistory), + MAKENAMEIDMAP (callHistorySystem), + MAKENAMEIDMAP (cellularDeviceControl), + MAKENAMEIDMAP (cellularDeviceIdentity), + MAKENAMEIDMAP (cellularMessaging), + MAKENAMEIDMAP (chat), + MAKENAMEIDMAP (chatSystem), + MAKENAMEIDMAP (codeGeneration), + MAKENAMEIDMAP (confirmAppClose), + MAKENAMEIDMAP (contacts), + MAKENAMEIDMAP (contactsSystem), + MAKENAMEIDMAP (contactSystem), + MAKENAMEIDMAP (cortanaSpeechAccessory), + MAKENAMEIDMAP (customInstallActions), + MAKENAMEIDMAP (deviceManagementDmAccount), + MAKENAMEIDMAP (deviceManagementEmailAccount), + MAKENAMEIDMAP (deviceManagementFoundation), + MAKENAMEIDMAP (deviceManagementWapSecurityPolicies), + MAKENAMEIDMAP (deviceMangementFoundation), + MAKENAMEIDMAP (deviceUnlock), + MAKENAMEIDMAP (documentsLibrary), + MAKENAMEIDMAP (dualSimTiles), + MAKENAMEIDMAP (email), + MAKENAMEIDMAP (emailSystem), + MAKENAMEIDMAP (enterpriseAuthentication), + MAKENAMEIDMAP (enterpriseDataPolicy), + MAKENAMEIDMAP (enterpriseDeviceLockdown), + MAKENAMEIDMAP (extendedExecutionBackgroundAudio), + MAKENAMEIDMAP (extendedExecutionCritical), + MAKENAMEIDMAP (extendedExecutionUnconstrained), + MAKENAMEIDMAP (externalDependenciesVirtualCapability), + MAKENAMEIDMAP (firstSignInSettings), + MAKENAMEIDMAP (gameList), + MAKENAMEIDMAP (humaninterfacedevice), + MAKENAMEIDMAP (hyperLinkLearnMore), + MAKENAMEIDMAP (inputForegroundObservation), + MAKENAMEIDMAP (inputInjection), + MAKENAMEIDMAP (inputInjection_Brokered), + MAKENAMEIDMAP (inputObservation), + MAKENAMEIDMAP (inputSuppression), + MAKENAMEIDMAP (internetClient), + MAKENAMEIDMAP (internetClientServer), + MAKENAMEIDMAP (interopServices), + MAKENAMEIDMAP (localSystemServices), + MAKENAMEIDMAP (location), + MAKENAMEIDMAP (locationHistory), + MAKENAMEIDMAP (locationSystem), + MAKENAMEIDMAP (lockScreenCreatives), + MAKENAMEIDMAP (lowLevelDevices), + MAKENAMEIDMAP (microphone), + MAKENAMEIDMAP (modifiableApp), + MAKENAMEIDMAP (musicLibrary), + MAKENAMEIDMAP (networkConnectionManagerProvisioning), + MAKENAMEIDMAP (networkDataPlanProvisioning), + MAKENAMEIDMAP (networkingVpnProvider), + MAKENAMEIDMAP (objects3d), + MAKENAMEIDMAP (oemDeployment), + MAKENAMEIDMAP (oemPublicDirectory), + MAKENAMEIDMAP (optical), + MAKENAMEIDMAP (packagedServices), + MAKENAMEIDMAP (packageManagement), + MAKENAMEIDMAP (packagePolicySystem), + MAKENAMEIDMAP (packageQuery), + MAKENAMEIDMAP (packageWriteRedirectionCompatibilityShim), + MAKENAMEIDMAP (phoneCall), + MAKENAMEIDMAP (phoneCallHistory), + MAKENAMEIDMAP (phoneCallHistoryPublic), + MAKENAMEIDMAP (phoneCallHistorySystem), + MAKENAMEIDMAP (picturesLibrary), + MAKENAMEIDMAP (pointOfService), + MAKENAMEIDMAP (previewStore), + MAKENAMEIDMAP (previewUiComposition), + MAKENAMEIDMAP (privateNetworkClientServer), + MAKENAMEIDMAP (proximity), + MAKENAMEIDMAP (recordedCallsFolder), + MAKENAMEIDMAP (remotePassportAuthentication), + MAKENAMEIDMAP (removableStorage), + MAKENAMEIDMAP (runFullTrust), + MAKENAMEIDMAP (screenDuplication), + MAKENAMEIDMAP (sharedUserCertificates), + MAKENAMEIDMAP (smsSend), + MAKENAMEIDMAP (spatialPerception), + MAKENAMEIDMAP (systemManagement), + MAKENAMEIDMAP (teamEditionExperience), + MAKENAMEIDMAP (uiAccess), + MAKENAMEIDMAP (unvirtualizedResources), + MAKENAMEIDMAP (usb), + MAKENAMEIDMAP (userAccountInformation), + MAKENAMEIDMAP (userDataAccountSetup), + MAKENAMEIDMAP (userDataAccountsProvider), + MAKENAMEIDMAP (userDataSystem), + MAKENAMEIDMAP (userPrincipalName), + MAKENAMEIDMAP (userSigninSupport), + MAKENAMEIDMAP (videosLibrary), + MAKENAMEIDMAP (visualElementsSystem), + MAKENAMEIDMAP (visualVoiceMail), + MAKENAMEIDMAP (voipCall), + MAKENAMEIDMAP (walletSystem), + MAKENAMEIDMAP (webcam), + MAKENAMEIDMAP (wiFiControl), + MAKENAMEIDMAP (xboxAccessoryManagement) +}; +#ifdef MAKENAMEIDMAP +#undef MAKENAMEIDMAP +#endif +std::string GetSuitableLanguageValue (const std::map &map, const std::nstring &localename) +{ + for (auto &it : map) if (it.first == localename) return it.second; + for (auto &it : map) if (LocaleNameCompare (pugi::as_wide (it.first), pugi::as_wide (localename))) return it.second; + for (auto &it : map) if (IsNormalizeStringEquals (GetLocaleRestrictedCodeA (it.first), GetLocaleRestrictedCodeA (localename))) return it.second; + for (auto &it : map) if (LocaleNameCompare (pugi::as_wide (GetLocaleRestrictedCodeA (it.first)), pugi::as_wide (GetLocaleRestrictedCodeA (localename)))) return it.second; + return ""; +} +std::string GetSuitableLanguageValue (const std::map &map) +{ + if (map.empty ()) return ""; + std::string ret = GetSuitableLanguageValue (map, pugi::as_utf8 (GetComputerLocaleCodeW ())); + if (ret.empty ()) ret = GetSuitableLanguageValue (map, "en-US"); + if (ret.empty ()) ret = map.begin ()->second; + return ret; +} +struct xmldoc +{ + pugi::xml_document doc; + bool isvalid = false; + void destroy () + { + if (isvalid) doc.reset (); + isvalid = false; + } + bool create (const std::wstring &filepath) + { + destroy (); + auto res = doc.load_file (filepath.c_str ()); + return isvalid = res; + } + xmldoc (const std::wstring &filepath) { create (filepath); } + ~xmldoc () { destroy (); } + std::string get (const std::string &id) const + { + auto root = doc.first_child (); + auto nodes = root.children (); + for (auto &it : nodes) + { + if (IsNormalizeStringEquals (std::string (it.attribute ("id").as_string ()), id)) + { + auto strings = it.children (); + std::map lang_value; + for (auto &sub : strings) + { + std::nstring lang = sub.attribute ("name").as_string (); + if (!lang.empty ()) lang_value [lang] = sub.text ().get (); + } + return GetSuitableLanguageValue (lang_value); + } + } + return ""; + } + std::wstring get (const std::wstring &id) const { return pugi::as_wide (get (pugi::as_utf8 (id))); } + std::wstring operator [] (const std::wstring &id) const { return get (id); } + std::wstring operator [] (const std::wstring &id) { return get (id); } + std::string operator [] (const std::string &id) const { return get (id); } + std::string operator [] (const std::string &id) { return get (id); } +} cap_localeres (CombinePath (GetProgramRootDirectoryW (), L"locale\\capabilities.xml")); +std::wstring GetCapabilityDisplayName (const std::wstring &capname) +{ + std::nstring searchname = pugi::as_utf8 (capname); + std::wstring ret = cap_localeres [capname]; + if (IsNormalizeStringEmpty (ret)) + { + for (auto &it : g_nameToId) + { + if (it.first == searchname) return GetRCStringSW (it.second); + } + } + else return ret; + return L""; } \ No newline at end of file diff --git a/pkgread/typestrans.h b/pkgread/typestrans.h new file mode 100644 index 0000000..7abde9b --- /dev/null +++ b/pkgread/typestrans.h @@ -0,0 +1,265 @@ +#pragma once +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif +#include +#ifdef __cplusplus +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif +unsigned _wtou (const wchar_t *str) +{ + unsigned value = 0; + if (str) + { + swscanf (str, L"%u", &value); + } + return value; +} +unsigned long _wtoul (const wchar_t *str) +{ + unsigned value = 0; + if (str) + { + swscanf (str, L"%lu", &value); + } + return value; +} +unsigned long long _wtou64 (const wchar_t *str) +{ + unsigned long long value = 0; + if (str) + { + swscanf (str, L"%llu", &value); + } + return value; +} +double _wtod (const wchar_t *str) +{ + if (!str || !*str) return 0.0; // ַָ + double value = 0.0; + if (swscanf (str, L"%lg", &value) == 1) + { + return value; + } + return 0.0; // ʧʱ 0.0 +} +unsigned atou (const char *str) +{ + unsigned value = 0; + if (str) + { + sscanf (str, "%u", &value); + } + return value; +} +unsigned long atoul (const char *str) +{ + unsigned value = 0; + if (str) + { + sscanf (str, "%lu", &value); + } + return value; +} +unsigned long long atou64 (const char *str) +{ + unsigned long long value = 0; + if (str) + { + sscanf (str, "%llu", &value); + } + return value; +} +double atod (const char *str) +{ + if (!str || !*str) return 0.0; // ַָ + double value = 0.0; + if (sscanf (str, "%lg", &value) == 1) + { + return value; + } + return 0.0; // ʧʱ 0.0 +} +int8_t atoi8 (const char *str) +{ + int value = 0; + if (str) sscanf (str, "%d", &value); + return (int8_t)value; +} +int16_t atoi16 (const char *str) +{ + int value = 0; + if (str) sscanf (str, "%d", &value); + return (int16_t)value; +} +int32_t atoi32 (const char *str) +{ + int32_t value = 0; + if (str) sscanf (str, "%d", &value); + return value; +} +uint8_t atoui8 (const char *str) +{ + unsigned value = 0; + if (str) sscanf (str, "%u", &value); + return (uint8_t)value; +} +uint16_t atoui16 (const char *str) +{ + unsigned value = 0; + if (str) sscanf (str, "%u", &value); + return (uint16_t)value; +} +uint32_t atoui32 (const char *str) +{ + uint32_t value = 0; + if (str) sscanf (str, "%u", &value); + return value; +} +int8_t _wtoi8 (const wchar_t *str) +{ + int value = 0; + if (str) swscanf (str, L"%d", &value); + return (int8_t)value; +} +int16_t _wtoi16 (const wchar_t *str) +{ + int value = 0; + if (str) swscanf (str, L"%d", &value); + return (int16_t)value; +} +int32_t _wtoi32 (const wchar_t *str) +{ + int32_t value = 0; + if (str) swscanf (str, L"%d", &value); + return value; +} +uint8_t _wtoui8 (const wchar_t *str) +{ + unsigned value = 0; + if (str) swscanf (str, L"%u", &value); + return (uint8_t)value; +} +uint16_t _wtoui16 (const wchar_t *str) +{ + unsigned value = 0; + if (str) swscanf (str, L"%u", &value); + return (uint16_t)value; +} +uint32_t _wtoui32 (const wchar_t *str) +{ + uint32_t value = 0; + if (str) swscanf (str, L"%u", &value); + return value; +} +int64_t atoi64 (const char *str) +{ + int64_t value = 0; + if (str) sscanf (str, "%lld", &value); + return value; +} + +EXTERN_C int StringToIntA (const char *str) { return atoi (str); } +EXTERN_C int StringToIntW (const WCHAR *str) { return _wtoi (str); } +EXTERN_C unsigned StringToUnsignedA (const char *str) { return atou (str); } +EXTERN_C unsigned StringToUnsignedW (const WCHAR *str) { return _wtou (str); } +EXTERN_C bool StringToBoolA (const char *str) +{ + char buf [32] = {0}; + strcpy (buf, str); + for (int cnt = 0; buf [cnt]; cnt ++) buf [cnt] = tolower (buf [cnt]); + return !strcmp (buf, "true") || + !strcmp (buf, "yes") || + !strcmp (buf, "ok") || + !strcmp (buf, "sure") || + !strcmp (buf, "okay") || + !strcmp (buf, "zhen") || + !strcmp (buf, ""); +} +EXTERN_C bool StringToBoolW (const WCHAR *str) +{ + WCHAR buf [32] = {0}; + lstrcpyW (buf, str); + for (int cnt = 0; buf [cnt]; cnt ++) buf [cnt] = tolower (buf [cnt]); + return !lstrcmpW (buf, L"true") || + !lstrcmpW (buf, L"yes") || + !lstrcmpW (buf, L"ok") || + !lstrcmpW (buf, L"sure") || + !lstrcmpW (buf, L"okay") || + !lstrcmpW (buf, L"zhen") || + !lstrcmpW (buf, L""); +} +EXTERN_C long StringToLongA (const char *str) { return atol (str); } +EXTERN_C long StringToLongW (const WCHAR *str) { return _wtol (str); } +EXTERN_C unsigned long StringToULongA (const char *str) { return atoul (str); } +EXTERN_C unsigned long StringToULongW (const WCHAR *str) { return _wtoul (str); } +EXTERN_C long long StringToLongLongA (const char *str) { return atoll (str); } +EXTERN_C long long StringToLongLongW (const WCHAR *str) { return _wtoll (str); } +EXTERN_C unsigned long long StringToULongLongA (const char *str) { return atou64 (str); } +EXTERN_C unsigned long long StringToULongLongW (const WCHAR *str) { return _wtou64 (str); } +EXTERN_C float StringToFloatA (const char *str) { return atof (str); } +EXTERN_C float StringToFloatW (const WCHAR *str) { return _wtof (str); } +EXTERN_C double StringToDoubleA (const char *str) { return atod (str); } +EXTERN_C double StringToDoubleW (const WCHAR *str) { return _wtod (str); } + +#ifdef __cplusplus +int StringToInt (LPCSTR str) { return StringToIntA (str); } +int StringToInt (LPCWSTR str) { return StringToIntW (str); } +unsigned StringToUnsigned (LPCSTR str) { return StringToUnsignedA (str); } +unsigned StringToUnsigned (LPCWSTR str) { return StringToUnsignedW (str); } +bool StringToBool (LPCSTR str) { return StringToBoolA (str); } +bool StringToBool (LPCWSTR str) { return StringToBoolW (str); } +long StringToLong (LPCSTR str) { return StringToLongA (str); } +long StringToLong (LPCWSTR str) { return StringToLongW (str); } +unsigned long StringToULong (LPCSTR str) { return StringToULongA (str); } +unsigned long StringToULong (LPCWSTR str) { return StringToULongW (str); } +long long StringToLongLong (LPCSTR str) { return StringToLongLongA (str); } +long long StringToLongLong (LPCWSTR str) { return StringToLongLongW (str); } +unsigned long long StringToULongLong (LPCSTR str) { return StringToULongLongA (str); } +unsigned long long StringToULongLong (LPCWSTR str) { return StringToULongLongW (str); } +float StringToFloat (LPCSTR str) { return StringToFloatA (str); } +float StringToFloat (LPCWSTR str) { return StringToFloatW (str); } +double StringToDouble (LPCSTR str) { return StringToDoubleA (str); } +double StringToDouble (LPCWSTR str) { return StringToDoubleW (str); } +#endif + +#if defined (__cplusplus) && defined (__cplusplus_cli) +using namespace System; +#define toInt(_String_Managed_Object_) Int32::Parse (_String_Managed_Object_) +#define objToInt(_Object_Managed_) Convert::ToInt32 (_Object_Managed_) +#define toDouble(_String_Managed_Object_) Double::Parse (_String_Managed_Object_) +#define objToDouble(_Object_Managed_) Convert::ToDouble (_Object_Managed_) +#define toBool(_String_Managed_Object_) Boolean::Parse (_String_Managed_Object_) +bool objToBool (Object ^result) +{ + if (!result) return false; + try + { + String ^strValue = safe_cast (result); + return (strValue->ToLower () == "on"); + } + catch (InvalidCastException ^) + { + try + { + return Convert::ToBoolean (result); + } + catch (InvalidCastException ^) + { + return false; + } + } + return false; +} +#define toDateTime(_String_Managed_Object_) DateTime::Parse (_String_Managed_Object_) +#define toDateTimeObj(_Object_Managed_) Convert::ToDateTime (_Object_Managed_) +#define objectToType(_Object_Managed_, _Type_Name_) Convert::To##_Type_Name_ (_Object_Managed_) +#endif \ No newline at end of file diff --git a/shared/html/css/pages.css b/shared/html/css/pages.css index de2b1fc..1a5c49d 100644 --- a/shared/html/css/pages.css +++ b/shared/html/css/pages.css @@ -24,6 +24,7 @@ body * { margin: 0px; padding: 0px; border: 0px; + background-color: #f3f3f3; } .pagecontainer.full { @@ -74,6 +75,17 @@ body * { color: white; } +.page.splash .content.splash .status-text { + width: 100%; + padding: 0 20px; + box-sizing: border-box; + margin-top: 10px; + overflow-y: hidden; + overflow-x: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + .page.splash .content.splash progress { border-style: none; background-color: transparent; @@ -257,9 +269,53 @@ progress.win-ring:indeterminate::-ms-fill { box-sizing: border-box; transition: width 0.5s cubic-bezier(0.1, 0.9, 0.2, 1), height 0.5s cubic-bezier(0.1, 0.9, 0.2, 1), top 0.5s cubic-bezier(0.1, 0.9, 0.2, 1), left 0.5s cubic-bezier(0.1, 0.9, 0.2, 1), right 0.5s cubic-bezier(0.1, 0.9, 0.2, 1), bottom 0.5s cubic-bezier(0.1, 0.9, 0.2, 1), margin 0.5s cubic-bezier(0.1, 0.9, 0.2, 1), padding 0.5s cubic-bezier(0.1, 0.9, 0.2, 1); list-style-position: outside; + color: rgb(113, 113, 113); /*test*/ - border: 1px solid black; - padding: 5px; + /*border: 1px solid black; + padding: 5px;*/ +} + +.page .content p, +.page .content span, +.page .content h1, +.page .content label, +.page .content select, +.page .content .functions ul li, +.page .content .reason { + font-weight: normal; +} + +.page .content .pkgtitle.multiple { + font-weight: bold; + -ms-overflow-x: hidden; + -ms-overflow-y: hidden; + -ms-text-overflow: ellipsis; + white-space: nowrap; + max-height: 1.3em; + max-width: 100%; +} + +.page .content .pkgtitle.multiple span { + font-weight: bold; + -ms-overflow-x: hidden; + -ms-overflow-y: hidden; + -ms-text-overflow: ellipsis; + max-height: 1.3em; + white-space: nowrap; + max-width: 100%; +} + +.pkgtitle span[data-overflow]::after { + content: "..."; +} + +.page>.content h1 { + font-size: 25pt; + margin-bottom: 8px; +} + +.page>.content .pkgapplabel { + color: rgb(0, 120, 215); } .page>.progress { @@ -273,6 +329,14 @@ progress.win-ring:indeterminate::-ms-fill { box-sizing: border-box; } +.content #moreinfo-flyout-content p>span:nth-child(1) { + -ms-user-select: none; +} + +.content #moreinfo-flyout-content>span:nth-child(2) { + color: darkgray; +} + .progress * { width: 100%; } @@ -364,7 +428,7 @@ progress.win-ring:indeterminate::-ms-fill { } .page.select>.controls.select>.command button:nth-of-type(2) { - display: none; + /*display: none;*/ } .page.select>.content.select, @@ -450,4 +514,32 @@ progress.win-ring:indeterminate::-ms-fill { .page.installing.multiple>.content .currentfile select, .page.installing.multiple>.content .currentfile br { display: none; +} + +@keyframes scale-visible { + from { + transform: translateX(50px) scale(0.8); + opacity: 0; + } + to { + transform: translateX(0) scale(1); + opacity: 1; + } +} + +.page.installsuccess.multiple>.content.installsuccess * { + display: none; +} + +.page.installsuccess.multiple>.content.installsuccess>.currentfile { + display: block; +} + +.page.installsuccess.multiple>.content.installsuccess>.currentfile h1.title { + display: block; +} + +.page.installsuccess>.controls.installsuccess>.command button:nth-of-type(2), +.page.installfailed>.controls.installsuccess>.command button:nth-of-type(2) { + display: none; } \ No newline at end of file diff --git a/shared/html/deepseek_html_20251122_6d71df.html b/shared/html/deepseek_html_20251122_6d71df.html new file mode 100644 index 0000000..5a36103 --- /dev/null +++ b/shared/html/deepseek_html_20251122_6d71df.html @@ -0,0 +1,376 @@ + + + + + + 动画效果测试 + + + + + + + + + +
+
+

动画效果测试

+

此页面展示animation.js中定义的所有动画效果。点击每个动画类别下的按钮来测试对应的动画。

+
+ +
+
+

弹出动画 (Flyout)

+
+
+
+ + + + + + + + +
+
等待动画执行...
+
+
+ +
+

渐变动画 (Opacity)

+
+
+
+ + +
+
等待动画执行...
+
+
+ +
+

缩放动画 (Scale)

+
+
+
+ + +
+
等待动画执行...
+
+
+ +
+

默认动画 (Default)

+
+
+
+ + + + +
+
等待动画执行...
+
+
+ +
+

边缘动画 (Edge)

+
+
+
+ + +
+
等待动画执行...
+
+
+ +
+

面板动画 (Panel)

+
+
+
+ + + + +
+
等待动画执行...
+
+
+ +
+

弹出动画 (Popup)

+
+
+
+ +
+
等待动画执行...
+
+
+ +
+

拖放动画 (Drag)

+
+
+
+ + +
+
等待动画执行...
+
+
+ +
+

内容动画 (Content)

+
+
+
+ + +
+
等待动画执行...
+
+
+ +
+

页面动画 (Page)

+
+
+
+ + +
+
等待动画执行...
+
+
+ +
+

其他动画

+
+
+
+ + +
+
等待动画执行...
+
+
+
+ +
+

动画效果测试页面 - 使用 WinJS 动画库

+
+
+ + + + \ No newline at end of file diff --git a/shared/html/install.html b/shared/html/install.html index aee1fcb..1cc701a 100644 --- a/shared/html/install.html +++ b/shared/html/install.html @@ -20,6 +20,7 @@ + @@ -27,11 +28,12 @@
-
+
Splash Screen
+

-

+


    -
  • 使用全部的系统资源
- + +
+
+
+

+

:

+

:

+

:

+

:

+

:

+

:

+
+
+

+

:

+

:

+
+
+

+

:

+

:

+
    +
    +
    +
    + +
     
    - +

    @@ -119,11 +312,10 @@
    - - + +
    -
    diff --git a/shared/html/js/animation.js b/shared/html/js/animation.js index 5b44fc5..cbf69cb 100644 --- a/shared/html/js/animation.js +++ b/shared/html/js/animation.js @@ -152,35 +152,114 @@ } return swResult; } - + /** + * 异步设置动画,返回一个 Promise 对象,动画结束后会执行 + * @param {HTMLElement} element 元素节点 + * @param {string|Array } swKeyFrames 动画关键帧名称 + * @param {number} uMillisecond 动画持续时间(毫秒) + * @param {string} [swTimingFunc] 缓动函数,默认 cubic-bezier(0.1, 0.9, 0.2, 1) + * @param {number} [uDelayMs] 延迟时间(毫秒),默认 0 + * @param {string} [swIteration] 播放次数,默认 "1" + * @param {string} [swDirection] 播放方向,默认 "normal" + * @param {string} [swFillMode] 填充模式,默认 "forwards" + * @param {string} [swPlayState] 播放状态,默认 "" + * @returns {Promise} + */ + function RunAsync(element, swKeyFrames, uMillisecond, swTimingFunc, uDelayMs, swIteration, swDirection, swFillMode, swPlayState) { + return new WinJS.Promise(function(complete) { + element.style.animation = generateAnimeString(swKeyFrames, uMillisecond, swTimingFunc, uDelayMs, swIteration, swDirection, swFillMode, swPlayState); + element.addEventListener("animationend", function() { + element.style.animation = ""; + complete(); + }); + }); + } module.exports = { Windows: { UI: { Animation: { Keyframes: AnimationKeyFrames, Animation: generateAnimeString, - /** - * 异步设置动画,返回一个 Promise 对象,动画结束后会执行 - * @param {HTMLElement} element 元素节点 - * @param {string|Array } swKeyFrames 动画关键帧名称 - * @param {number} uMillisecond 动画持续时间(毫秒) - * @param {string} [swTimingFunc] 缓动函数,默认 cubic-bezier(0.1, 0.9, 0.2, 1) - * @param {number} [uDelayMs] 延迟时间(毫秒),默认 0 - * @param {string} [swIteration] 播放次数,默认 "1" - * @param {string} [swDirection] 播放方向,默认 "normal" - * @param {string} [swFillMode] 填充模式,默认 "forwards" - * @param {string} [swPlayState] 播放状态,默认 "" - * @returns {Promise} - */ - RunAsync: function(element, swKeyFrames, uMillisecond, swTimingFunc, uDelayMs, swIteration, swDirection, swFillMode, swPlayState) { - return new WinJS.Promise(function(complete) { - element.style.animation = generateAnimeString(swKeyFrames, uMillisecond, swTimingFunc, uDelayMs, swIteration, swDirection, swFillMode, swPlayState); - element.addEventListener("animationend", function() { - element.style.animation = ""; - complete(); - }); - }); - } + animation: generateAnimeString, + RunAsync: RunAsync, + runAsync: RunAsync + } + } + } + }; + if (!String.prototype.repeat) { + String.prototype.repeat = function(count) { + 'use strict'; + if (this == null) { throw new TypeError('can\'t convert ' + this + ' to object'); } + var str = '' + this; + count = +count; + if (count != count) { count = 0 } + if (count < 0) { throw new RangeError('repeat count must be non-negative'); } + if (count == Infinity) { throw new RangeError('repeat count must be less than infinity'); } + count = Math.floor(count); + if (str.length == 0 || count == 0) { return '' } + if (str.length * count >= 1 << 28) { throw new RangeError('repeat count must not overflow maximum string size'); } + var rpt = ''; + for (var i = 0; i < count; i++) { rpt += str } + return rpt + } + } + var timers = {}; + + function DisplayLoadingAmineChar(containerId, shouldAnimate) { + var container = null; + if (containerId instanceof HTMLElement) { + if (typeof containerId.id === "string" && containerId.id.length > 0) { + container = containerId; + containerId = container.id; + } else { + containerId.id = "elementid-" + Math.floor(Math.random() * 1000000); + container = containerId; + containerId = container.id; + } + } else document.getElementById(containerId); + var textNode = container.firstChild; + if (!textNode || textNode.nodeType !== 3) { + textNode = document.createTextNode(""); + container.innerHTML = ""; + container.appendChild(textNode); + } + var chars = ''.repeat(10); + var index = 0; + var charGroupSize = 120; + + function showNextChar() { + if (index < chars.length) { + textNode.nodeValue = chars.charAt(index); + index++; + if (index % charGroupSize === 0) { + clearInterval(timers[containerId]); + setTimeout(startAnimation, 200); + } + } else { + index = 0; + textNode.nodeValue = chars.charAt(index); + } + } + + function startAnimation() { + if (timers[containerId]) { + clearInterval(timers[containerId]); + } + if (shouldAnimate) { + timers[containerId] = setInterval(showNextChar, 30); + } else { + clearInterval(timers[containerId]); + textNode.nodeValue = chars.charAt(chars.length - 1); + } + } + startAnimation(); + } + module.exports = { + Windows: { + UI: { + Animation: { + loading: DisplayLoadingAmineChar } } } diff --git a/shared/html/js/bridge.js b/shared/html/js/bridge.js index 97f14b9..ed9d50e 100644 --- a/shared/html/js/bridge.js +++ b/shared/html/js/bridge.js @@ -10,7 +10,10 @@ External: ext, Frame: { isIe10: function() { return ext.IEFrame.Version === 10; }, - isIe11: function() { return ext.IEFrame.Version === 11; } + isIe11: function() { return ext.IEFrame.Version === 11; }, + callEvent: function(funcName, e) { + ext.Window.CallEvent(funcName, e); + } }, UI: { Splash: { @@ -19,11 +22,12 @@ fadeOut: function() { ext.System.UI.FadeOutSplash(); } } }, - String: { - trim: function(str) { return ext.String.Trim(str); }, - tolower: function(str) { return ext.String.ToLower(str); }, - toupper: function(str) { return ext.String.ToUpper(str); }, - }, + String: ext.String, + /* { + trim: function(str) { return ext.String.Trim(str); }, + tolower: function(str) { return ext.String.ToLower(str); }, + toupper: function(str) { return ext.String.ToUpper(str); }, + }, */ NString: { equals: function(str1, str2) { return ext.String.NString.NEquals(str1, str2); }, compare: function(str1, str2) { return ext.String.NString.Compare(str1, str2); }, @@ -35,6 +39,26 @@ byid: function(resid) { return ext.System.Resources.GetById(resid); }, nameToId: function(resname) { return ext.System.Resources.ToId(resname); }, idToName: function(resid) { return ext.System.Resources.ToName(resid); }, + }, + Package: { + filepaths: function() { + return JSON.parse(ext.Package.GetPackagesToJson() || "[]"); + }, + pkginfo: function(filepath) { + return JSON.parse(ext.Package.GetPackageInfoToJson(filepath) || "{}"); + }, + capabilityDisplayName: function(capability) { + return ext.Package.GetCapabilityDisplayName(capability); + }, + installResult: function(filepath) { + return ext.Package.GetPackageInstallResult(filepath); + }, + }, + Locale: { + toLcid: function(localeName) { return ext.System.Locale.ToLcid(localeName); }, + toLocaleName: function(lcid) { return ext.System.Locale.ToLocaleName(lcid); }, + localeInfo: function(lcid, lcType) { return ext.System.Locale.LocaleInfo(lcid, lcType); }, + localeInfoEx: function(localeName, lcType) { return ext.System.Locale.LocaleInfoEx(localeName, lcType); } } }; Object.defineProperty(global.Bridge.Frame, "scale", { @@ -56,6 +80,15 @@ Object.defineProperty(global.Bridge.UI, "dpi", { get: function() { return ext.System.UI.DPI; } }); + Object.defineProperty(global.Bridge.UI, "themeColor", { + get: function() { return ext.System.UI.ThemeColor; } + }); + Object.defineProperty(global.Bridge.UI, "contrast", { + get: function() { return ext.System.UI.HighContrast; } + }); + Object.defineProperty(global.Bridge.UI, "darkmode", { + get: function() { return ext.System.UI.DarkMode; } + }); Object.defineProperty(global.Bridge.UI.Splash, "backcolor", { get: function() { return ext.System.UI.SplashBackgroundColor; }, }); diff --git a/shared/html/js/color.js b/shared/html/js/color.js index f39f9f2..cadb847 100644 --- a/shared/html/js/color.js +++ b/shared/html/js/color.js @@ -24,6 +24,7 @@ Object.defineProperty(this, "color", { get: function() { return parent; } }); + this.stringify = function() { return "rgb(" + parent.red + "," + parent.green + "," + parent.blue + ")"; }; } function RGBA(parent) { @@ -34,6 +35,7 @@ }); this.toString = function() { return "rgba(" + parent.red + "," + parent.green + "," + parent.blue + "," + (parent.alpha / 255).toFixed(2) + ")"; }; this.valueOf = function() { return parent.valueOf(); }; + this.stringify = function() { return "rgba(" + parent.red + "," + parent.green + "," + parent.blue + "," + (parent.alpha / 255).toFixed(2) + ")"; }; } function HSL(parent) { @@ -196,6 +198,7 @@ }); this.toString = function() { return "hsl(" + this.hue + "," + (this.saturation * 100).toFixed(2) + "%," + (this.lightness * 100).toFixed(2) + "%)"; }; this.valueOf = function() { return parent.valueOf(); }; + this.stringify = function() { return "hsl(" + this.hue + "," + (this.saturation * 100).toFixed(2) + "%," + (this.lightness * 100).toFixed(2) + "%)"; }; } function HSLA(parent) { @@ -206,6 +209,7 @@ }); this.toString = function() { return "hsla(" + this.hue + "," + (this.saturation * 100).toFixed(2) + "%," + (this.lightness * 100).toFixed(2) + "%," + (parent.alpha / 255).toFixed(2) + ")"; }; this.valueOf = function() { return parent.valueOf(); }; + this.stringify = function() { return "hsla(" + this.hue + "," + (this.saturation * 100).toFixed(2) + "%," + (this.lightness * 100).toFixed(2) + "%," + (parent.alpha / 255).toFixed(2) + ")"; }; } function HWB(parent) { @@ -381,6 +385,13 @@ } }; this.valueOf = function() { return parent.valueOf(); }; + this.stringify = function() { + if (parent.alpha == 255) { + return "hwb(" + this.hue + "," + (this.white * 100).toFixed(2) + "%," + (this.black * 100).toFixed(2) + "%)"; + } else { + return "hwb(" + this.hue + "," + (this.white * 100).toFixed(2) + "%," + (this.black * 100).toFixed(2) + "% / " + (parent.alpha / 255).toFixed(2) + ")"; + } + }; } /** * @@ -390,26 +401,28 @@ * @param {number} alpha 透明度通道值 0-255 */ function Color(red, green, blue, alpha) { - red = red & 0xFF; - green = green & 0xFF; - blue = blue & 0xFF; - alpha = (typeof alpha === "undefined") ? 255 : (alpha & 0xFF); - this.rgbData = (red << 16) | (green << 8) | blue; - this.alpha = alpha; + this._red = red & 0xFF; + this._green = green & 0xFF; + this._blue = blue & 0xFF; + this._alpha = (typeof alpha === "undefined") ? 255 : (alpha & 0xFF); + Object.defineProperty(this, "rgbData", { + get: function() { return this._rgbData; }, + set: function(value) { this._rgbData = value & 0xFFFFFF; } + }); // 红色通道 Object.defineProperty(this, "red", { - get: function() { return (this.rgbData >>> 16) & 0xFF; }, - set: function(value) { this.rgbData = ((value & 0xFF) << 16) | (this.rgbData & 0x00FFFF); } + get: function() { return this._red; }, + set: function(value) { this._red = value & 0xFF; } }); // 绿色通道 Object.defineProperty(this, "green", { - get: function() { return (this.rgbData >>> 8) & 0xFF; }, - set: function(value) { this.rgbData = (this.rgbData & 0xFF00FF) | ((value & 0xFF) << 8); } + get: function() { return this._green; }, + set: function(value) { this._green = value & 0xFF; } }); // 蓝色通道 Object.defineProperty(this, "blue", { - get: function() { return this.rgbData & 0xFF; }, - set: function(value) { this.rgbData = (this.rgbData & 0xFFFF00) | (value & 0xFF); } + get: function() { return this._blue; }, + set: function(value) { this._blue = value & 0xFF; } }); // Alpha 通道单独存储 Object.defineProperty(this, "alpha", { @@ -458,6 +471,16 @@ this.HSL = new HSL(this); this.HSLA = new HSLA(this); this.HWB = new HWB(this); + this.stringify = function() { return this.hex; }; + } + /** + * 解析颜色字符串 + * @param {string} str 颜色字符串 + * @returns {Color} 解析得到的颜色对象 + */ + Color.parse = function(str) { + var json = JSON.parse(window.external.IEFrame.ParseHtmlColor(str)); + return new Color(json.r, json.g, json.b, json.a); } module.exports = { Color: Color }; })(this); \ No newline at end of file diff --git a/shared/html/js/event.js b/shared/html/js/event.js index 033998e..2effc83 100644 --- a/shared/html/js/event.js +++ b/shared/html/js/event.js @@ -171,13 +171,35 @@ } return { + /** + * 监听元素变化,并触发回调函数。 + * @param {Element} el 目标元素 + * @param {string} type 事件类型,如 "resize", "position", "attribute", "child" + * @param {function} callback 回调函数,参数为事件对象 + */ observe: observe, + /** + * 取消监听元素变化。 + * @param {Element} el 目标元素 + * @param {string} type 事件类型,如 "resize", "position", "attribute", "child" + * @param {function} [callback] 回调函数,如果指定,则只移除指定的回调函数,否则移除所有回调函数。 + */ detach: detach, + /** + * 清除所有监听。 + */ clearAll: clearAll, + /** + * 事件类型枚举。 + */ EventType: { + /** 元素尺寸变化 */ resize: "resize", + /** 元素位置变化 */ position: "position", + /** 元素属性变化 */ attribute: "attribute", + /** 子元素变化 */ child: "child" } }; diff --git a/shared/html/js/pages.js b/shared/html/js/pages.js index 0c5711b..f5434f6 100644 --- a/shared/html/js/pages.js +++ b/shared/html/js/pages.js @@ -25,12 +25,20 @@ var splashBackColor = ""; + var timer = { + title: null, + text: null, + logo: null, + progress: null, + controls: null, + }; + function setPage(swPageLabel, bIsMulti) { var page = getPage(); swPageLabel = ("" + (swPageLabel || "")); for (var i = 0; i < supportPageList.length; i++) { if (Bridge.NString.equals(swPageLabel, supportPageList[i])) { - page.classList.add(supportPageList[i]); + if (!page.classList.contains(supportPageList[i])) page.classList.add(supportPageList[i]); } else { if (page.classList.contains(supportPageList[i])) page.classList.remove(supportPageList[i]); } @@ -49,6 +57,125 @@ break; } } + (function() { + if (Bridge.NString.equals(swPageLabel, "loading")) { + var content = page.querySelector(".content.loading"); + if (content) content.style.visibility = "hidden"; + setTimeout(function(node) { + if (node) { + node.style.visibility = "visible"; + var animation = Windows.UI.Animation; + animation.runAsync(node, animation.Keyframes.Flyout.toLeft, 500); + } + }, 0, content); + var loading = content.querySelector(".ring-loading"); + Windows.UI.Animation.loading(loading, true); + } else { + var content = page.querySelector(".content.loading"); + if (content) { + var loading = content.querySelector(".ring-loading"); + Windows.UI.Animation.loading(loading, false); + } + } + })(); + (function() { + function push_nonull(arr, item) { + if (item) arr.push(item); + } + var timerkeys = Object.keys(timer); + for (var i = 0; i < timerkeys.length; i++) { + if (timer[timerkeys[i]]) { + clearTimeout(timer[timerkeys[i]]); + timer[timerkeys[i]] = null; + } + } + var content = page.querySelector(".content." + Bridge.String.trim(swPageLabel)); + var controls = page.querySelector(".controls." + Bridge.String.trim(swPageLabel)); + var progress = page.querySelector(".progress"); + var reason = page.querySelector(".reason"); + var titlepart = []; + var textpart = []; + var storelogo = null; + if (content) { + if (bIsMulti) push_nonull(titlepart, content.querySelector(".currentfile")); + push_nonull(titlepart, content.querySelector(".pkgtitle")); + if (bIsMulti) push_nonull(titlepart, content.querySelector(".pkgtitle.multiple")); + push_nonull(titlepart, content.querySelector(".pkgapplabel")); + push_nonull(titlepart, content.querySelector(".pkgpublisher")); + push_nonull(titlepart, content.querySelector(".pkgversion")); + push_nonull(textpart, content.querySelector(".pkgfunctions-label")); + push_nonull(textpart, content.querySelector(".functions")); + push_nonull(textpart, content.querySelector(".moreinfo")); + storelogo = content.querySelector(".storelogo"); + } + var refresh = function(nodes) { + for (var i = 0; i < nodes.titlepart.length; i++) nodes.titlepart[i].style.visibility = "hidden"; + for (var i = 0; i < nodes.textpart.length; i++) nodes.textpart[i].style.visibility = "hidden"; + if (nodes.storelogo) nodes.storelogo.style.visibility = "hidden"; + if (nodes.progress) nodes.progress.style.visibility = "hidden"; + if (nodes.controls) nodes.controls.style.visibility = "hidden"; + if (nodes.reason) nodes.reason.style.visibility = "hidden"; + var animation = Windows.UI.Animation; + timer.title = setTimeout(function(titlenodes) { + if (titlenodes) { + for (var i = 0; i < titlenodes.length; i++) { + animation.runAsync(titlenodes[i], animation.Keyframes.Flyout.toLeft, 500); + } + for (var i = 0; i < titlenodes.length; i++) titlenodes[i].style.visibility = "visible"; + } + }, 0, nodes.titlepart); + timer.text = setTimeout(function(textnodes) { + if (textnodes) { + for (var i = 0; i < textnodes.length; i++) { + animation.runAsync(textnodes[i], animation.Keyframes.Flyout.toLeft, 500); + } + for (var i = 0; i < textnodes.length; i++) textnodes[i].style.visibility = "visible"; + } + }, 50, nodes.textpart); + timer.logo = setTimeout(function(logonode) { + if (logonode) { + animation.runAsync(logonode, "scale-visible", 500); + logonode.style.visibility = "visible"; + } + }, 100, nodes.storelogo); + timer.progress = setTimeout(function(progressnode) { + if (progressnode) { + animation.runAsync(progressnode, animation.Keyframes.Flyout.toLeft, 500); + progressnode.style.visibility = "visible"; + } + }, 100, nodes.progress); + timer.controls = setTimeout(function(controlnodes) { + if (controlnodes) { + animation.runAsync(controlnodes, animation.Keyframes.Flyout.toTop, 500); + controlnodes.style.visibility = "visible"; + } + }, 100, nodes.controls); + timer.reason = setTimeout(function(reasonnode) { + if (reasonnode) { + animation.runAsync(reasonnode, animation.Keyframes.Flyout.toLeft, 500); + reasonnode.style.visibility = "visible"; + } + }, 100, nodes.reason); + }; + refresh({ + titlepart: titlepart, + textpart: textpart, + storelogo: storelogo, + progress: progress, + controls: controls, + reason: reason, + }); + })(); + (function() { + var page = document.querySelector(".page"); + var progress = page.querySelector(".progress"); + var ringLoading = progress.querySelector(".ring-loading"); + if (Bridge.NString.equals(swPageLabel, "installing")) { + Windows.UI.Animation.loading(ringLoading, true); + } else { + Windows.UI.Animation.loading(ringLoading, false); + } + })(); } function getPageLabel() { @@ -97,15 +224,48 @@ }); Object.defineProperty(ret, "content", { get: function() { - var content = page.querySelector(".content.splash"); - return content; + try { + var content = page.querySelector(".content.splash"); + return content; + } catch (e) { return null; } }, }); + Object.defineProperty(ret, "statusText", { + get: function() { + var statustext = page.querySelector(".content.splash .status-text"); + return statustext.textContent; + }, + set: function(value) { + var statustext = page.querySelector(".content.splash .status-text"); + if (!statustext) return; + statustext.textContent = value; + } + }); + ret["getImageUrl"] = function() { return ret.imagesrc; }; + ret["setImageUrl"] = function(value) { ret.imagesrc = value; }; + ret["getBackground"] = function() { return ret.background; }; + ret["setBackground"] = function(value) { ret.background = value; }; + ret["setStatusText"] = function(value) { ret.statusText = value; }; + ret["getStatusText"] = function() { return ret.statusText; }; + ret["getContent"] = function() { return ret.content; }; return ret; } + function getPreinstallPage() { + return document.querySelector(".page.preinstall"); + } + module.exports = { - Page: {} + Page: { + set: setPage, + get: function() { + if (isMultiPage()) { + return [getPageLabel(), "multiple"]; + } else { + return getPageLabel(); + } + } + } }; Object.defineProperty(Page, "current", { get: function() { return getPageLabel(); }, @@ -118,4 +278,364 @@ Object.defineProperty(Page, "splash", { get: function() { return getSplashPage(); } }); + module.exports = { + setPage: setPage, + getPage: getPage, + getPageIsMulti: isMultiPage, + setPageMultiple: setPageMultiple, + getSplashPage: getSplashPage, + getSplashPageImageUrl: function() { return getSplashPage().imagesrc; }, + setSplashPageImageUrl: function(value) { getSplashPage().imagesrc = value; }, + getSplashPageBackground: function() { return getSplashPage().background; }, + setSplashPageBackground: function(value) { getSplashPage().background = value; }, + getSplashPageStatusText: function() { return getSplashPage().statusText; }, + setSplashPageStatusText: function(value) { try { getSplashPage().statusText = value; } catch (e) {} }, + getSplashPageContent: function() { return getSplashPage().content; }, + }; + + function parseVersion(version) { + var v = (version || "0.0.0.0").split("."); + var ret = { major: 0, minor: 0, build: 0, revision: 0 }; + if (v.length >= 1) ret.major = parseInt(v[0]); + if (v.length >= 2) ret.minor = parseInt(v[1]); + if (v.length >= 3) ret.build = parseInt(v[2]); + if (v.length >= 4) ret.revision = parseInt(v[3]); + return ret; + } + + function stringifyVersion(version) { + return version.major + "." + version.minor + "." + version.build + "." + version.revision; + } + + function setFlyoutDisplayInfo(pkginfo) { + var flyout = document.getElementById("moreinfo-flyout"); + var content = document.getElementById("moreinfo-flyout-content"); + (function() { + var name = content.querySelector(".id.name"); + name.textContent = pkginfo.identity.name; + var publisher = content.querySelector(".id.publisher"); + publisher.textContent = pkginfo.identity.publisher; + var version = content.querySelector(".id.version"); + version.textContent = stringifyVersion(pkginfo.identity.realver); + var arch = content.querySelector(".id.arch"); + if (pkginfo.type === 1) { + switch (pkginfo.identity.architecture) { + case 1: + arch.textContent = "x86"; + break; + case 2: + arch.textContent = "x64"; + break; + case 4: + arch.textContent = "ARM"; + break; + case 8: + arch.textContent = "ARM64"; + break; + case 16: + arch.textContent = "Neutral"; + break; + } + } else if (pkginfo.type === 2) { + var varch = pkginfo.identity.architecture; + var strarr = []; + if (varch & 1) strarr.push("x86"); + if (varch & 2) strarr.push("x64"); + if (varch & 4) strarr.push("ARM"); + if (varch & 8) strarr.push("ARM64"); + arch.textContent = strarr.join(", "); + } + var family = content.querySelector(".id.family"); + family.textContent = pkginfo.identity.package_family_name; + var full = content.querySelector(".id.full"); + full.textContent = pkginfo.identity.package_full_name; + })(); + (function() { + var framework = content.querySelector(".prop.framework"); + framework.textContent = Bridge.Resources.byname(pkginfo.properties.framework ? "IDS_MOREINFO_PROPYES" : "IDS_MOREINFO_PROPNO"); + var respkg = content.querySelector(".prop.respkg"); + respkg.textContent = Bridge.Resources.byname(pkginfo.properties.removable ? "IDS_MOREINFO_PROPYES" : "IDS_MOREINFO_PROPNO"); + })(); + (function() { + var sys = content.querySelector(".info.sys"); + var strutils = Bridge.External.String; + sys.textContent = strutils.format(Bridge.Resources.byname("IDS_MOREINFO_INFOSYS_VALUE"), pkginfo.prerequisites.os_min_version_description, stringifyVersion(pkginfo.prerequisites.os_min_version)); + var lang = content.querySelector(".info.langs"); + lang.innerHTML = ""; + for (var i = 0; i < pkginfo.resources.languages.length; i++) { + var localeName = pkginfo.resources.languages[i]; + var li = document.createElement("li"); + li.textContent = Bridge.Locale.localeInfoEx(localeName, 2); + lang.appendChild(li); + } + })(); + } + + function noticeLoadPreinstallPage(ismul) { + setPage("preinstall", ismul); + var page = getPreinstallPage(); + if (!page) return; + var content = page.querySelector(".content.preinstall"); + if (!content) return; + var filelist = Bridge.Package.filepaths(); + var fselect = content.querySelector(".currentfile select"); + for (var i = 0; i < filelist.length; i++) { + var option = document.createElement("option"); + option.value = filelist[i]; + option.text = filelist[i]; + fselect.appendChild(option); + } + if (filelist.length > 0) { + var strutils = Bridge.External.String; + var pkgtitle = null; + if (filelist.length <= 1) { + pkgtitle = content.querySelector(".pkgtitle"); + } else { + pkgtitle = content.querySelector(".pkgtitle.multiple"); + } + var pkgpublisher = content.querySelector(".pkgpublisher"); + var pkgversion = content.querySelector(".pkgversion"); + var storelogo = content.querySelector(".storelogo"); + var storelogoimg = storelogo.querySelector("img"); + var storelogofilter = storelogo.querySelector(".filter"); + var pkginfo = Bridge.Package.pkginfo(filelist[0]); + if (filelist.length <= 1) { + if (!pkgtitle.hasAttribute("data-pkgname")) + pkgtitle.setAttribute("data-pkgname", pkginfo.properties.display_name); + if (!pkgtitle.hasAttribute("data-titlefmt")) + pkgtitle.setAttribute("data-titlefmt", Bridge.Resources.byname("IDS_PREINSTALL_TITLE")); + pkgtitle.innerHTML = strutils.formatInnerHtml(pkgtitle.getAttribute("data-titlefmt"), pkgtitle.getAttribute("data-pkgname")); + } else { + pkgtitle.innerHTML = strutils.formatInnerHtml(Bridge.Resources.byname("IDS_PREINSTALL_MPKGNAME"), pkginfo.properties.display_name); + } + pkgpublisher.innerHTML = strutils.formatInnerHtml(Bridge.Resources.byname("IDS_PUBLISHER"), pkginfo.properties.publisher_display_name); + pkgversion.innerHTML = strutils.formatInnerHtml(Bridge.Resources.byname("IDS_VERSION"), stringifyVersion(pkginfo.identity.version)); + storelogoimg.src = pkginfo.properties.logo_base64; + storelogo.setAttribute("data-logoimg", pkginfo.properties.logo); + var backcolor = ""; + if (pkginfo.applications.length > 0) { + var appinfo = pkginfo.applications[0]; + backcolor = appinfo.BackgroundColor || Bridge.UI.themeColor; + } else { backcolor = Bridge.UI.themeColor; } + storelogo.style.backgroundColor = backcolor; + storelogofilter.style.background = Color.genTileBackFilter(backcolor); + var funclist = content.querySelector(".functions ul"); + for (var j = 0; j < pkginfo.capabilities.capabilities_name.length; j++) { + var li = document.createElement("li"); + var capname = pkginfo.capabilities.capabilities_name[j]; + li.setAttribute("data-capability", capname); + li.textContent = Bridge.Package.capabilityDisplayName(capname); + if (Bridge.NString.empty(li.textContent)) li.textContent = capname; + funclist.appendChild(li); + } + for (var j = 0; j < pkginfo.capabilities.device_capabilities.length; j++) { + var capname = pkginfo.capabilities.device_capabilities[j]; + var cdname = Bridge.Package.capabilityDisplayName(capname); + if (!Bridge.NString.empty(cdname)) { + var li = document.createElement("li"); + li.setAttribute("data-capability", capname); + li.textContent = Bridge.Package.capabilityDisplayName(capname); + funclist.appendChild(li); + } + } + setFlyoutDisplayInfo(pkginfo); + } + } + + function setPreinstallPagePkgTitleFormatSingle(fmt) { + var page = document.querySelector(".page"); + if (!page) return; + var content = page.querySelector(".content.preinstall"); + if (!content) return; + var pkgtitle = content.querySelector("h1.pkgtitle"); + pkgtitle.setAttribute("data-titlefmt", fmt); + } + + function setControlButtonState(serial, title, display, ban) { + var page = document.querySelector(".page"); + if (!page) return; + var controls = page.querySelector(".controls"); + if (!controls) return; + var commands = controls.querySelectorAll(".command button"); + try { + if (title !== void 0) commands[serial - 1].textContent = title; + if (display !== void 0) commands[serial - 1].style.display = display ? "" : "none"; + if (ban !== void 0) commands[serial - 1].disabled = ban; + } catch (e) {} + } + + function setLaunchWhenReady(selected, ban) { + var page = document.querySelector(".page"); + if (!page) return; + var controls = page.querySelector(".controls"); + if (!controls) return; + var checkbox = controls.querySelector(".checkbox input"); + if (!checkbox) return; + if (selected !== void 0) checkbox.checked = selected; + if (ban !== void 0) checkbox.disabled = ban; + } + + function getLaunchWhenReady() { + var page = document.querySelector(".page"); + if (!page) return false; + var controls = page.querySelector(".controls"); + if (!controls) return false; + var checkbox = controls.querySelector(".checkbox input"); + if (!checkbox) return false; + return checkbox.checked == true; + } + + function noticeLoadSelectPage() { + setPage("select", false); + setPreinstallPagePkgTitleFormatSingle(Bridge.Resources.byname("IDS_SELECT_TITLE")) + setControlButtonState(1, Bridge.Resources.byname("IDS_SELECT_OPENFILE"), true, false); + setControlButtonState(2, Bridge.Resources.byname("IDS_PREINSTALL_CANCEL"), true, false); + } + + function setInstallingPackageInfoMultiple(filepath) { + var page = document.querySelector(".page"); + if (!page) return; + var content = page.querySelector(".content.installing"); + if (!content) return; + var progress = page.querySelector(".progress"); + if (!progress) return; + var pkgtitle = content.querySelector(".pkgtitle.multiple"); + var title = content.querySelector(".title.multiple"); + var pkgpublisher = content.querySelector(".pkgpublisher"); + var pkgversion = content.querySelector(".pkgversion"); + var storelogo = content.querySelector(".storelogo"); + var storelogoimg = storelogo.querySelector("img"); + var storelogofilter = storelogo.querySelector(".filter"); + var pkginfo = Bridge.Package.pkginfo(filepath); + pkgtitle.innerHTML = Bridge.String.formatInnerHtml(Bridge.Resources.byname("IDS_PREINSTALL_MPKGNAME"), pkginfo.properties.display_name); + pkgpublisher.innerHTML = Bridge.String.formatInnerHtml(Bridge.Resources.byname("IDS_PUBLISHER"), pkginfo.properties.publisher_display_name); + pkgversion.innerHTML = Bridge.String.formatInnerHtml(Bridge.Resources.byname("IDS_VERSION"), stringifyVersion(pkginfo.identity.version)); + storelogoimg.src = pkginfo.properties.logo_base64; + storelogo.setAttribute("data-logoimg", pkginfo.properties.logo); + var backcolor = ""; + if (pkginfo.applications.length > 0) { + var appinfo = pkginfo.applications[0]; + backcolor = appinfo.BackgroundColor || Bridge.UI.themeColor; + } else { backcolor = Bridge.UI.themeColor; } + storelogo.style.backgroundColor = backcolor; + storelogofilter.style.background = Color.genTileBackFilter(backcolor); + } + + function noticeLoadInstallingPage(ismul) { + setPage("installing", ismul); + var page = document.querySelector(".page"); + if (!page) return; + var content = page.querySelector(".content.installing"); + if (!content) return; + var progress = page.querySelector(".progress"); + if (!progress) return; + var pkgtitle = null; + if (!ismul) { + pkgtitle = content.querySelector(".pkgtitle"); + pkgtitle.setAttribute("data-titlefmt", Bridge.Resources.byname("IDS_INSTALLING_TITLE")); + } + var title = null; + if (ismul) { + title = content.querySelector(".title.multiple"); + title.textContent = Bridge.Resources.byname("IDS_INSTALLING_MTITLE"); + } else title = content.querySelector(".title"); + } + // 0 - 100, float + function setInstallingProgress(percent) { + var page = document.querySelector(".page"); + if (!page) return; + var progress = page.querySelector(".progress"); + if (!progress) return; + var bar = progress.querySelector("progress"); + if (typeof bar.max !== "number") bar.max = 100; + if (typeof bar.min !== "number") bar.min = 0; + bar.value = bar.min + (bar.max - bar.min) * (percent * 0.01); + if (bar.value > bar.max) bar.value = bar.max; + if (bar.value < bar.min) bar.value = bar.min; + } + + function setInstallingStatus(status) { + var page = document.querySelector(".page"); + if (!page) return; + var progress = page.querySelector(".progress"); + if (!progress) return; + var statusbar = progress.querySelector(".status"); + if (!statusbar) return; + statusbar.textContent = status; + } + + function noticeLoadInstallSuccessPage(ismul) { + setPage("installsuccess", ismul); + var page = document.querySelector(".page"); + var files = Bridge.Package.filepaths(); + var pkginfo = Bridge.Package.pkginfo(files[0]); + if (ismul) { + var content = page.querySelector(".content.installsuccess"); + if (!content) return; + var title = content.querySelector(".currentfile .title.multiple"); + title.textContent = Bridge.Resources.byname("IDS_SUCCESS_MTITLE"); + var hasApp = false; + for (var i = 0; i < files.length; i++) { + var pi = Bridge.Package.pkginfo(files[i]); + if (pi.applications && pi.applications.length > 0) { + hasApp = true; + break; + } + } + setControlButtonState(1, Bridge.Resources.byname(hasApp ? "IDS_SUCCESS_LAUNCH" : "IDS_COMMAND_CANCEL"), true, false); + } else { + setPreinstallPagePkgTitleFormatSingle(Bridge.Resources.byname("IDS_SUCCESS_TITLE")); + setControlButtonState(1, Bridge.Resources.byname(pkginfo.applications && pkginfo.applications.length > 0 ? "IDS_SUCCESS_LAUNCH" : "IDS_COMMAND_CANCEL"), true, false); + } + } + + function noticeLoadInstallFailedPage(ismul) { + setPage("installfailed", ismul); + var page = document.querySelector(".page"); + if (!page) return; + var content = page.querySelector(".content.installfailed"); + if (!content) return; + var files = Bridge.Package.filepaths(); + setControlButtonState(1, Bridge.Resources.byname("IDS_COMMAND_CANCEL"), true, false); + var title = null; + var reason = page.querySelector(".reason textarea"); + if (ismul) { + title = content.querySelector(".currentfile .title.multiple"); + title.textContent = Bridge.Resources.byname("IDS_FAILED_MTITLE"); + var select = content.querySelector(".currentfile select"); + select.value = ""; + select.value = files[0]; + try { + if (document.createEvent) { + var event = document.createEvent('HTMLEvents'); + event.initEvent('change', true, false); // bubbles, cancelable + select.dispatchEvent(event); + } else if (select.fireEvent) { // IE <= 8 + select.fireEvent('onchange'); + } + } catch (e) {} + } else { + title = content.querySelector(".title"); + setPreinstallPagePkgTitleFormatSingle(Bridge.Resources.byname("IDS_FAILED_STITLE")); + var hres = Bridge.Package.installResult(files[0]); + reason.textContent = hres.message; + } + } + module.exports = { + noticeLoadPreinstallPage: noticeLoadPreinstallPage, + parseVersion: parseVersion, + stringifyVersion: stringifyVersion, + setFlyoutDisplayInfo: setFlyoutDisplayInfo, + setPreinstallPagePkgTitleFormatSingle: setPreinstallPagePkgTitleFormatSingle, + setControlButtonState: setControlButtonState, + setLaunchWhenReady: setLaunchWhenReady, + getLaunchWhenReady: getLaunchWhenReady, + noticeLoadSelectPage: noticeLoadSelectPage, + setInstallingPackageInfoMultiple: setInstallingPackageInfoMultiple, + noticeLoadInstallingPage: noticeLoadInstallingPage, + setInstallingProgress: setInstallingProgress, + setInstallingStatus: setInstallingStatus, + noticeLoadInstallSuccessPage: noticeLoadInstallSuccessPage, + noticeLoadInstallFailedPage: noticeLoadInstallFailedPage + }; })(this); \ No newline at end of file diff --git a/shared/html/js/tileback.js b/shared/html/js/tileback.js new file mode 100644 index 0000000..ae26cd0 --- /dev/null +++ b/shared/html/js/tileback.js @@ -0,0 +1,33 @@ +(function() { + "use strict"; + + function calcColorComponent(x) { + var y; + if (x <= 127.5) { + y = 0.999 * x - 5.4361 + x; + } else { + y = -0.999 * x + 249.32 + x; + } + return (y < 0 ? 0 : y) % 256; // 确保y不小于0 + } + + function roundToNearestInt(num) { + return Math.round(num); + } + + function genTileBackFilter(backcolor) { + var basecolor = Color.parse(backcolor); + var rightcolor = new Color( + roundToNearestInt(calcColorComponent(basecolor.red)), + roundToNearestInt(calcColorComponent(basecolor.green)), + roundToNearestInt(calcColorComponent(basecolor.blue)), + 0.25 + ); + return "linear-gradient(to right, rgba(0,0,0,0), " + rightcolor.RGBA.stringify() + ")"; + } + module.exports = { + Color: { + genTileBackFilter: genTileBackFilter + } + }; +})(); \ No newline at end of file diff --git a/shared/locale/capabilities.xml b/shared/locale/capabilities.xml new file mode 100644 index 0000000..820c78b --- /dev/null +++ b/shared/locale/capabilities.xml @@ -0,0 +1,412 @@ + + + + 作为附件应用注册,并选择加入特定应用的通知 + + + 检测设备的当前动向 + + + 发现支持 AllJoyn 的应用和设备并与其交互 + + + 以管理员身份运行 + + + 收集有关其他应用的诊断信息 + + + 访问存储在设备上的本地数据 + + + 访问本地程序包内容 + + + 应用许可 + + + 使用日历中的约会 + + + 读取并修改日历上的所有约会 + + + 系统级别约会访问 + + + 获取经过身份验证的资源。 + + + + 读取已由“垃圾邮件筛选”应用阻止的短信和彩信 + + + 与已配对的蓝牙设备通信 + + + 蓝牙智能设备 + + + 蓝牙设备 + + + 文件系统 + + + 呼叫历史记录 + + + 系统级别呼叫历史记录访问 + + + 能够控制 Windows 设备 + + + 访问 Windows 设备标识数据 + + + 利用短信和富通信 + + + 阅读并删除文本消息 + + + 阅读并编写所有短信和彩信 + + + 动态生成代码 + + + 关闭自身及其窗口,并延迟关闭它们的应用 + + + 使用联系人 + + + 读取联系人信息 + + + + 系统级别联系人访问 + + + 适用于附件的语音识别 + + + 安装其他软件 + + + 设置和配置移动运营商开放移动联盟 - 设备管理 (MO OMA-DM) 帐户 + + + 添加并管理电子邮件帐户 + + + 移动设备管理配置 + + + 配置无线应用程序协议 (WAP) + + + 对设备上的移动设备管理 (MDM) 云解决方案提供商 (CSP) 基础设施具有基本的访问权限 + + + 解锁适用于开发人员和企业方案的设备 + + + 使用文档库 + + + 在具有多张 SIM 卡的设备上创建另一个应用列表条目 + + + 读取、分类和发送电子邮件 + + + 读取、分类和发送限制或敏感的电子邮件。 + + + 使用企业域凭据 + + + 为你的设备定义特定于企业的策略 + + + 使用设备锁定 API 并访问企业共享的存储文件夹 + + + + 当应用不在前台时播放音频 + + + 开始重要的扩展执行会话 + + + 开始不受限制的扩展执行会话 + + + 安装外部依赖项 + + + 在首次登录到设备时访问设置 + + + 游戏列表 + + + 使用支持人机接口设备 (HID) 协议的设备 + + + 了解详细信息 + + + 当应用程序在前台(处于焦点位置和活动状态)时,观察并截获各种形式的原始输入 + + + 授予应用权限以将各种形式的输入注入 OneCore 系统 + + + 注入输入并以编程方式推动用户体验 + + + 观察正在由系统接收的原始输入 + + + 取消正在由系统接收的原始输入 + + + 访问 Internet 连接 + + + 访问 Internet 连接并充当服务器。 + + + 驱动程序访问 + + + 在使用最大权限运行的计算机上安装服务 + + + 使用位置 + + + 访问设备的位置历史记录 + + + 定位系统 + + + 访问锁屏界面的创造性设置 + + + IoT 低级别总线硬件 + + + 使用麦克风 + + + 允许用户修改应用 + + + 使用音乐库 + + + 定义将设备与 WWAN 和 WLAN 接口相连接的策略 + + + 在设备上搜集有关流量套餐的信息并读取网络使用情况 + + + 访问 VPN 功能 + + + 以编程方式访问 3D 对象 + + + OEM 和 MO 合作伙伴应用 + + + OEM 和 MO 合作伙伴应用 + + + 访问光盘驱动器上的功能 + + + + 在计算机上安装服务 + + + 直接管理其他应用 + + + 控制与安装在设备上的应用相关的系统策略 + + + 搜集有关其他应用的信息 + + + 将文件写入应用的安装文件夹 + + + 访问设备上所有的电话线 + + + 读取呼叫历史记录并删除历史记录中的条目 + + + 电话呼叫公共历史记录 + + + 完全修改呼叫历史记录 + + + 使用图片库 + + + 使用条形码扫描仪和磁卡读卡器 + + + Microsoft Store 预览版功能 + + + 预览 Windows UI 构成 API 以接收反馈 + + + 访问家庭或工作网络 + + + 使用支持近场通信 (NFC) 服务的设备 + + + 访问电话录音 + + + + 访问可用于解锁远程电脑的凭据 + + + 使用存储在外部存储设备上的数据 + + + 使用全部系统资源 + + + 在其他设备上投射屏幕 + + + 使用设备上可用的软件和硬件证书 + + + 发送短信和彩信 + + + 查看你当前和过去的环境 + + + IoT 系统管理 + + + 访问控制试验体验的内部 API + + + 与你的计算机上的每个应用程序交互 + + + 写入在卸载时不会清除的注册表项和文件 + + + 访问 USB 连接的设备 + + + 访问帐户的用户名和头像 + + + 直接访问存储在设备上的帐户 + + + 用户数据帐户提供程序 + + + 对你的数据具有不受限制的访问权限 + + + + 检索用户主体名称 (UPN),无需许可提示 + + + 在设备上使用帐户登录到应用 + + + 使用视频库 + + + 访问应用的磁贴数据 + + + 对可视语音信箱具有完全访问权限 + + + 使用设备的 IP 语音 (VoIP) 服务 + + + 对存储的“电子钱包”应用卡具有完全访问权限 + + + 使用网络摄像头 + + + 扫描并连接到 WLAN 网络 + + + Xbox 附件 + + + + 在后台播放媒体 + + + 允许应用程序在进入后台后继续执行一段时间的操作 + + + 允许使用图形捕获 + + + 允许无边框图形捕获 + + + 进程内媒体扩展 + + + 允许应用程序以编程方式将各种形式的输入注入系统,例如 HID、触摸、笔、键盘或鼠标。 + + + 允许应用程序访问离线地图。 + + + 允许应用访问设备上的所有电话线 + + + 允许应用程序访问与用户的 Microsoft 帐户关联的设备列表 + + + 查询软件许可政策 + + + 管理应用安装 + + + 可访问电子邮件、联系人、日历等的用户数据帐户 + + + 允许应用程序访问任务设置的当前状态 + + + 可访问系统任务项 + + + 允许应用程序访问通知设置的当前状态 + + + Web 平台媒体扩展 + +