From f9f4db3f6c2094f3702f64a3173c19e359d4c330 Mon Sep 17 00:00:00 2001 From: Bruce Date: Thu, 2 Apr 2026 11:33:57 +0800 Subject: [PATCH] Update Reader. --- AppxPackage/AppxPackage.csproj | 5 + AppxPackage/PackageReader.cs | 1382 ++++++++++++++++- AppxPackage/PkgReadNative.cs | 158 ++ AppxPackage/Utils.cs | 67 + AppxPackage/packages.config | 1 + DataUtils/Storage.cs | 104 +- Reader/ReaderShell.cs | 2 +- pkgread/pkgread.cpp | 118 ++ pkgread/pkgread.h | 10 + priformatcli/priformatcli.cpp | 4 + reslib/reslib.rc | Bin 34264 -> 34448 bytes reslib/resource.h | Bin 13284 -> 13374 bytes shared/VisualElementsManifest.xml | 12 + shared/html/install.html | 2 + shared/html/js/polyfill-ie.js | 314 ++++ shared/html/libs/contentdlg/contentdlg.css | 110 -- shared/html/libs/msgbox/contentdlg.css | 117 ++ .../libs/{contentdlg => msgbox}/contentdlg.js | 30 +- shared/html/libs/msgbox/msgbox.css | 95 -- shared/html/libs/msgbox/msgbox.elder.css | 95 ++ shared/html/libs/msgbox/msgbox.elder.js | 532 +++++++ shared/html/libs/msgbox/msgbox.js | 660 ++++---- shared/html/manager.html | 2 + shared/html/reader.html | 292 +++- shared/html/reader/page.css | 6 +- shared/html/report.html | 432 ++++++ shared/html/settings.html | 2 + shared/html/settings/appinstaller.html | 2 + shared/html/settings/appinstaller/about.html | 2 + .../html/settings/appinstaller/cssedit.html | 4 + .../html/settings/appinstaller/general.html | 2 + shared/html/settings/appinstaller/guide.html | 2 + shared/html/settings/appinstaller/theme.html | 2 + shared/html/settings/manager.html | 2 + shared/html/settings/manager/general.html | 2 + shared/html/settings/manager/guide.html | 2 + shared/html/settings/settings.html | 2 + shared/html/settings/settings/general.html | 2 + shared/html/settings/settings/guide.html | 2 + shared/html/settings/update.html | 2 + shared/locale/resources.xml | 4 + 41 files changed, 3921 insertions(+), 663 deletions(-) create mode 100644 AppxPackage/Utils.cs delete mode 100644 shared/html/libs/contentdlg/contentdlg.css create mode 100644 shared/html/libs/msgbox/contentdlg.css rename shared/html/libs/{contentdlg => msgbox}/contentdlg.js (92%) create mode 100644 shared/html/libs/msgbox/msgbox.elder.css create mode 100644 shared/html/libs/msgbox/msgbox.elder.js create mode 100644 shared/html/report.html diff --git a/AppxPackage/AppxPackage.csproj b/AppxPackage/AppxPackage.csproj index f1694e0..3941460 100644 --- a/AppxPackage/AppxPackage.csproj +++ b/AppxPackage/AppxPackage.csproj @@ -48,6 +48,10 @@ MinimumRecommendedRules.ruleset + + ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll + True + ..\packages\Newtonsoft.Json.13.0.4\lib\net40\Newtonsoft.Json.dll True @@ -70,6 +74,7 @@ + diff --git a/AppxPackage/PackageReader.cs b/AppxPackage/PackageReader.cs index f6bb9c3..a06c2f5 100644 --- a/AppxPackage/PackageReader.cs +++ b/AppxPackage/PackageReader.cs @@ -5,8 +5,14 @@ using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading; +using System.Dynamic; using AppxPackage.Info; using NativeWrappers; +using System.Threading.Tasks; +using ICSharpCode.SharpZipLib; +using System.IO; +using System.Xml; +using ICSharpCode.SharpZipLib.Zip; //using PriFormat; namespace AppxPackage { @@ -88,6 +94,305 @@ namespace AppxPackage return ret; } } + internal class PriAllValuesReader: IDisposable + { + public PackageReader pr = null; + private Dictionary pkgAppDict = new Dictionary (); + private Dictionary pkgLocDict = new Dictionary (); + private Dictionary pkgScaDict = new Dictionary (); + private Dictionary priAppPkg = new Dictionary (); + private Dictionary priLocPkg = new Dictionary (); + private Dictionary priScaPkg = new Dictionary (); + public PriAllValuesReader (PackageReader p_pr) + { + pr = p_pr; + } + public void Init () + { + var hPkg = pr.Instance; + var pkgType = pr.Type; + if (pkgType == PackageType.Appx) + { + var priinst = PackageReadHelper.GetAppxFileFromAppxPackage (hPkg, "resources.pri"); + pkgAppDict [IntPtr.Zero] = priinst; + priAppPkg [priinst] = (new PriReader (priinst)); + } + else if (pkgType == PackageType.Bundle) + { + var appPkg = PackageReadHelper.GetAppxBundleApplicationPackageFile (hPkg); + var appPkgPri = PackageReadHelper.GetFileFromPayloadPackage (appPkg, "resources.pri"); + pkgAppDict [appPkg] = appPkgPri; + priAppPkg [appPkgPri] = new PriReader (appPkgPri); + var localeResPkgList = PackageReadHelper.GetAppxBundleAllLocaleResourcePackageFileNameList (hPkg); + foreach (var filename in localeResPkgList) + { + var localePkg = PackageReadHelper.GetAppxBundlePayloadPackageFile (hPkg, filename); + var localePkgPri = PackageReadHelper.GetFileFromPayloadPackage (localePkg, "resources.pri"); + pkgLocDict [localePkg] = localePkgPri; + priLocPkg [localePkg] = (new PriReader (localePkgPri)); + } + var fileResPkgList = PackageReadHelper.GetAppxBundleAllFileResourcePackageFileNameList (hPkg); + foreach (var filename in fileResPkgList) + { + var filePkg = PackageReadHelper.GetAppxBundlePayloadPackageFile (hPkg, filename); + var filePkgPri = PackageReadHelper.GetFileFromPayloadPackage (filePkg, "resources.pri"); + pkgScaDict [filePkg] = filePkgPri; + priScaPkg [filePkgPri] = (new PriReader (filePkgPri)); + } + } + } + public void Dispose () + { + if (pr == null) return; + foreach (var i in priAppPkg) if (i.Value != null) i.Value.Dispose (); + foreach (var i in priLocPkg) if (i.Value != null) i.Value.Dispose (); + foreach (var i in priScaPkg) if (i.Value != null) i.Value.Dispose (); + priAppPkg.Clear (); + priLocPkg.Clear (); + priScaPkg.Clear (); + priAppPkg = null; + priLocPkg = null; + priScaPkg = null; + foreach (var kv in pkgAppDict) + { + if (kv.Value != IntPtr.Zero) PackageReadHelper.DestroyAppxFileStream (kv.Value); + if (kv.Key != IntPtr.Zero) PackageReadHelper.DestroyAppxFileStream (kv.Key); + } + foreach (var kv in pkgLocDict) + { + if (kv.Value != IntPtr.Zero) PackageReadHelper.DestroyAppxFileStream (kv.Value); + if (kv.Key != IntPtr.Zero) PackageReadHelper.DestroyAppxFileStream (kv.Key); + } + foreach (var kv in pkgScaDict) + { + if (kv.Value != IntPtr.Zero) PackageReadHelper.DestroyAppxFileStream (kv.Value); + if (kv.Key != IntPtr.Zero) PackageReadHelper.DestroyAppxFileStream (kv.Key); + } + pkgAppDict.Clear (); + pkgLocDict.Clear (); + pkgScaDict.Clear (); + pkgAppDict = null; + pkgLocDict = null; + pkgScaDict = null; + pr = null; + } + /// + /// 获取某个本地化字符串资源的所有语言资源 + /// + /// 资源 ID,一般为“ms-resource:”开头 + /// 返回以区域代码为键,本地化字符串为值的字典 + public Dictionary LocaleResourceAllValues (string resid) + { + var dict = new Dictionary (StringComparer.OrdinalIgnoreCase); + foreach (var pri in priAppPkg) + { + foreach (var kv in pri.Value.LocaleResourceAllValue (resid)) + { + dict [kv.Key] = kv.Value; + } + } + foreach (var pri in priLocPkg) + { + foreach (var kv in pri.Value.LocaleResourceAllValue (resid)) + { + dict [kv.Key] = kv.Value; + } + } + return dict; + } + /// + /// 获取某个涉及缩放资源的文件名及其文件的 Base64。 + /// + /// 资源 ID,一般为文件名,如“Assert\LargeTile.png” + /// 返回以缩放比和高对比度为键,一个前者为文件名,后者为 data url 组成的元组为值的字典 + public Dictionary> FileResourceAllValues (string resid) + { + var dict = new Dictionary> (); + var rePkgDict = new Dictionary (); + foreach (var kv in pkgAppDict) + rePkgDict [kv.Value] = kv.Key; + foreach (var pri in priAppPkg) + { + var pkg = rePkgDict [pri.Key]; + #region appx + if (pr.Type == PackageType.Appx) + { + foreach (var kv in pri.Value.PathResourceAllValue (resid)) + { + var imgInst = PackageReadHelper.GetAppxFileFromAppxPackage (pr.Instance, kv.Value); + IntPtr b64ph; + var b64p = PackageReadHelper.StreamToBase64W (imgInst, null, 0, out b64ph); + var imgB64 = ""; + if (b64p != IntPtr.Zero) imgB64 = Marshal.PtrToStringUni (b64p); + if (b64p != IntPtr.Zero) PackageReadHelper.PackageReaderFreeString (b64p); + dict [kv.Key] = new Tuple (kv.Value, imgB64); + } + } + #endregion + #region bundle + else if (pr.Type == PackageType.Bundle) + { + foreach (var kv in pri.Value.PathResourceAllValue (resid)) + { + var imgInst = PackageReadHelper.GetFileFromPayloadPackage (pkg, kv.Value); + IntPtr b64ph; + var b64p = PackageReadHelper.StreamToBase64W (imgInst, null, 0, out b64ph); + var imgB64 = ""; + if (b64p != IntPtr.Zero) imgB64 = Marshal.PtrToStringUni (b64p); + if (b64p != IntPtr.Zero) PackageReadHelper.PackageReaderFreeString (b64p); + dict [kv.Key] = new Tuple (kv.Value, imgB64); + } + } + #endregion + } + rePkgDict.Clear (); + foreach (var kv in pkgScaDict) rePkgDict [kv.Value] = kv.Key; + foreach (var pri in priScaPkg) + { + var pkg = rePkgDict [pri.Key]; + foreach (var kv in pri.Value.PathResourceAllValue (resid)) + { + var imgInst = PackageReadHelper.GetFileFromPayloadPackage (pkg, kv.Value); + IntPtr b64ph; + var b64p = PackageReadHelper.StreamToBase64W (imgInst, null, 0, out b64ph); + var imgB64 = ""; + if (b64p != IntPtr.Zero) imgB64 = Marshal.PtrToStringUni (b64p); + if (b64p != IntPtr.Zero) PackageReadHelper.PackageReaderFreeString (b64p); + dict [kv.Key] = new Tuple (kv.Value, imgB64); + } + } + return dict; + } + private static byte [] Base64ToBytes (string base64) + { + int commaIndex = base64.IndexOf (','); + if (commaIndex >= 0) + { + base64 = base64.Substring (commaIndex + 1); + } + try + { + return Convert.FromBase64String (base64); + } + catch + { + return new byte [0]; + } + } + internal class TrimIgnoreCaseComparer: IEqualityComparer + { + public bool Equals (string x, string y) + { + if (x == null && y == null) return true; + if (x == null || y == null) return false; + return string.Equals (x.Trim (), y.Trim (), StringComparison.OrdinalIgnoreCase); + } + public int GetHashCode (string obj) + { + if (obj == null) return 0; + return obj.Trim ().ToLowerInvariant ().GetHashCode (); + } + } + private HashSet set = new HashSet (new TrimIgnoreCaseComparer ()); + public Dictionary FileResourceAllValues (string resid, ZipOutputStream zos) + { + var comparer = new TrimIgnoreCaseComparer (); + var dict = new Dictionary (); + var rePkgDict = new Dictionary (); + foreach (var kv in pkgAppDict) + rePkgDict [kv.Value] = kv.Key; + foreach (var pri in priAppPkg) + { + var pkg = rePkgDict [pri.Key]; + #region appx + if (pr.Type == PackageType.Appx) + { + foreach (var kv in pri.Value.PathResourceAllValue (resid)) + { + dict [kv.Key] = kv.Value; + if (set.Contains (kv.Value, comparer)) continue; + else set.Add (kv.Value); + var imgInst = PackageReadHelper.GetAppxFileFromAppxPackage (pr.Instance, kv.Value); + IntPtr b64ph; + var b64p = PackageReadHelper.StreamToBase64W (imgInst, null, 0, out b64ph); + var imgB64 = ""; + if (b64p != IntPtr.Zero) imgB64 = Marshal.PtrToStringUni (b64p); + if (b64p != IntPtr.Zero) PackageReadHelper.PackageReaderFreeString (b64p); + if (zos != null) + { + var entryPath = kv.Value.Replace ('\\', '/'); + var ze = new ZipEntry (entryPath); + ze.DateTime = DateTime.Now; + zos.PutNextEntry (ze); + var bytes = Base64ToBytes (imgB64); + zos.Write (bytes, 0, bytes.Length); + zos.CloseEntry (); + } + } + } + #endregion + #region bundle + else if (pr.Type == PackageType.Bundle) + { + foreach (var kv in pri.Value.PathResourceAllValue (resid)) + { + dict [kv.Key] = kv.Value; + if (set.Contains (kv.Value, comparer)) continue; + else set.Add (kv.Value); + var imgInst = PackageReadHelper.GetFileFromPayloadPackage (pkg, kv.Value); + IntPtr b64ph; + var b64p = PackageReadHelper.StreamToBase64W (imgInst, null, 0, out b64ph); + var imgB64 = ""; + if (b64p != IntPtr.Zero) imgB64 = Marshal.PtrToStringUni (b64p); + if (b64p != IntPtr.Zero) PackageReadHelper.PackageReaderFreeString (b64p); + if (zos != null) + { + var ze = new ZipEntry (kv.Value.Replace ('\\', '/')); + ze.DateTime = DateTime.Now; + zos.PutNextEntry (ze); + var bytes = Base64ToBytes (imgB64); + zos.Write (bytes, 0, bytes.Length); + zos.CloseEntry (); + } + } + } + #endregion + } + rePkgDict.Clear (); + foreach (var kv in pkgScaDict) rePkgDict [kv.Value] = kv.Key; + foreach (var pri in priScaPkg) + { + var pkg = rePkgDict [pri.Key]; + foreach (var kv in pri.Value.PathResourceAllValue (resid)) + { + dict [kv.Key] = kv.Value; + if (set.Contains (kv.Value, comparer)) continue; + else set.Add (kv.Value); + var imgInst = PackageReadHelper.GetFileFromPayloadPackage (pkg, kv.Value); + IntPtr b64ph; + var b64p = PackageReadHelper.StreamToBase64W (imgInst, null, 0, out b64ph); + var imgB64 = ""; + if (b64p != IntPtr.Zero) imgB64 = Marshal.PtrToStringUni (b64p); + if (b64p != IntPtr.Zero) PackageReadHelper.PackageReaderFreeString (b64p); + if (zos != null) + { + var ze = new ZipEntry (kv.Value.Replace ('\\', '/')); + ze.DateTime = DateTime.Now; + zos.PutNextEntry (ze); + var bytes = Base64ToBytes (imgB64); + zos.Write (bytes, 0, bytes.Length); + zos.CloseEntry (); + } + } + } + rePkgDict.Clear (); + return dict; + } + ~PriAllValuesReader () + { + set?.Clear (); + } + } [ComVisible (true)] [ClassInterface (ClassInterfaceType.AutoDual)] public class BaseInfoSection: IDisposable, DataUtils.Utilities.IJsonBuild @@ -192,8 +497,7 @@ namespace AppxPackage } public override object BuildJSON () { - return new - { + return new { name = Name, package_full_name = FullName, package_family_name = FamilyName, @@ -340,12 +644,12 @@ namespace AppxPackage public bool ResourcePackage { get { return BoolValue ("ResourcePackage"); } } public override object BuildJSON () { - return new - { + return new { display_name = DisplayName, description = Description, publisher_display_name = Publisher, Framework = Framework, + framework = Framework, resource_package = ResourcePackage, logo = Logo, logo_base64 = LogoBase64 @@ -688,8 +992,7 @@ namespace AppxPackage { using (var apps = this) { - return apps.Select (app => - { + return apps.Select (app => { var dict = new Dictionary (StringComparer.OrdinalIgnoreCase); foreach (var kv in app) { @@ -713,7 +1016,7 @@ namespace AppxPackage [ClassInterface (ClassInterfaceType.AutoDual)] public class PRCapabilities: BaseInfoSection, ICapabilities { - public PRCapabilities (ref IntPtr hReader) : base (ref hReader) {} + public PRCapabilities (ref IntPtr hReader) : base (ref hReader) { } public List Capabilities { get @@ -791,8 +1094,7 @@ namespace AppxPackage } public override object BuildJSON () { - return new - { + return new { capabilities_name = Capabilities, device_capabilities = DeviceCapabilities, display_capabilities_name = CapabilityDisplayNames @@ -843,8 +1145,7 @@ namespace AppxPackage } public override object BuildJSON () { - return this.Select (d => new - { + return this.Select (d => new { name = d.Name, publisher = d.Publisher, vermin = d.Version.BuildJSON () @@ -855,7 +1156,7 @@ namespace AppxPackage [ClassInterface (ClassInterfaceType.AutoDual)] public class PRResources: BaseInfoSection, IResources { - public PRResources (ref IntPtr hReader) : base (ref hReader) {} + public PRResources (ref IntPtr hReader) : base (ref hReader) { } public List DXFeatures { get @@ -873,7 +1174,7 @@ namespace AppxPackage return ret; } } - public List Languages + public List Languages { get { @@ -932,8 +1233,7 @@ namespace AppxPackage } public override object BuildJSON () { - return new - { + return new { dx_feature_levels = DXFeatures.Select (e => (int)e).ToList (), languages = Languages, scales = Scales @@ -942,7 +1242,7 @@ namespace AppxPackage } public class PRPrerequisites: BaseInfoSection, IPrerequisites { - public PRPrerequisites (ref IntPtr hReader) : base (ref hReader) {} + public PRPrerequisites (ref IntPtr hReader) : base (ref hReader) { } protected DataUtils.Version GetVersion (string name) { PackageReadHelper.VERSION ver; @@ -961,8 +1261,7 @@ namespace AppxPackage public string OSMinVersionDescription { get { return GetVersionDescription ("OSMinVersion"); } } public override object BuildJSON () { - return new - { + return new { os_min_version = OSMinVersion.BuildJSON (), os_min_version_description = OSMinVersionDescription, os_max_version_tested = OSMaxVersionTested.BuildJSON (), @@ -1002,7 +1301,8 @@ namespace AppxPackage m_priStreams.Add (istream); m_priBundle.Set (3, istream); } - } break; + } + break; case PackageType.Bundle: { IntPtr hls = IntPtr.Zero, hss = IntPtr.Zero; @@ -1055,7 +1355,7 @@ namespace AppxPackage } } } - finally {} + finally { } } finally { @@ -1064,7 +1364,8 @@ namespace AppxPackage if (hss != IntPtr.Zero) PackageReadHelper.DestroyAppxFileStream (hss); IntPtr hlpri = IntPtr.Zero, hspri = IntPtr.Zero; } - } break; + } + break; } #endregion return; @@ -1152,8 +1453,7 @@ namespace AppxPackage public void BuildJsonTextAsync (object callback) { if (callback == null) return; - Thread thread = new Thread (() => - { + Thread thread = new Thread (() => { string json = string.Empty; try { @@ -1171,8 +1471,7 @@ namespace AppxPackage } private object BuildJsonObject () { - return new - { + return new { valid = IsValid, filepath = FilePath, type = (int)Type, @@ -1188,5 +1487,1038 @@ namespace AppxPackage } public static bool AddApplicationItem (string itemName) => PackageReadHelper.AddPackageApplicationItemGetName (itemName); public static bool RemoveApplicationItem (string itemName) => PackageReadHelper.RemovePackageApplicationItemGetName (itemName); + public static string [] GetApplicationItem () => PackageReadHelper.GetApplicationItemNames (); + public static void UpdateApplicationItems (IEnumerable items) => PackageReadHelper.SetApplicationItemNames (items); + public string BuildJsonForUse () + { + bool parsePri = UsePri; + bool usePri = EnablePri; + try + { + UsePri = false; + EnablePri = false; + object packageInfo = null; + #region file + var typestr = "unknown"; + switch (Type) + { + case PackageType.Appx: typestr = "appx"; break; + case PackageType.Bundle: typestr = "bundle"; break; + default: + case PackageType.Unknown: typestr = "unknown"; break; + } + var rolestr = "unknown"; + switch (Role) + { + case PackageRole.Application: rolestr = "application"; break; + case PackageRole.Framework: rolestr = "framework"; break; + case PackageRole.Resource: rolestr = "resource"; break; + default: + case PackageRole.Unknown: rolestr = "unknown"; break; + } + var pkgfile = new { + path = FilePath, + valid = IsValid, + type = typestr, + role = rolestr + }; + #endregion + #region id + var id = Identity; + var pkgid = new { + name = id.Name, + publisher = id.Publisher, + version = id.Version.ToString (), + realVersion = id.RealVersion.ToString (), + architecture = id.ProcessArchitecture.Select (e => { + switch (e) + { + case Architecture.ARM: return "arm"; + case Architecture.ARM64: return "arm64"; + case Architecture.Neutral: return "neutral"; + case Architecture.x64: return "x64"; + case Architecture.x86: return "x86"; + default: + case Architecture.Unknown: return "unknown"; + } + }).ToList (), + familyName = id.FamilyName, + fullName = id.FullName + }; + #endregion + #region prerequistes + var preq = Prerequisites; + var pkgpreq = new { + osMinVersion = preq.OSMinVersion.ToString (), + osMaxVersionTested = preq.OSMaxVersionTested.ToString (), + osMinVersionDescription = preq.OSMinVersionDescription, + osMaxVersionTestedDescription = preq.OSMaxVersionDescription + }; + #endregion + #region resources + var res = Resources; + var pkgres = new { + languages = res.Languages, + scales = res.Scales, + dxFeatureLevels = res.DXFeatures.Select (d => { + switch (d) + { + case DXFeatureLevel.Level9: return 9; + case DXFeatureLevel.Level10: return 10; + case DXFeatureLevel.Level11: return 11; + case DXFeatureLevel.Level12: return 12; + default: + case DXFeatureLevel.Unspecified: return -1; + } + }).ToList () + }; + #endregion + #region capabilities + var caps = Capabilities; + var pkgcaps = new { + capabilities = caps.Capabilities, + deviceCapabilities = caps.DeviceCapabilities + }; + #endregion + #region dependencies + var deps = Dependencies; + var pkgdeps = Dependencies.Select (d => new { + name = d.Name, + publisher = d.Publisher, + minVersion = d.Version.ToString () + }).ToList (); + #endregion + using (var priAllRes = new PriAllValuesReader (this)) + { + priAllRes.Init (); + #region prop + var prop = Properties; + var dispname = prop.DisplayName; + var dispNameDict = new Dictionary (); + if (PriFileHelper.IsMsResourcePrefix (dispname)) + dispNameDict = priAllRes.LocaleResourceAllValues (dispname); + dispNameDict ["root"] = dispname; + var desc = prop.Description; + var descDict = new Dictionary (); + if (PriFileHelper.IsMsResourcePrefix (desc)) + descDict = priAllRes.LocaleResourceAllValues (desc); + descDict ["root"] = desc; + var disppub = prop.Publisher; + var dispPubDict = new Dictionary (); + if (PriFileHelper.IsMsResourcePrefix (disppub)) + dispPubDict = priAllRes.LocaleResourceAllValues (disppub); + dispPubDict ["root"] = disppub; + var logoList = priAllRes.FileResourceAllValues (prop.Logo) + .Select (kv => { + string contrast = ""; + switch (kv.Key.Contrast) + { + case PriResourceKey.PriContrast.None: contrast = ""; break; + case PriResourceKey.PriContrast.Black: contrast = "black"; break; + case PriResourceKey.PriContrast.White: contrast = "white"; break; + case PriResourceKey.PriContrast.High: contrast = "high"; break; + case PriResourceKey.PriContrast.Low: contrast = "low"; break; + } + + if (kv.Key.IsTargetSize) + { + return new { + targetSize = kv.Key.Value, + contrast = contrast, + name = kv.Value.Item1, + base64 = kv.Value.Item2 + }; + } + else if (kv.Key.IsScale) + { + return new { + scale = kv.Key.Value, + contrast = contrast, + name = kv.Value.Item1, + base64 = kv.Value.Item2 + }; + } + else if (kv.Key.IsString) + { + return new { + language = kv.Key.Value, + name = kv.Value.Item1, + base64 = kv.Value.Item2 + }; + } + else + { + return (dynamic)null; // 不满足条件时返回 null + } + }) + .Where (item => item != null) // 过滤掉 null + .ToList (); + var pkgprop = new { + displayName = dispNameDict, + publisherDisplayName = dispPubDict, + description = descDict, + logo = logoList, + framework = prop.Framework, + resourcePackage = prop.ResourcePackage + }; + #endregion + #region apps + var apps = Applications; + var pkgapps = new List (); + foreach (var app in apps) + { + dynamic obj = new ExpandoObject (); + var dict = (IDictionary)obj; + foreach (var kv in app) + { + if (Utils.AppFileProperties.Contains (kv.Key, StringComparer.OrdinalIgnoreCase)) + { + dict [Utils.PascalToCamel (kv.Key)] = priAllRes.FileResourceAllValues (kv.Value) + .Select (skv => { + string contrast = ""; + switch (skv.Key.Contrast) + { + case PriResourceKey.PriContrast.None: contrast = ""; break; + case PriResourceKey.PriContrast.Black: contrast = "black"; break; + case PriResourceKey.PriContrast.White: contrast = "white"; break; + case PriResourceKey.PriContrast.High: contrast = "high"; break; + case PriResourceKey.PriContrast.Low: contrast = "low"; break; + } + + if (skv.Key.IsTargetSize) + { + return new { + targetSize = skv.Key.Value, + contrast = contrast, + name = skv.Value.Item1, + base64 = skv.Value.Item2 + }; + } + else if (skv.Key.IsScale) + { + return new { + scale = skv.Key.Value, + contrast = contrast, + name = skv.Value.Item1, + base64 = skv.Value.Item2 + }; + } + else if (skv.Key.IsString) + { + return new { + language = skv.Key.Value, + name = skv.Value.Item1, + base64 = skv.Value.Item2 + }; + } + else + { + return (dynamic)null; // 不满足条件时返回 null + } + }).Where (item => item != null).ToList (); + } + else + { + if (PriFileHelper.IsMsResourcePrefix (kv.Value)) + { + var itemDict = new Dictionary (); + itemDict = priAllRes.LocaleResourceAllValues (kv.Value); + itemDict ["root"] = kv.Value; + dict [Utils.PascalToCamel (kv.Key)] = itemDict; + } + else + { + dict [Utils.PascalToCamel (kv.Key)] = kv.Value; + } + } + } + pkgapps.Add (obj); + } + #endregion + packageInfo = new { + file = pkgfile, + identity = pkgid, + properties = pkgprop, + resources = pkgres, + prerequisites = pkgpreq, + applications = pkgapps, + capabilities = pkgcaps, + dependencies = pkgdeps + }; + } + return Newtonsoft.Json.JsonConvert.SerializeObject ( + packageInfo, + Newtonsoft.Json.Formatting.Indented + ); + } + finally + { + EnablePri = usePri; + UsePri = parsePri; + } + } + public void SaveJsonFile (string savefilepath, object resolve, object reject) + { + try + { + #region + using (var fs = File.Create (savefilepath)) + { + using (var zos = new ZipOutputStream (fs)) + { + zos.SetLevel (9); + bool parsePri = UsePri; + bool usePri = EnablePri; + try + { + UsePri = false; + EnablePri = false; + object packageInfo = null; + #region file + var typestr = "unknown"; + switch (Type) + { + case PackageType.Appx: typestr = "appx"; break; + case PackageType.Bundle: typestr = "bundle"; break; + default: + case PackageType.Unknown: typestr = "unknown"; break; + } + var rolestr = "unknown"; + switch (Role) + { + case PackageRole.Application: rolestr = "application"; break; + case PackageRole.Framework: rolestr = "framework"; break; + case PackageRole.Resource: rolestr = "resource"; break; + default: + case PackageRole.Unknown: rolestr = "unknown"; break; + } + var pkgfile = new { + path = FilePath, + valid = IsValid, + type = typestr, + role = rolestr + }; + #endregion + #region id + var id = Identity; + var pkgid = new { + name = id.Name, + publisher = id.Publisher, + version = id.Version.ToString (), + realVersion = id.RealVersion.ToString (), + architecture = id.ProcessArchitecture.Select (e => { + switch (e) + { + case Architecture.ARM: return "arm"; + case Architecture.ARM64: return "arm64"; + case Architecture.Neutral: return "neutral"; + case Architecture.x64: return "x64"; + case Architecture.x86: return "x86"; + default: + case Architecture.Unknown: return "unknown"; + } + }).ToList (), + familyName = id.FamilyName, + fullName = id.FullName, + resourceId = id.ResourceId + }; + #endregion + #region prerequistes + var preq = Prerequisites; + var pkgpreq = new { + osMinVersion = preq.OSMinVersion.ToString (), + osMaxVersionTested = preq.OSMaxVersionTested.ToString (), + osMinVersionDescription = preq.OSMinVersionDescription, + osMaxVersionTestedDescription = preq.OSMaxVersionDescription + }; + #endregion + #region resources + var res = Resources; + var pkgres = new { + languages = res.Languages, + scales = res.Scales, + dxFeatureLevels = res.DXFeatures.Select (d => { + switch (d) + { + case DXFeatureLevel.Level9: return 9; + case DXFeatureLevel.Level10: return 10; + case DXFeatureLevel.Level11: return 11; + case DXFeatureLevel.Level12: return 12; + default: + case DXFeatureLevel.Unspecified: return -1; + } + }).ToList () + }; + #endregion + #region capabilities + var caps = Capabilities; + var pkgcaps = new { + capabilities = caps.Capabilities, + deviceCapabilities = caps.DeviceCapabilities + }; + #endregion + #region dependencies + var deps = Dependencies; + var pkgdeps = Dependencies.Select (d => new { + name = d.Name, + publisher = d.Publisher, + minVersion = d.Version.ToString () + }).ToList (); + #endregion + using (var priAllRes = new PriAllValuesReader (this)) + { + priAllRes.Init (); + #region prop + var prop = Properties; + var dispname = prop.DisplayName; + var dispNameDict = new Dictionary (); + if (PriFileHelper.IsMsResourcePrefix (dispname)) + dispNameDict = priAllRes.LocaleResourceAllValues (dispname); + dispNameDict ["root"] = dispname; + var desc = prop.Description; + var descDict = new Dictionary (); + if (PriFileHelper.IsMsResourcePrefix (desc)) + descDict = priAllRes.LocaleResourceAllValues (desc); + descDict ["root"] = desc; + var disppub = prop.Publisher; + var dispPubDict = new Dictionary (); + if (PriFileHelper.IsMsResourcePrefix (disppub)) + dispPubDict = priAllRes.LocaleResourceAllValues (disppub); + dispPubDict ["root"] = disppub; + var logoList = priAllRes.FileResourceAllValues (prop.Logo, zos) + .Select (kv => { + string contrast = ""; + switch (kv.Key.Contrast) + { + case PriResourceKey.PriContrast.None: contrast = ""; break; + case PriResourceKey.PriContrast.Black: contrast = "black"; break; + case PriResourceKey.PriContrast.White: contrast = "white"; break; + case PriResourceKey.PriContrast.High: contrast = "high"; break; + case PriResourceKey.PriContrast.Low: contrast = "low"; break; + } + + if (kv.Key.IsTargetSize) + { + return new { + targetSize = kv.Key.Value, + contrast = contrast, + name = kv.Value + }; + } + else if (kv.Key.IsScale) + { + return new { + scale = kv.Key.Value, + contrast = contrast, + name = kv.Value + }; + } + else if (kv.Key.IsString) + { + return new { + language = kv.Key.Value, + name = kv.Value + }; + } + else + { + return (dynamic)null; // 不满足条件时返回 null + } + }) + .Where (item => item != null) // 过滤掉 null + .ToList (); + var pkgprop = new { + displayName = dispNameDict, + publisherDisplayName = dispPubDict, + description = descDict, + logo = logoList, + framework = prop.Framework, + resourcePackage = prop.ResourcePackage + }; + #endregion + #region apps + var apps = Applications; + var pkgapps = new List (); + foreach (var app in apps) + { + dynamic obj = new ExpandoObject (); + var dict = (IDictionary)obj; + foreach (var kv in app) + { + if (Utils.AppFileProperties.Contains (kv.Key, StringComparer.OrdinalIgnoreCase)) + { + dict [Utils.PascalToCamel (kv.Key)] = priAllRes.FileResourceAllValues (kv.Value, zos) + .Select (skv => { + string contrast = ""; + switch (skv.Key.Contrast) + { + case PriResourceKey.PriContrast.None: contrast = ""; break; + case PriResourceKey.PriContrast.Black: contrast = "black"; break; + case PriResourceKey.PriContrast.White: contrast = "white"; break; + case PriResourceKey.PriContrast.High: contrast = "high"; break; + case PriResourceKey.PriContrast.Low: contrast = "low"; break; + } + + if (skv.Key.IsTargetSize) + { + return new { + targetSize = skv.Key.Value, + contrast = contrast, + name = skv.Value + }; + } + else if (skv.Key.IsScale) + { + return new { + scale = skv.Key.Value, + contrast = contrast, + name = skv.Value + }; + } + else if (skv.Key.IsString) + { + return new { + language = skv.Key.Value, + name = skv.Value + }; + } + else + { + return (dynamic)null; // 不满足条件时返回 null + } + }).Where (item => item != null).ToList (); + } + else + { + if (PriFileHelper.IsMsResourcePrefix (kv.Value)) + { + var itemDict = new Dictionary (); + itemDict = priAllRes.LocaleResourceAllValues (kv.Value); + itemDict ["root"] = kv.Value; + dict [Utils.PascalToCamel (kv.Key)] = itemDict; + } + else + { + dict [Utils.PascalToCamel (kv.Key)] = kv.Value; + } + } + } + pkgapps.Add (obj); + } + #endregion + packageInfo = new { + file = pkgfile, + identity = pkgid, + properties = pkgprop, + resources = pkgres, + prerequisites = pkgpreq, + applications = pkgapps, + capabilities = pkgcaps, + dependencies = pkgdeps + }; + } + var jsonstr = Newtonsoft.Json.JsonConvert.SerializeObject (packageInfo, Newtonsoft.Json.Formatting.None); + var ze = new ZipEntry ("info.json"); + ze.DateTime = DateTime.Now; + zos.PutNextEntry (ze); + var bytes = Encoding.UTF8.GetBytes (jsonstr); + zos.Write (bytes, 0, bytes.Length); + zos.CloseEntry (); + if (resolve != null) JSHelper.CallJS (resolve); + } + finally + { + EnablePri = usePri; + UsePri = parsePri; + } + } + } + #endregion + } + catch (Exception ex) + { + if (reject != null) JSHelper.CallJS (reject, ex); + } + } + public void SaveJsonFileAsync (string savefilepath, object resolve, object reject) + { + Thread thread = new Thread (() => { + SaveJsonFile (savefilepath, resolve, reject); + }); + thread.SetApartmentState (ApartmentState.MTA); + thread.IsBackground = true; + thread.Start (); + } + public void SaveXmlFile (string savefilepath, object resolve, object reject) + { + try + { + #region + using (var fs = File.Create (savefilepath)) + { + using (var zos = new ZipOutputStream (fs)) + { + zos.SetLevel (9); + bool parsePri = UsePri; + bool usePri = EnablePri; + try + { + UsePri = false; + EnablePri = false; + var xml = new XmlDocument (); + var decl = xml.CreateXmlDeclaration ("1.0", "utf-8", "yes"); + xml.AppendChild (decl); + var root = xml.CreateElement ("Package"); + xml.AppendChild (root); + #region file + var typestr = "unknown"; + switch (Type) + { + case PackageType.Appx: typestr = "appx"; break; + case PackageType.Bundle: typestr = "bundle"; break; + default: + case PackageType.Unknown: typestr = "unknown"; break; + } + var rolestr = "unknown"; + switch (Role) + { + case PackageRole.Application: rolestr = "application"; break; + case PackageRole.Framework: rolestr = "framework"; break; + case PackageRole.Resource: rolestr = "resource"; break; + default: + case PackageRole.Unknown: rolestr = "unknown"; break; + } + { + var nodefile = xml.CreateElement ("File"); + var nodefilepath = xml.CreateElement ("Path"); + nodefilepath.InnerText = FilePath; + var nodefilevalid = xml.CreateElement ("Valid"); + nodefilevalid.InnerText = IsValid ? "true" : "false"; + var nodefiletype = xml.CreateElement ("Type"); + nodefiletype.InnerText = typestr; + var nodefilerole = xml.CreateElement ("Role"); + nodefilerole.InnerText = rolestr; + nodefile.AppendChild (nodefilepath); + nodefile.AppendChild (nodefilevalid); + nodefile.AppendChild (nodefiletype); + nodefile.AppendChild (nodefilerole); + root.AppendChild (nodefile); + } + #endregion + #region id + var id = Identity; + { + var nodeid = xml.CreateElement ("Identity"); + var nodeidname = xml.CreateElement ("Name"); + nodeidname.InnerText = id.Name; + var nodeidpub = xml.CreateElement ("Publisher"); + nodeidpub.InnerText = id.Publisher; + var nodeidver = xml.CreateElement ("Version"); + nodeidver.InnerText = id.Version.ToString (); + var nodeidrealver = xml.CreateElement ("RealVersion"); + nodeidrealver.InnerText = id.RealVersion.ToString (); + var nodeidarchs = xml.CreateElement ("ProcessorArchitectures"); + foreach (var a in id.ProcessArchitecture) + { + var astr = ""; + switch (a) + { + case Architecture.ARM: astr = "arm"; break; + case Architecture.ARM64: astr = "arm64"; break; + case Architecture.Neutral: astr = "neutral"; break; + case Architecture.x64: astr = "x64"; break; + case Architecture.x86: astr = "x86"; break; + default: + case Architecture.Unknown: astr = "unknown"; break; + } + var nodeidarch = xml.CreateElement ("ProcessorArchitecture"); + nodeidarch.SetAttribute ("Value", astr); + nodeidarchs.AppendChild (nodeidarch); + } + var nodeidfamily = xml.CreateElement ("FamilyName"); + nodeidfamily.InnerText = id.FamilyName; + var nodeidfull = xml.CreateElement ("FullName"); + nodeidfull.InnerText = id.FullName; + var nodeidresid = xml.CreateElement ("ResourceId"); + nodeidresid.InnerText = id.ResourceId; + nodeid.AppendChild (nodeidname); + nodeid.AppendChild (nodeidpub); + nodeid.AppendChild (nodeidver); + nodeid.AppendChild (nodeidrealver); + nodeid.AppendChild (nodeidarchs); + nodeid.AppendChild (nodeidfamily); + nodeid.AppendChild (nodeidfamily); + nodeid.AppendChild (nodeidresid); + root.AppendChild (nodeid); + } + #endregion + using (var priAllRes = new PriAllValuesReader (this)) + { + priAllRes.Init (); + #region prop + var prop = Properties; + var dispname = prop.DisplayName; + var dispNameDict = new Dictionary (); + if (PriFileHelper.IsMsResourcePrefix (dispname)) + dispNameDict = priAllRes.LocaleResourceAllValues (dispname); + dispNameDict ["root"] = dispname; + var desc = prop.Description; + var descDict = new Dictionary (); + if (PriFileHelper.IsMsResourcePrefix (desc)) + descDict = priAllRes.LocaleResourceAllValues (desc); + descDict ["root"] = desc; + var disppub = prop.Publisher; + var dispPubDict = new Dictionary (); + if (PriFileHelper.IsMsResourcePrefix (disppub)) + dispPubDict = priAllRes.LocaleResourceAllValues (disppub); + dispPubDict ["root"] = disppub; + { + var nodeprop = xml.CreateElement ("Properties"); + var nodepropname = xml.CreateElement ("DisplayName"); + foreach (var kv in dispNameDict) + { + var nodelocale = xml.CreateElement ("LocaleResource"); + nodelocale.SetAttribute ("Lang", kv.Key); + nodelocale.InnerText = kv.Value; + nodepropname.AppendChild (nodelocale); + } + var nodeproppub = xml.CreateElement ("PublisherDisplayName"); + foreach (var kv in dispPubDict) + { + var nodelocale = xml.CreateElement ("LocaleResource"); + nodelocale.SetAttribute ("Lang", kv.Key); + nodelocale.InnerText = kv.Value; + nodeproppub.AppendChild (nodelocale); + } + var nodepropdesc = xml.CreateElement ("Description"); + foreach (var kv in descDict) + { + var nodelocale = xml.CreateElement ("LocaleResource"); + nodelocale.SetAttribute ("Lang", kv.Key); + nodelocale.InnerText = kv.Value; + nodepropdesc.AppendChild (nodelocale); + } + var nodeproplogo = xml.CreateElement ("Logo"); + foreach (var kv in priAllRes.FileResourceAllValues (prop.Logo, zos)) + { + #region logo + var key = kv.Key; + var value = kv.Value; + var nodefile = xml.CreateElement ("File"); + var attrName = xml.CreateAttribute ("Name"); + attrName.Value = value; + nodefile.Attributes.Append (attrName); + if (key.Contrast != PriResourceKey.PriContrast.None) + { + string contrast = ""; + switch (key.Contrast) + { + case PriResourceKey.PriContrast.Black: contrast = "black"; break; + case PriResourceKey.PriContrast.White: contrast = "white"; break; + case PriResourceKey.PriContrast.High: contrast = "high"; break; + case PriResourceKey.PriContrast.Low: contrast = "low"; break; + } + var attrContrast = xml.CreateAttribute ("Contrast"); + attrContrast.Value = contrast; + nodefile.Attributes.Append (attrContrast); + } + if (key.IsTargetSize) + { + var attr = xml.CreateAttribute ("TargetSize"); + attr.Value = key.Value.ToString (); + nodefile.Attributes.Append (attr); + } + else if (key.IsScale) + { + var attr = xml.CreateAttribute ("Scale"); + attr.Value = key.Value.ToString (); + nodefile.Attributes.Append (attr); + } + else if (key.IsString) + { + var attr = xml.CreateAttribute ("Language"); + attr.Value = key.Value.ToString (); + nodefile.Attributes.Append (attr); + } + nodeproplogo.AppendChild (nodefile); + #endregion + } + var nodepropfrw = xml.CreateElement ("Framework"); + nodepropfrw.InnerText = prop.Framework ? "true" : "false"; + var nodepropres = xml.CreateElement ("ResourcePackage"); + nodepropres.InnerText = prop.ResourcePackage ? "true" : "false"; + nodeprop.AppendChild (nodepropname); + nodeprop.AppendChild (nodeproppub); + nodeprop.AppendChild (nodepropdesc); + nodeprop.AppendChild (nodeproplogo); + nodeprop.AppendChild (nodepropfrw); + nodeprop.AppendChild (nodepropres); + root.AppendChild (nodeprop); + } + #endregion + #region apps + // Applications 节点 + XmlElement nodeApplications = xml.CreateElement ("Applications"); + + foreach (var app in Applications) + { + XmlElement nodeApp = xml.CreateElement ("Application"); + + // AppUserModelId 作为属性 + string aumidObj = app ["AppUserModelId"]; + if (aumidObj == null || aumidObj.Trim ().Length == 0) aumidObj = app ["AppUserModelID"]; + nodeApp.SetAttribute ("AppUserModelId", aumidObj); + foreach (var kv in app) + { + string key = kv.Key; + string value = kv.Value; + + // 跳过 AppUserModelId,因为已经作为属性 + if (string.Equals (key, "AppUserModelId", StringComparison.OrdinalIgnoreCase)) + continue; + + XmlElement nodeProp = xml.CreateElement (key); + + // 文件资源类型 + if (Utils.AppFileProperties.Contains (key, StringComparer.OrdinalIgnoreCase)) + { + foreach (var skv in priAllRes.FileResourceAllValues (value, zos)) + { + var fileKey = skv.Key; + var fileValue = skv.Value; + + XmlElement nodeFile = xml.CreateElement ("File"); + + // Name 必有 + XmlAttribute attrName = xml.CreateAttribute ("Name"); + attrName.Value = fileValue; + nodeFile.Attributes.Append (attrName); + + // Contrast 可选 + if (fileKey.Contrast != PriResourceKey.PriContrast.None) + { + string contrast = ""; + switch (fileKey.Contrast) + { + case PriResourceKey.PriContrast.Black: contrast = "black"; break; + case PriResourceKey.PriContrast.White: contrast = "white"; break; + case PriResourceKey.PriContrast.High: contrast = "high"; break; + case PriResourceKey.PriContrast.Low: contrast = "low"; break; + } + if (!string.IsNullOrEmpty (contrast)) + { + XmlAttribute attrContrast = xml.CreateAttribute ("Contrast"); + attrContrast.Value = contrast; + nodeFile.Attributes.Append (attrContrast); + } + } + + // TargetSize + if (fileKey.IsTargetSize) + { + XmlAttribute attrTS = xml.CreateAttribute ("TargetSize"); + attrTS.Value = fileKey.Value.ToString (); + nodeFile.Attributes.Append (attrTS); + } + // Scale + else if (fileKey.IsScale) + { + XmlAttribute attrS = xml.CreateAttribute ("Scale"); + attrS.Value = fileKey.Value.ToString (); + nodeFile.Attributes.Append (attrS); + } + // Language + else if (fileKey.IsString) + { + XmlAttribute attrL = xml.CreateAttribute ("Lang"); + attrL.Value = fileKey.Value.ToString (); + nodeFile.Attributes.Append (attrL); + } + nodeProp.AppendChild (nodeFile); + } + } + // 多语言资源 + else if (PriFileHelper.IsMsResourcePrefix (value)) + { + Dictionary localeDict = priAllRes.LocaleResourceAllValues (value); + localeDict ["root"] = value.ToString (); + + foreach (KeyValuePair lkv in localeDict) + { + XmlElement nodeLocale = xml.CreateElement ("LocaleResource"); + nodeLocale.SetAttribute ("Lang", lkv.Key); + nodeLocale.InnerText = lkv.Value; + nodeProp.AppendChild (nodeLocale); + } + } + else + { + nodeProp.InnerText = value.ToString (); + } + + nodeApp.AppendChild (nodeProp); + } + + nodeApplications.AppendChild (nodeApp); + } + root.AppendChild (nodeApplications); + #endregion + } + #region prerequistes + var preq = Prerequisites; + { + var nodepreq = xml.CreateElement ("Prerequisites"); + var nodeosmin = xml.CreateElement ("OSMinVersion"); + nodeosmin.InnerText = preq.OSMinVersion.ToString (); + nodeosmin.SetAttribute ("Description", preq.OSMinVersionDescription); + var nodeosmaxt = xml.CreateElement ("OSMaxVersionTested"); + nodeosmaxt.InnerText = preq.OSMaxVersionTested.ToString (); + nodeosmaxt.SetAttribute ("Description", preq.OSMaxVersionDescription); + nodepreq.AppendChild (nodeosmin); + nodepreq.AppendChild (nodeosmaxt); + root.AppendChild (nodepreq); + } + #endregion + #region resources + XmlElement nodeResources = xml.CreateElement ("Resources"); + var res = Resources; + if (res.Languages != null) + { + foreach (var lang in res.Languages) + { + XmlElement nodeRes = xml.CreateElement ("Resource"); + XmlAttribute attrLang = xml.CreateAttribute ("Language"); + attrLang.Value = lang; + nodeRes.Attributes.Append (attrLang); + nodeResources.AppendChild (nodeRes); + } + } + if (res.Scales != null) + { + foreach (var scale in res.Scales) + { + XmlElement nodeRes = xml.CreateElement ("Resource"); + XmlAttribute attrScale = xml.CreateAttribute ("Scale"); + attrScale.Value = scale.ToString (); + nodeRes.Attributes.Append (attrScale); + nodeResources.AppendChild (nodeRes); + } + } + if (res.DXFeatures != null) + { + foreach (var d in res.DXFeatures) + { + int level = -1; + switch (d) + { + case DXFeatureLevel.Level9: level = 9; break; + case DXFeatureLevel.Level10: level = 10; break; + case DXFeatureLevel.Level11: level = 11; break; + case DXFeatureLevel.Level12: level = 12; break; + case DXFeatureLevel.Unspecified: + default: level = -1; break; + } + XmlElement nodeRes = xml.CreateElement ("Resource"); + XmlAttribute attrDX = xml.CreateAttribute ("DXFeatureLevel"); + attrDX.Value = level.ToString (); + nodeRes.Attributes.Append (attrDX); + nodeResources.AppendChild (nodeRes); + } + } + root.AppendChild (nodeResources); + #endregion + #region capabilities + XmlElement nodeCapabilities = xml.CreateElement ("Capabilities"); + var caps = Capabilities; + if (caps.Capabilities != null) + { + foreach (var cap in caps.Capabilities) + { + XmlElement nodeCap = xml.CreateElement ("Capability"); + XmlAttribute attrName = xml.CreateAttribute ("Name"); + attrName.Value = cap; + nodeCap.Attributes.Append (attrName); + nodeCapabilities.AppendChild (nodeCap); + } + } + if (caps.DeviceCapabilities != null) + { + foreach (var devCap in caps.DeviceCapabilities) + { + XmlElement nodeDevCap = xml.CreateElement ("DeviceCapability"); + XmlAttribute attrName = xml.CreateAttribute ("Name"); + attrName.Value = devCap; + nodeDevCap.Attributes.Append (attrName); + nodeCapabilities.AppendChild (nodeDevCap); + } + } + root.AppendChild (nodeCapabilities); + #endregion + #region dependencies + XmlElement nodeDependencies = xml.CreateElement ("Dependencies"); + var deps = Dependencies; + if (deps != null) + { + foreach (var dep in deps) + { + XmlElement nodeDep = xml.CreateElement ("Dependency"); + XmlAttribute attrName = xml.CreateAttribute ("Name"); + attrName.Value = dep.Name ?? ""; + nodeDep.Attributes.Append (attrName); + XmlAttribute attrPublisher = xml.CreateAttribute ("Publisher"); + attrPublisher.Value = dep.Publisher ?? ""; + nodeDep.Attributes.Append (attrPublisher); + XmlAttribute attrMinVersion = xml.CreateAttribute ("MinVersion"); + attrMinVersion.Value = dep.Version != null ? dep.Version.ToString () : ""; + nodeDep.Attributes.Append (attrMinVersion); + nodeDependencies.AppendChild (nodeDep); + } + } + root.AppendChild (nodeDependencies); + #endregion + var ze = new ZipEntry ("info.xml"); + ze.DateTime = DateTime.Now; + zos.PutNextEntry (ze); + byte [] bytes; + using (var ms = new MemoryStream ()) + { + var settings = new XmlWriterSettings { + Encoding = Encoding.UTF8, + Indent = true, + OmitXmlDeclaration = false + }; + using (var writer = XmlWriter.Create (ms, settings)) + { + xml.Save (writer); + } + bytes = ms.ToArray (); + } + zos.Write (bytes, 0, bytes.Length); + zos.CloseEntry (); + if (resolve != null) JSHelper.CallJS (resolve); + } + finally + { + EnablePri = usePri; + UsePri = parsePri; + } + } + } + #endregion + } + catch (Exception ex) + { + if (reject != null) JSHelper.CallJS (reject, ex); + } + } + public void SaveXmlFileAsync (string savefilepath, object resolve, object reject) + { + Thread thread = new Thread (() => { + SaveXmlFile (savefilepath, resolve, reject); + }); + thread.SetApartmentState (ApartmentState.MTA); + thread.IsBackground = true; + thread.Start (); + } } } diff --git a/AppxPackage/PkgReadNative.cs b/AppxPackage/PkgReadNative.cs index c9ed8bc..151cec0 100644 --- a/AppxPackage/PkgReadNative.cs +++ b/AppxPackage/PkgReadNative.cs @@ -20,6 +20,8 @@ namespace NativeWrappers using UINT64 = System.UInt64; using HRESULT = System.Int32; using ULONG = System.UInt32; + using System.Collections.Generic; + using System.Linq; public static class PackageReadHelper { @@ -304,6 +306,7 @@ namespace NativeWrappers { } } + // ================= Manifest Reader ================= [DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)] @@ -404,5 +407,160 @@ namespace NativeWrappers [DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)] public static extern IntPtr GetManifestPrerequistieSystemVersionName (IntPtr hReader, string lpName); + // ========== Appx Bundle Resource Packages ========== + [DllImport (DllName, CallingConvention = CallConv)] + private static extern IntPtr GetAppxBundleAllResourcePackageFileNames (IntPtr hReader); + + [DllImport (DllName, CallingConvention = CallConv)] + private static extern void FreeAppxBundlePayloadsFileNameList (IntPtr hStringList); + + /// + /// 获取 Bundle 包中所有资源包的文件名列表。 + /// + /// 由 CreatePackageReader 创建的读取器句柄 + /// 资源包文件名数组,若无资源包或非 bundle 类型则返回空数组 + public static string [] GetAppxBundleAllResourcePackageFileNameList (IntPtr hReader) + { + IntPtr hList = GetAppxBundleAllResourcePackageFileNames (hReader); + if (hList == IntPtr.Zero) + return new string [0]; + + try + { + return ReadWStringList (hList); + } + finally + { + FreeAppxBundlePayloadsFileNameList (hList); + } + } + + [DllImport (DllName, CallingConvention = CallConv)] + private static extern IntPtr GetAppxBundleAllLocaleResourcePackageFileNames (IntPtr hReader); + + /// + /// 获取 Bundle 包中所有区域设置资源包的文件名列表。 + /// + /// 由 CreatePackageReader 创建的读取器句柄 + /// 区域设置资源包文件名数组,若无则返回空数组 + public static string [] GetAppxBundleAllLocaleResourcePackageFileNameList (IntPtr hReader) + { + IntPtr hList = GetAppxBundleAllLocaleResourcePackageFileNames (hReader); + if (hList == IntPtr.Zero) + return new string [0]; + + try + { + return ReadWStringList (hList); + } + finally + { + FreeAppxBundlePayloadsFileNameList (hList); + } + } + + [DllImport (DllName, CallingConvention = CallConv)] + private static extern IntPtr GetAppxBundleAllFileResourcePackageFileNames (IntPtr hReader); + + /// + /// 获取 Bundle 包中所有文件资源包的文件名列表。 + /// + /// 由 CreatePackageReader 创建的读取器句柄 + /// 文件资源包文件名数组,若无则返回空数组 + public static string [] GetAppxBundleAllFileResourcePackageFileNameList (IntPtr hReader) + { + IntPtr hList = GetAppxBundleAllFileResourcePackageFileNames (hReader); + if (hList == IntPtr.Zero) + return new string [0]; + + try + { + return ReadWStringList (hList); + } + finally + { + FreeAppxBundlePayloadsFileNameList (hList); + } + } + + // 用于更新应用项名称列表(设置要查询的项) + [DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)] + public static extern void UpdatePackageApplicationItemGetName ( + [In] IntPtr [] lpNames, // 传入一个 IntPtr 数组,每个元素指向一个 Unicode 字符串 + uint dwArrLen + ); + + // 回调委托声明 + [UnmanagedFunctionPointer (CallConv)] + public delegate void IterWStringCallback ([MarshalAs (UnmanagedType.LPWStr)] string lpString); + + // 枚举当前列表中的项(通过回调逐个返回) + [DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)] + public static extern void GetPackageApplicationItemGetNameList ( + IterWStringCallback pfCallback // 回调函数指针 + ); + /// + /// 更新内部的应用项名称列表(设置要查询的项) + /// + /// 要设置的项名称集合 + public static void SetApplicationItemNames (IEnumerable names) + { + if (names == null) + { + // 传入空数组,清空列表 + UpdatePackageApplicationItemGetName (new IntPtr [0], 0); + return; + } + + var nameList = names.ToList (); + if (nameList.Count == 0) + { + UpdatePackageApplicationItemGetName (new IntPtr [0], 0); + return; + } + + // 为每个字符串分配非托管内存 + IntPtr [] ptrs = new IntPtr [nameList.Count]; + try + { + for (int i = 0; i < nameList.Count; i++) + { + ptrs [i] = Marshal.StringToHGlobalUni (nameList [i]); + } + + UpdatePackageApplicationItemGetName (ptrs, (uint)nameList.Count); + } + finally + { + // 释放分配的内存 + foreach (var ptr in ptrs) + { + if (ptr != IntPtr.Zero) + Marshal.FreeHGlobal (ptr); + } + } + } + /// + /// 获取当前内部的应用项名称列表(通过回调收集所有项) + /// + /// 应用项名称数组 + public static string [] GetApplicationItemNames () + { + var result = new List (); + + // 定义回调:将收到的字符串添加到列表 + IterWStringCallback callback = (str) => + { + if (!string.IsNullOrEmpty (str)) + result.Add (str); + }; + + // 调用本机函数,传入委托 + GetPackageApplicationItemGetNameList (callback); + + // 注意:GC 需要保持 callback 的存活直到本机调用结束,这里通过局部变量引用即可, + // 因为本机函数是同步调用的,不会在函数返回后继续使用回调。 + return result.ToArray (); + } } } \ No newline at end of file diff --git a/AppxPackage/Utils.cs b/AppxPackage/Utils.cs new file mode 100644 index 0000000..245c1d7 --- /dev/null +++ b/AppxPackage/Utils.cs @@ -0,0 +1,67 @@ +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; + +internal static class Utils +{ + public static string PascalToCamel (string pascalCase) + { + if (string.IsNullOrEmpty (pascalCase)) + return pascalCase; + + // 已经是小驼峰或首字母小写,直接返回 + if (char.IsLower (pascalCase [0])) + return pascalCase; + + // 按大写字母边界拆分单词(处理连续大写字母作为一个单词) + // 正则解释: + // (?<=[a-z])(?=[A-Z]) 小写后跟大写 -> 分割 + // | 或 + // (?<=[A-Z])(?=[A-Z][a-z]) 大写后跟大写+小写(如 XMLR 中的 X 和 MLR)-> 分割 + string [] words = Regex.Split (pascalCase, @"(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])"); + + StringBuilder result = new StringBuilder (); + + for (int i = 0; i < words.Length; i++) + { + string word = words [i]; + if (string.IsNullOrEmpty (word)) + continue; + + if (i == 0) + { + // 第一个单词:全部转为小写 + result.Append (word.ToLowerInvariant ()); + } + else + { + // 后续单词:首字母大写,其余小写 + result.Append (char.ToUpperInvariant (word [0])); + if (word.Length > 1) + result.Append (word.Substring (1).ToLowerInvariant ()); + } + } + + return result.ToString (); + } + /// + /// 表示应用清单中用于定义文件/资源路径的属性名称 + /// + public static readonly List AppFileProperties = new List + { + "Executable", + "LockScreenLogo", + "Logo", + "SmallLogo", + "Square150x150Logo", + "Square30x30Logo", + "Square310x310Logo", + "Square44x44Logo", + "Square70x70Logo", + "Square71x71Logo", + "StartPage", + "Tall150x310Logo", + "WideLogo", + "Wide310x150Logo" + }; +} \ No newline at end of file diff --git a/AppxPackage/packages.config b/AppxPackage/packages.config index 649c3f8..b785422 100644 --- a/AppxPackage/packages.config +++ b/AppxPackage/packages.config @@ -1,4 +1,5 @@  + \ No newline at end of file diff --git a/DataUtils/Storage.cs b/DataUtils/Storage.cs index d6d4583..dc66442 100644 --- a/DataUtils/Storage.cs +++ b/DataUtils/Storage.cs @@ -539,8 +539,7 @@ namespace DataUtils public void File (string filter, string initDir, object jsCallback) { IWin32Window owner = GetActiveWindowOwner (); - Thread t = new Thread (() => - { + Thread t = new Thread (() => { string result = string.Empty; try { @@ -565,8 +564,7 @@ namespace DataUtils public void Files (string filter, string initDir, object jsCallback) { IWin32Window owner = GetActiveWindowOwner (); - Thread t = new Thread (() => - { + Thread t = new Thread (() => { string result = "[]"; try { @@ -591,8 +589,7 @@ namespace DataUtils public void Dir (string initDir, object jsCallback) { IWin32Window owner = GetActiveWindowOwner (); - Thread t = new Thread (() => - { + Thread t = new Thread (() => { string result = string.Empty; try { @@ -616,8 +613,7 @@ namespace DataUtils public void Dirs (string initDir, object jsCallback) { IWin32Window owner = GetActiveWindowOwner (); - Thread t = new Thread (() => - { + Thread t = new Thread (() => { string result = "[]"; try { @@ -649,8 +645,71 @@ namespace DataUtils } [ComVisible (true)] [ClassInterface (ClassInterfaceType.AutoDual)] + public class _I_Folder + { + [DllImport ("shell32.dll")] + private static extern int SHGetKnownFolderPath ( + [MarshalAs (UnmanagedType.LPStruct)] Guid rfid, + uint dwFlags, + IntPtr hToken, + out IntPtr ppszPath); + private static string KF (Guid g) + { + IntPtr p; + SHGetKnownFolderPath (g, 0, IntPtr.Zero, out p); + string s = Marshal.PtrToStringUni (p); + Marshal.FreeCoTaskMem (p); + return s; + } + private static readonly Guid FOLDERID_Downloads = new Guid ("374DE290-123F-4565-9164-39C4925E467B"); + private static readonly Guid FOLDERID_SavedPictures = new Guid ("3B193882-D3AD-4EAB-965A-69829D1FB59F"); + private static readonly Guid FOLDERID_SavedGames = new Guid ("4C5C32FF-BB9D-43B0-BF90-45A0FEEB6D0E"); + private static readonly Guid FOLDERID_Links = new Guid ("BFB9D5E0-C6A9-404C-B2B2-AE6DB6AF4968"); + private static readonly Guid FOLDERID_Contacts = new Guid ("56784854-C6CB-462B-8169-88E350ACB882"); + private static readonly Guid FOLDERID_Searches = new Guid ("7D1D3A04-DEBB-4115-95CF-2F29DA2920DA"); + public string ProgramFiles => Environment.GetFolderPath (Environment.SpecialFolder.ProgramFiles); + public string ProgramFilesX86 => Environment.GetFolderPath (Environment.SpecialFolder.ProgramFilesX86); + public string Windows => Environment.GetFolderPath (Environment.SpecialFolder.Windows); + public string System32 => Environment.SystemDirectory; + public string UserProfile => Environment.GetFolderPath (Environment.SpecialFolder.UserProfile); + public string Desktop => Environment.GetFolderPath (Environment.SpecialFolder.Desktop); + public string Documents => Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments); + public string Pictures => Environment.GetFolderPath (Environment.SpecialFolder.MyPictures); + public string Music => Environment.GetFolderPath (Environment.SpecialFolder.MyMusic); + public string Videos => Environment.GetFolderPath (Environment.SpecialFolder.MyVideos); + public string AppDataRoaming => Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData); + public string AppDataLocal => Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData); + public string AppDataLocalLow => Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData) + "\\Low"; + public string Temp => System.IO.Path.GetTempPath (); + public string PublicDesktop => Environment.GetFolderPath (Environment.SpecialFolder.CommonDesktopDirectory); + public string PublicDocuments => Environment.GetFolderPath (Environment.SpecialFolder.CommonDocuments); + public string PublicPictures => Environment.GetFolderPath (Environment.SpecialFolder.CommonPictures); + public string PublicMusic => Environment.GetFolderPath (Environment.SpecialFolder.CommonMusic); + public string PublicVideos => Environment.GetFolderPath (Environment.SpecialFolder.CommonVideos); + public string Downloads => KF (FOLDERID_Downloads); + public string SavedPictures => KF (FOLDERID_SavedPictures); + public string SavedGames => KF (FOLDERID_SavedGames); + public string Links => KF (FOLDERID_Links); + public string Contacts => KF (FOLDERID_Contacts); + public string Searches => KF (FOLDERID_Searches); + } + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDual)] public class _I_Storage { + [DllImport ("user32.dll")] + private static extern IntPtr GetForegroundWindow (); + class WindowWrapper: IWin32Window + { + private IntPtr _hwnd; + public WindowWrapper (IntPtr handle) { _hwnd = handle; } + public IntPtr Handle { get { return _hwnd; } } + } + private static IWin32Window GetActiveWindowOwner () + { + IntPtr hWnd = GetForegroundWindow (); + return hWnd != IntPtr.Zero ? new WindowWrapper (hWnd) : null; + } private static void CallJS (object jsFunc, params object [] args) { if (jsFunc == null) return; @@ -680,6 +739,35 @@ namespace DataUtils public _I_Directory GetDirectory (string path) { return new _I_Directory (path); } public _I_Directory GetDir (string path) { return GetDirectory (path); } public _I_Explorer Explorer => new _I_Explorer (); + public void Save (string filter, string initDir, string defaultName, object jsCallback) + { + IWin32Window owner = GetActiveWindowOwner (); + Thread t = new Thread (() => { + string result = string.Empty; + try + { + using (SaveFileDialog dlg = new SaveFileDialog ()) + { + dlg.Filter = filter; + dlg.InitialDirectory = string.IsNullOrEmpty (initDir) + ? Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments) + : initDir; + if (!string.IsNullOrEmpty (defaultName)) + dlg.FileName = defaultName; + dlg.OverwritePrompt = true; + dlg.AddExtension = true; + if (dlg.ShowDialog (owner) == DialogResult.OK) + result = dlg.FileName; + } + } + catch { } + CallJS (jsCallback, result); + }); + t.IsBackground = true; + t.SetApartmentState (ApartmentState.STA); + t.Start (); + } + public _I_Folder Folders => new _I_Folder (); } // Small shell helpers that P/Invoke for folder retrieval using CSIDL or Known Folder GUIDs internal static class ShellHelpers diff --git a/Reader/ReaderShell.cs b/Reader/ReaderShell.cs index c48d8d1..91e4466 100644 --- a/Reader/ReaderShell.cs +++ b/Reader/ReaderShell.cs @@ -26,7 +26,7 @@ namespace Reader } catch { } InitSize (); - Text = Bridge.ResXmlStore.StringRes.Get ("MANAGER_APPTITLE"); + Text = Bridge.ResXmlStore.StringRes.Get ("READER_APPTITLE"); this.Load += Form_Load; } private void InitSize () diff --git a/pkgread/pkgread.cpp b/pkgread/pkgread.cpp index 91d6a85..f275b4f 100644 --- a/pkgread/pkgread.cpp +++ b/pkgread/pkgread.cpp @@ -1221,6 +1221,124 @@ void PackageReaderFreeString (LPWSTR lpStrFromThisDll) free (lpStrFromThisDll); } +HLIST_PVOID GetAppxBundleAllResourcePackageFileNames (_In_ HPKGREAD hReader) +{ + auto ptr = ToPtrPackage (hReader); + if (!ptr) return nullptr; + if (ptr->type () == PackageType::bundle) + { + auto br = ptr->bundle_reader (); + std::vector rpi; + br.package_id_items ().resource_packages (rpi); + auto buf = (HLIST_PVOID)malloc (sizeof (LIST_PVOID) + sizeof (LPWSTR) * rpi.size ()); + buf->dwSize = rpi.size (); + for (size_t i = 0; i < rpi.size (); i ++) + { + auto &it = rpi [i]; + buf->alpVoid [i] = _wcsdup (it.file_name ().c_str ()); + } + return buf; + } + return nullptr; +} +HLIST_PVOID GetAppxBundleAllLocaleResourcePackageFileNames (_In_ HPKGREAD hReader) +{ + auto ptr = ToPtrPackage (hReader); + if (!ptr) return nullptr; + if (ptr->type () == PackageType::bundle) + { + auto br = ptr->bundle_reader (); + std::vector rpi; + br.package_id_items ().resource_packages (rpi); + std::vector localePkgNames; + for (size_t i = 0; i < rpi.size (); i ++) + { + auto &it = rpi [i]; + auto qres = it.qualified_resources (); + std::vector langs; + std::vector temp; + std::vector dxt; + qres.qualified_resources (&langs, &temp, &dxt); + if (temp.size () > 0 || dxt.size () > 0) continue; + localePkgNames.push_back (it.file_name ()); + } + auto buf = (HLIST_PVOID)malloc (sizeof (LIST_PVOID) + sizeof (LPWSTR) * localePkgNames.size ()); + buf->dwSize = localePkgNames.size (); + for (size_t i = 0; i < localePkgNames.size (); i ++) + { + buf->alpVoid [i] = _wcsdup (localePkgNames [i].c_str ()); + } + return buf; + } + return nullptr; +} +HLIST_PVOID GetAppxBundleAllFileResourcePackageFileNames (_In_ HPKGREAD hReader) +{ + auto ptr = ToPtrPackage (hReader); + if (!ptr) return nullptr; + if (ptr->type () == PackageType::bundle) + { + auto br = ptr->bundle_reader (); + std::vector rpi; + br.package_id_items ().resource_packages (rpi); + std::vector filePkgNames; + for (size_t i = 0; i < rpi.size (); i ++) + { + auto &it = rpi [i]; + auto qres = it.qualified_resources (); + std::vector langs; + std::vector temp; + std::vector dxt; + qres.qualified_resources (&langs, &temp, &dxt); + if (temp.size () > 0) + filePkgNames.push_back (it.file_name ()); + } + auto buf = (HLIST_PVOID)malloc (sizeof (LIST_PVOID) + sizeof (LPWSTR) * filePkgNames.size ()); + buf->dwSize = filePkgNames.size (); + for (size_t i = 0; i < filePkgNames.size (); i ++) + { + buf->alpVoid [i] = _wcsdup (filePkgNames [i].c_str ()); + } + return buf; + } + return nullptr; +} +void FreeAppxBundlePayloadsFileNameList (_In_ HLIST_PVOID hStringList) +{ + if (!hStringList) return; + for (size_t i = 0; i < hStringList->dwSize; i ++) + { + auto ptr = hStringList->alpVoid [i]; + if (!ptr) continue; + free (ptr); + } + free (hStringList); +} +void UpdatePackageApplicationItemGetName (_In_ LPCWSTR *lpNames, _In_ DWORD dwArrLen) +{ + bool clearAll = !lpNames || !dwArrLen; + if (clearAll) + { + appitems.clear (); + return; + } + appitems.clear (); + for (size_t i = 0; i < dwArrLen; i ++) + { + auto ptr = lpNames [i]; + if (strnull (ptr)) continue; + push_unique (appitems, std::wstring (ptr)); + } +} +void GetPackageApplicationItemGetNameList (_In_ ITER_WSTRING_CALLBACK pfCallback) +{ + if (!pfCallback) return; + for (auto &it : appitems) + { + pfCallback (it.c_str ()); + } +} + // ========== Ƕ嵥ļĶȡ ========== #define ToHandleMRead(_cpp_ptr_) reinterpret_cast (_cpp_ptr_) #define ToPtrManifest(_cpp_ptr_) reinterpret_cast (_cpp_ptr_) diff --git a/pkgread/pkgread.h b/pkgread/pkgread.h index ddd4b06..e9bc179 100644 --- a/pkgread/pkgread.h +++ b/pkgread/pkgread.h @@ -290,6 +290,16 @@ extern "C" // ʵͨ free ͷżɣǵ⣬ôд˸ PKGREAD_API void PackageReaderFreeString (LPWSTR lpStrFromThisDll); + PKGREAD_API HLIST_PVOID GetAppxBundleAllResourcePackageFileNames (_In_ HPKGREAD hReader); + + PKGREAD_API HLIST_PVOID GetAppxBundleAllLocaleResourcePackageFileNames (_In_ HPKGREAD hReader); + + PKGREAD_API HLIST_PVOID GetAppxBundleAllFileResourcePackageFileNames (_In_ HPKGREAD hReader); + PKGREAD_API void FreeAppxBundlePayloadsFileNameList (_In_ HLIST_PVOID hStringList); + + PKGREAD_API void UpdatePackageApplicationItemGetName (_In_ LPCWSTR *lpNames, _In_ DWORD dwArrLen); + typedef void (*ITER_WSTRING_CALLBACK) (LPCWSTR lpString); + PKGREAD_API void GetPackageApplicationItemGetNameList (_In_ ITER_WSTRING_CALLBACK pfCallback); // ========= Ӧ嵥ĶȡһЩ͵Ǹõ ========= TEMPLATE_STRUCT (PKGMANIFESTREAD); diff --git a/priformatcli/priformatcli.cpp b/priformatcli/priformatcli.cpp index 0cc61d4..6fabeda 100644 --- a/priformatcli/priformatcli.cpp +++ b/priformatcli/priformatcli.cpp @@ -1055,6 +1055,10 @@ size_t GetPriScaleAndTargetSizeFileList ( auto value = quali->Value; qualis->Add (type, value); } + if (qualis->Count == 0 && tasktype == 1) + { + qualis->Add (QualifierType::Scale, 100); + } if (qualis->ContainsKey (QualifierType::Language)) { resc = PRI_MAKE_STRING (LocaleCodeToLcidW (MPStringToStdW (qualis [QualifierType::Language]->ToString ()))); diff --git a/reslib/reslib.rc b/reslib/reslib.rc index 89ca9fa65d55992d9ca16f31526636e59f1a0485..d8525f201e50c5bd90be85c7023ca029667845fc 100644 GIT binary patch delta 81 zcmcc7%`~BxX+xal + + + + + + + + diff --git a/shared/html/js/polyfill-ie.js b/shared/html/js/polyfill-ie.js index bd899f0..7796d29 100644 --- a/shared/html/js/polyfill-ie.js +++ b/shared/html/js/polyfill-ie.js @@ -215,4 +215,318 @@ } }; } +})(this); +(function(global) { + if (typeof global.Map === "undefined") { + function Map() { + this.elements = new Array(); + // 获取Map元素个数 + this.size = function() { + return this.elements.length; + }, + // 判断Map是否为空 + this.isEmpty = function() { + return (this.elements.length < 1); + }, + // 删除Map所有元素 + this.clear = function() { + this.elements = new Array(); + }, + // 向Map中增加元素(key, value) + this.put = function(_key, _value) { + if (this.containsKey(_key) == true) { + if (this.containsValue(_value)) { + if (this.remove(_key) == true) { + this.elements.push({ + key: _key, + value: _value + }); + } + } else { + this.elements.push({ + key: _key, + value: _value + }); + } + } else { + this.elements.push({ + key: _key, + value: _value + }); + } + }, + // 向Map中增加元素(key, value) + this.set = function(_key, _value) { + if (this.containsKey(_key) == true) { + if (this.containsValue(_value)) { + if (this.remove(_key) == true) { + this.elements.push({ + key: _key, + value: _value + }); + } + } else { + this.elements.push({ + key: _key, + value: _value + }); + } + } else { + this.elements.push({ + key: _key, + value: _value + }); + } + }, + // 删除指定key的元素,成功返回true,失败返回false + this.remove = function(_key) { + var bln = false; + try { + for (i = 0; i < this.elements.length; i++) { + if (this.elements[i].key == _key) { + this.elements.splice(i, 1); + return true; + } + } + } catch (e) { + bln = false; + } + return bln; + }, + + // 删除指定key的元素,成功返回true,失败返回false + this.delete = function(_key) { + var bln = false; + try { + for (i = 0; i < this.elements.length; i++) { + if (this.elements[i].key == _key) { + this.elements.splice(i, 1); + return true; + } + } + } catch (e) { + bln = false; + } + return bln; + }, + + // 获取指定key的元素值value,失败返回null + this.get = function(_key) { + try { + for (i = 0; i < this.elements.length; i++) { + if (this.elements[i].key == _key) { + return this.elements[i].value; + } + } + } catch (e) { + return null; + } + }, + + // set指定key的元素值value + this.setValue = function(_key, _value) { + var bln = false; + try { + for (i = 0; i < this.elements.length; i++) { + if (this.elements[i].key == _key) { + this.elements[i].value = _value; + return true; + } + } + } catch (e) { + bln = false; + } + return bln; + }, + + // 获取指定索引的元素(使用element.key,element.value获取key和value),失败返回null + this.element = function(_index) { + if (_index < 0 || _index >= this.elements.length) { + return null; + } + return this.elements[_index]; + }, + + // 判断Map中是否含有指定key的元素 + this.containsKey = function(_key) { + var bln = false; + try { + for (i = 0; i < this.elements.length; i++) { + if (this.elements[i].key == _key) { + bln = true; + } + } + } catch (e) { + bln = false; + } + return bln; + }, + + // 判断Map中是否含有指定key的元素 + this.has = function(_key) { + var bln = false; + try { + for (i = 0; i < this.elements.length; i++) { + if (this.elements[i].key == _key) { + bln = true; + } + } + } catch (e) { + bln = false; + } + return bln; + }, + + // 判断Map中是否含有指定value的元素 + this.containsValue = function(_value) { + var bln = false; + try { + for (i = 0; i < this.elements.length; i++) { + if (this.elements[i].value == _value) { + bln = true; + } + } + } catch (e) { + bln = false; + } + return bln; + }, + + // 获取Map中所有key的数组(array) + this.keys = function() { + var arr = new Array(); + for (i = 0; i < this.elements.length; i++) { + arr.push(this.elements[i].key); + } + return arr; + }, + + // 获取Map中所有value的数组(array) + this.values = function() { + var arr = new Array(); + for (i = 0; i < this.elements.length; i++) { + arr.push(this.elements[i].value); + } + return arr; + }; + + /** + * map遍历数组 + * @param callback [function] 回调函数; + * @param context [object] 上下文; + */ + this.forEach = function forEach(callback, context) { + context = context || window; + + //IE6-8下自己编写回调函数执行的逻辑 + var newAry = new Array(); + for (var i = 0; i < this.elements.length; i++) { + if (typeof callback === 'function') { + var val = callback.call(context, this.elements[i].value, this.elements[i].key, this.elements); + newAry.push(this.elements[i].value); + } + } + return newAry; + } + + } + global.Map = Map; + } +})(this); +(function(global) { + if (typeof global.Set === "undefined") { + function Set() { + var items = {}; + this.size = 0; + // 实现has方法 + // has(val)方法 + this.has = function(val) { + // 对象都有hasOwnProperty方法,判断是否拥有特定属性 + return items.hasOwnProperty(val); + }; + + // 实现add + this.add = function(val) { + if (!this.has(val)) { + items[val] = val; + this.size++; // 累加集合成员数量 + return true; + } + return false; + }; + + // delete(val)方法 + this.delete = function(val) { + if (this.has(val)) { + delete items[val]; // 将items对象上的属性删掉 + this.size--; + return true; + } + return false; + }; + // clear方法 + this.clear = function() { + items = {}; // 直接将集合赋一个空对象即可 + this.size = 0; + }; + + // keys()方法 + this.keys = function() { + return Object.keys(items); // 返回遍历集合的所有键名的数组 + }; + // values()方法 + this.values = function() { + return Object.values(items); // 返回遍历集合的所有键值的数组 + }; + + // forEach(fn, context)方法 + this.forEach = function(fn, context) { + for (var i = 0; i < this.size; i++) { + var item = Object.keys(items)[i]; + fn.call(context, item, item, items); + } + }; + + // 并集 + this.union = function(other) { + var union = new Set(); + var values = this.values(); + for (var i = 0; i < values.length; i++) { + union.add(values[i]); + } + values = other.values(); // 将values重新赋值为新的集合 + for (var i = 0; i < values.length; i++) { + union.add(values[i]); + } + + return union; + }; + // 交集 + this.intersect = function(other) { + var intersect = new Set(); + var values = this.values(); + for (var i = 0; i < values.length; i++) { + if (other.has(values[i])) { // 查看是否也存在于other中 + intersect.add(values[i]); // 存在的话就像intersect中添加元素 + } + } + return intersect; + }; + + // 差集 + this.difference = function(other) { + var difference = new Set(); + var values = this.values(); + for (var i = 0; i < values.length; i++) { + if (!other.has(values[i])) { // 将不存在于other集合中的添加到新的集合中 + difference.add(values[i]); + } + } + return difference; + }; + + + } + global.Set = Set; + } })(this); \ No newline at end of file diff --git a/shared/html/libs/contentdlg/contentdlg.css b/shared/html/libs/contentdlg/contentdlg.css deleted file mode 100644 index f61606e..0000000 --- a/shared/html/libs/contentdlg/contentdlg.css +++ /dev/null @@ -1,110 +0,0 @@ -.win-contentdialog { - position: absolute; - left: 0; - top: 0; - width: 100%; - height: 100%; - box-sizing: border-box; - background-color: rgba(0, 0, 0, 0.5); - transition: all 0.15s linear; - opacity: 1; - z-index: 100; -} -.win-contentdialog.hide { - opacity: 0; - pointer-events: none; -} -.win-contentdialog .win-contentdialog-dialog { - position: absolute; - left: 50%; - top: 50%; - width: 100%; - box-sizing: border-box; - padding: 20px 0; - background-color: rgb(31, 0, 104); - transition: all 0.5s cubic-bezier(0.1, 0.9, 0.2, 1); - transform: translate(-50%, -50%); -} - -.win-contentdialog .win-contentdialog-title { - font-size: 20pt; - font-weight: normal; - padding: 0 172px; - box-sizing: border-box; - display: block; -} - -.win-contentdialog .win-contentdialog-content { - padding: 0 172px; - overflow-y: auto; - box-sizing: border-box; - max-height: calc(100vh - 200px); - margin: 10px 0 20px 0; -} - -.win-contentdialog .win-contentdialog-commands { - padding: 0 172px; - box-sizing: border-box; - display: flex; - flex-direction: row; - flex-wrap: wrap; - align-content: flex-start; - justify-content: flex-end; -} - -.win-contentdialog .win-contentdialog-commands > button { - margin-left: 20px; -} - -.win-contentdialog .win-contentdialog-content p { - margin: 5px 0; -} - -.win-contentdialog .win-contentdialog-content dl dt, -.win-contentdialog .win-contentdialog-content dl dd { - display: inline-block; - margin: 0; - padding: 0; - vertical-align: middle; - margin-bottom: 10px; -} - -.win-contentdialog .win-contentdialog-content dl { - width: 100%; - max-width: 100%; - height: auto; - box-sizing: border-box; - margin: 0px; -} - -.win-contentdialog .win-contentdialog-content dl dt { - width: 100%; - max-width: 100%; - text-align: left; - padding-right: 8px; - } - -.win-contentdialog .win-contentdialog-content dl dd { - width: 100%; - max-width: 100%; - display: inline-block; - } - -.win-contentdialog .win-contentdialog-content dl dd * { - max-width: 100%; - } -.win-contentdialog-dialog-template { - display: none; -} -.win-contentdialog .win-contentdialog-content .win-contentdialog-dialog-template { - display: block; -} - -.win-ui-light .win-contentdialog .win-contentdialog-dialog, -.win-contentdialog.win-ui-light .win-contentdialog-dialog { - background-color: white; -} -.win-ui-dark .win-contentdialog .win-contentdialog-dialog, -.win-contentdialog.win-ui-dark .win-contentdialog-dialog { - background-color: rgb(31, 0, 104); -} \ No newline at end of file diff --git a/shared/html/libs/msgbox/contentdlg.css b/shared/html/libs/msgbox/contentdlg.css new file mode 100644 index 0000000..5f2c585 --- /dev/null +++ b/shared/html/libs/msgbox/contentdlg.css @@ -0,0 +1,117 @@ +.win-contentdialog { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + box-sizing: border-box; + background-color: rgba(0, 0, 0, 0.5); + transition: all 0.15s linear; + opacity: 1; + z-index: 100; +} + +.win-contentdialog.hide { + opacity: 0; + pointer-events: none; +} + +.win-contentdialog .win-contentdialog-dialog { + position: absolute; + left: 50%; + top: 50%; + width: 100%; + box-sizing: border-box; + padding: 20px 0; + background-color: rgb(31, 0, 104); + /*transition: all 0.5s cubic-bezier(0.1, 0.9, 0.2, 1);*/ + transition: height, max-height, min-height 0.5s cubic-bezier(0.1, 0.9, 0.2, 1); + transform: translate(-50%, -50%); +} + +.win-contentdialog .win-contentdialog-title { + font-size: 20pt; + font-weight: normal; + padding: 0 172px; + box-sizing: border-box; + display: block; +} + +.win-contentdialog .win-contentdialog-content { + padding: 0 172px; + overflow-y: auto; + box-sizing: border-box; + max-height: calc(100vh - 200px); + margin: 10px 0 20px 0; + font-weight: normal; +} + +.win-contentdialog .win-contentdialog-commands { + padding: 0 172px; + box-sizing: border-box; + display: flex; + flex-direction: row; + flex-wrap: wrap; + align-content: flex-start; + justify-content: flex-end; +} + +.win-contentdialog .win-contentdialog-commands>button { + margin-left: 20px; +} + +.win-contentdialog .win-contentdialog-content p { + margin: 5px 0; +} + +.win-contentdialog .win-contentdialog-content dl dt, +.win-contentdialog .win-contentdialog-content dl dd { + display: inline-block; + margin: 0; + padding: 0; + vertical-align: middle; + margin-bottom: 10px; +} + +.win-contentdialog .win-contentdialog-content dl { + width: 100%; + max-width: 100%; + height: auto; + box-sizing: border-box; + margin: 0px; +} + +.win-contentdialog .win-contentdialog-content dl dt { + width: 100%; + max-width: 100%; + text-align: left; + padding-right: 8px; +} + +.win-contentdialog .win-contentdialog-content dl dd { + width: 100%; + max-width: 100%; + display: inline-block; +} + +.win-contentdialog .win-contentdialog-content dl dd * { + max-width: 100%; +} + +.win-contentdialog-dialog-template { + display: none; +} + +.win-contentdialog .win-contentdialog-content .win-contentdialog-dialog-template { + display: block; +} + +.win-ui-light .win-contentdialog .win-contentdialog-dialog, +.win-contentdialog.win-ui-light .win-contentdialog-dialog { + background-color: white; +} + +.win-ui-dark .win-contentdialog .win-contentdialog-dialog, +.win-contentdialog.win-ui-dark .win-contentdialog-dialog { + background-color: rgb(31, 0, 104); +} \ No newline at end of file diff --git a/shared/html/libs/contentdlg/contentdlg.js b/shared/html/libs/msgbox/contentdlg.js similarity index 92% rename from shared/html/libs/contentdlg/contentdlg.js rename to shared/html/libs/msgbox/contentdlg.js index 27d7f5c..33dfb76 100644 --- a/shared/html/libs/contentdlg/contentdlg.js +++ b/shared/html/libs/msgbox/contentdlg.js @@ -3,7 +3,7 @@ (function (global) { "use strict"; - + if (typeof global.toStaticHTML === "undefined") global.toStaticHTML = function (str) { return str; }; if (typeof global.WinJS === "undefined" || !global.WinJS) global.WinJS = {}; if (typeof global.WinJS.UI === "undefined" || !global.WinJS.UI) global.WinJS.UI = {}; @@ -17,12 +17,12 @@ } /** - * 表示 ContentDialog 中的一个按钮命令。 - * @class - * @param {string} label 按钮显示文本 - * @param {function(Event=): (boolean|void)} [handler] 按钮点击处理函数 - * @param {string} [commandId] 命令唯一标识 - */ + * 表示 ContentDialog 中的一个按钮命令。 + * @class + * @param {string} label 按钮显示文本 + * @param {function(Event=): (boolean|void)} [handler] 按钮点击处理函数 + * @param {string} [commandId] 命令唯一标识 + */ function ContentDialogCommand(label, handler, commandId) { this.label = label; this.handler = handler; @@ -30,16 +30,17 @@ } /** - * 模拟 WinRT ContentDialog 的对话框 - * @class - * @memberof WinJS.UI - * @param {HTMLElement} element 容器 - * @param {Object} [options] 初始化选项 - */ + * 模拟 WinRT ContentDialog 的对话框 + * @class + * @memberof WinJS.UI + * @param {HTMLElement} element 容器 + * @param {Object} [options] 初始化选项 + */ function ContentDialog(element, options) { var container = element; - container.innerHTML = toStaticHTML('
'); + container.innerHTML = toStaticHTML('
'); container.classList.add("win-contentdialog"); + container.classList.add("notice-back"); container.classList.add("hide"); var title = container.querySelector(".win-contentdialog-title"); @@ -62,6 +63,7 @@ } self._commands.forEach(function (cmd, index) { var btn = document.createElement("button"); + btn.classList.add ("notice-btn"); btn.textContent = cmd.label; btn.setAttribute("data-command-id", cmd.commandId || index); diff --git a/shared/html/libs/msgbox/msgbox.css b/shared/html/libs/msgbox/msgbox.css index 427662f..e69de29 100644 --- a/shared/html/libs/msgbox/msgbox.css +++ b/shared/html/libs/msgbox/msgbox.css @@ -1,95 +0,0 @@ -.notice-back { - background-color: rgba(0, 0, 0, 0.5); - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - height: auto; - width: auto; - display: flex; - flex-direction: column; - flex-wrap: nowrap; - align-content: center; - justify-content: center; - display: -ms-flexbox; - -ms-flex-direction: column; - -ms-flex-wrap: nowrap; - -ms-flex-line-pack: center; - /* align-content: center */ - -ms-flex-pack: center; - /* justify-content: center */ - transition: all 0.15s linear; - opacity: 0; - z-index: 100; -} - -.notice-body { - background: #0078d7; - padding: 25px 172px; - left: 0; - right: 0; - top: auto; - bottom: auto; - max-height: 80%; - height: auto; - display: flex; - flex-direction: column; - flex-wrap: nowrap; - display: -ms-flexbox; - -ms-flex-direction: column; - -ms-flex-wrap: nowrap; - min-height: 0 !important; - box-sizing: border-box; -} - -.notice-body>h1, -.notice-body>h2, -.notice-body>h3, -.notice-body>h4, -.notice-body>h5, -.notice-body>h6, -.notice-body>p, -.notice-body>a, -.notice-body>span { - font-family: "Microsoft YaHei", "Segoe UI", "Ebrima", "Nirmala", "Gadugi", "Segoe UI Emoji", "Segoe UI Symbol", "Meiryo", "Leelawadee", "Microsoft JhengHei", "Malgun Gothic", "Estrangelo Edessa", "Microsoft Himalaya", "Microsoft New Tai Lue", "Microsoft PhagsPa", "Microsoft Tai Le", "Microsoft Yi Baiti", "Mongolian Baiti", "MV Boli", "Myanmar Text", "Javanese Text", "Cambria Math"; - white-space: pre-wrap; - word-break: break-all; -} - -.notice-title { - color: white; - font-weight: normal; - white-space: pre-wrap; -} - -.notice-text { - color: white; - font-weight: normal; - white-space: pre-wrap; - -ms-overflow-style: -ms-autohiding-scrollbar; -} - -.notice-controls { - display: flex; - flex-direction: row; - flex-wrap: nowrap; - align-content: center; - justify-content: flex-end; - align-items: center; - display: -ms-flexbox; - -ms-flex-direction: row; - -ms-flex-wrap: nowrap; - -ms-flex-line-pack: center; - /* align-content: center(几乎无效,保留即可) */ - -ms-flex-pack: end; - /* justify-content: flex-end */ - -ms-flex-align: center; - /* align-items: center */ - margin-top: 10px; - /*gap: 20px;*/ -} - -.notice-btn { - margin-left: 20px; -} \ No newline at end of file diff --git a/shared/html/libs/msgbox/msgbox.elder.css b/shared/html/libs/msgbox/msgbox.elder.css new file mode 100644 index 0000000..427662f --- /dev/null +++ b/shared/html/libs/msgbox/msgbox.elder.css @@ -0,0 +1,95 @@ +.notice-back { + background-color: rgba(0, 0, 0, 0.5); + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + height: auto; + width: auto; + display: flex; + flex-direction: column; + flex-wrap: nowrap; + align-content: center; + justify-content: center; + display: -ms-flexbox; + -ms-flex-direction: column; + -ms-flex-wrap: nowrap; + -ms-flex-line-pack: center; + /* align-content: center */ + -ms-flex-pack: center; + /* justify-content: center */ + transition: all 0.15s linear; + opacity: 0; + z-index: 100; +} + +.notice-body { + background: #0078d7; + padding: 25px 172px; + left: 0; + right: 0; + top: auto; + bottom: auto; + max-height: 80%; + height: auto; + display: flex; + flex-direction: column; + flex-wrap: nowrap; + display: -ms-flexbox; + -ms-flex-direction: column; + -ms-flex-wrap: nowrap; + min-height: 0 !important; + box-sizing: border-box; +} + +.notice-body>h1, +.notice-body>h2, +.notice-body>h3, +.notice-body>h4, +.notice-body>h5, +.notice-body>h6, +.notice-body>p, +.notice-body>a, +.notice-body>span { + font-family: "Microsoft YaHei", "Segoe UI", "Ebrima", "Nirmala", "Gadugi", "Segoe UI Emoji", "Segoe UI Symbol", "Meiryo", "Leelawadee", "Microsoft JhengHei", "Malgun Gothic", "Estrangelo Edessa", "Microsoft Himalaya", "Microsoft New Tai Lue", "Microsoft PhagsPa", "Microsoft Tai Le", "Microsoft Yi Baiti", "Mongolian Baiti", "MV Boli", "Myanmar Text", "Javanese Text", "Cambria Math"; + white-space: pre-wrap; + word-break: break-all; +} + +.notice-title { + color: white; + font-weight: normal; + white-space: pre-wrap; +} + +.notice-text { + color: white; + font-weight: normal; + white-space: pre-wrap; + -ms-overflow-style: -ms-autohiding-scrollbar; +} + +.notice-controls { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + align-content: center; + justify-content: flex-end; + align-items: center; + display: -ms-flexbox; + -ms-flex-direction: row; + -ms-flex-wrap: nowrap; + -ms-flex-line-pack: center; + /* align-content: center(几乎无效,保留即可) */ + -ms-flex-pack: end; + /* justify-content: flex-end */ + -ms-flex-align: center; + /* align-items: center */ + margin-top: 10px; + /*gap: 20px;*/ +} + +.notice-btn { + margin-left: 20px; +} \ No newline at end of file diff --git a/shared/html/libs/msgbox/msgbox.elder.js b/shared/html/libs/msgbox/msgbox.elder.js new file mode 100644 index 0000000..d85781c --- /dev/null +++ b/shared/html/libs/msgbox/msgbox.elder.js @@ -0,0 +1,532 @@ +function IsBlackLabel(text) { + if (text === null || text === undefined) return true; + var trimmed = String(text).replace(/^\s+|\s+$/g, ''); + return trimmed === ''; +} + +var MBFLAGS = { + MB_OK: 0x00000000, + MB_OKCANCEL: 0x00000001, + MB_ABORTRETRYIGNORE: 0x00000002, + MB_YESNOCANCEL: 0x00000003, + MB_YESNO: 0x00000004, + MB_RETRYCANCEL: 0x00000005, + MB_CANCELTRYCONTINUE: 0x00000006, + MB_HELP: 0x00004000, + MB_DEFBUTTON1: 0x00000000, + MB_DEFBUTTON2: 0x00000100, + MB_DEFBUTTON3: 0x00000200, + MB_DEFBUTTON4: 0x00000300, + MB_ICONERROR: 0x00000010, + MB_ICONWARNING: 0x00000030, + MB_ICONINFORMATION: 0x00000040 +}; + +var MBRET = { + IDOK: 1, + IDCANCEL: 2, + IDABORT: 3, + IDRETRY: 4, + IDIGNORE: 5, + IDYES: 6, + IDNO: 7, + IDCLOSE: 8, + IDHELP: 9, + IDTRYAGAIN: 10, + IDCONTINUE: 11 +}; + +Object.freeze(MBFLAGS); +Object.freeze(MBRET); + +(function(global) { + try { + var storage = Bridge.External.Storage; + var path = storage.path; + var root = path.getDir(path.program); + var respath = path.combine(root, "reslib.dll"); + var res = Bridge.Resources; + global.respath = respath; + global.getPublicRes = function(resId) { + return res.fromfile(respath, resId); + } + } catch (e) {} +})(this); + +function GetLocaleStringFromResId(resId) { try { return getPublicRes(resId); } catch (e) {} } +var msgboxResult = {}; + +function MessageBox(_lpText, _lpCaption, _uType, _objColor) { + var id = MessageBoxForJS(_lpText, _lpCaption, _uType, _objColor, function(valueReturn) { + getRes = valueReturn; + msgboxResult[id] = valueReturn; + }); + return id; +} + +function GetMessageBoxResult(msgboxId) { + var result = msgboxResult[msgboxId]; + if (result === undefined || result === null) return null; + msgboxResult[msgboxId] = null; + return result; +} + +function ClearAllMessageBoxResults() { + msgboxResult = null; + msgboxResult = {}; +} + +// 注意:callback 函数无返回值,传入参数:整数型 按下的按钮值。 +/* + 使用示例: + MessageBoxForJS("请选择一个按钮", "", MBFLAGS.MB_OKCANCEL, "#0078d7", function(value) { + console.log("MessageBoxForJS callback value: " + value); + }) +*/ +function MessageBoxForJS(_lpText, _lpCaption, _uType, _objColor, _callback) { + var msgbox = document.createElement("div"); + msgbox.classList.add("notice-back"); + msgbox.classList.add("win-ui-dark"); + var uniqueId = "msgbox_" + new Date().getTime(); + msgbox.id = uniqueId; + var msgbody = document.createElement("div"); + msgbody.classList.add("notice-body"); + if (!IsBlackLabel(_objColor)) { + msgbody.style.backgroundColor = _objColor; + } + msgbox.appendChild(msgbody); + var msgcontainter = document.createElement("div"); + msgcontainter.style.height = "100%"; + msgcontainter.style.width = "100%"; + msgcontainter.style.maxHeight = "100%"; + msgcontainter.style.minHeight = "0px"; + msgcontainter.style.boxSizing = "border-box"; + msgbody.appendChild(msgcontainter); + var msgcaption = document.createElement("div"); + msgcontainter.appendChild(msgcaption); + msgcontainter.style.display = "flex"; + msgcontainter.style.flexDirection = "column"; + var msgcontent = document.createElement("div"); + msgcontent.style.flex = "1 1 auto"; + msgcontent.style.marginRight = "3px"; + msgcontent.style.overflowX = "hidden"; + msgcontent.style.overflowY = "auto"; + msgcontent.style.minHeight = "0px"; + msgcontainter.appendChild(msgcontent); + if (_lpCaption instanceof HTMLElement) { + msgcaption.appendChild(_lpCaption); + msgcaption.classList.add("notice-title"); + } else { + if (!IsBlackLabel(_lpCaption)) { + var msgtitle = document.createElement("h2"); + msgtitle.textContent = _lpCaption; + msgtitle.classList.add("notice-title"); + msgcaption.appendChild(msgtitle); + } else { + var msgtitle = document.createElement("h2"); + msgtitle.textContent = ""; + msgtitle.classList.add("notice-title"); + msgcaption.appendChild(msgtitle); + } + } + if (_lpText instanceof HTMLElement || _lpText instanceof HTMLDivElement || typeof _lpText !== "string") { + try { + _lpText.classList.add("notice-text"); + msgcontent.appendChild(_lpText); + } catch (e) { + if (!IsBlackLabel(_lpText)) { + var msgtext = document.createElement("p"); + msgtext.textContent = _lpText; + msgtext.classList.add("notice-text"); + if (IsBlackLabel(_lpCaption)) { + msgtext.style.marginTop = "0"; + } + msgcontent.appendChild(msgtext); + } else { + var msgtext = document.createElement("p"); + msgtext.innerText = ""; + msgtext.classList.add("notice-text"); + if (IsBlackLabel(_lpCaption)) { + msgtext.style.marginTop = "0"; + } + msgcontent.appendChild(msgtext); + } + } + } else { + if (!IsBlackLabel(_lpText)) { + var msgtext = document.createElement("p"); + msgtext.textContent = _lpText; + msgtext.classList.add("notice-text"); + if (IsBlackLabel(_lpCaption)) { + msgtext.style.marginTop = "0"; + } + msgcontent.appendChild(msgtext); + } else { + var msgtext = document.createElement("p"); + msgtext.innerText = ""; + msgtext.classList.add("notice-text"); + if (IsBlackLabel(_lpCaption)) { + msgtext.style.marginTop = "0"; + } + msgcontent.appendChild(msgtext); + } + } + var msgctrls = document.createElement("div"); + msgctrls.classList.add("notice-controls"); + msgcontainter.appendChild(msgctrls); + var cnt = 0; + var cbFuncPress = function(valueReturn) { + getRes = valueReturn; + msgbox.style.opacity = 0; + setTimeout(function() { + document.body.removeChild(msgbox); + }, 500); + if (_callback) { + _callback(valueReturn); + } + }; + var pfCreateButton = function(displayNameResId, valueReturn) { + var btn = document.createElement("button"); + btn.innerHTML = GetLocaleStringFromResId(displayNameResId); + btn.classList.add("notice-btn"); + btn.addEventListener("click", function() { + cbFuncPress(valueReturn); + }); + msgctrls.appendChild(btn); + }; + if ((_uType & MBFLAGS.MB_HELP) === MBFLAGS.MB_HELP) { + pfCreateButton(808, MBRET.IDHELP); + } + for (cnt = 0; cnt <= MBFLAGS.MB_RETRYCANCEL; cnt++) { + if ((_uType & 0xF) === cnt) { + switch (cnt) { + case MBFLAGS.MB_OK: + { + pfCreateButton(800, MBRET.IDOK); + } + break; + case MBFLAGS.MB_OKCANCEL: + { + pfCreateButton(800, MBRET.IDOK); + pfCreateButton(801, MBRET.IDCANCEL); + } + break; + case MBFLAGS.MB_ABORTRETRYIGNORE: + { + pfCreateButton(802, MBRET.IDABORT); + pfCreateButton(803, MBRET.IDRETRY); + pfCreateButton(804, MBRET.IDIGNORE); + } + break; + case MBFLAGS.MB_YESNOCANCEL: + { + pfCreateButton(805, MBRET.IDYES); + pfCreateButton(806, MBRET.IDNO); + pfCreateButton(801, MBRET.IDCANCEL); + } + break; + case MBFLAGS.MB_YESNO: + { + pfCreateButton(805, MBRET.IDYES); + pfCreateButton(806, MBRET.IDNO); + } + break; + case MBFLAGS.MB_RETRYCANCEL: + { + pfCreateButton(803, MBRET.IDRETRY); + pfCreateButton(801, MBRET.IDCANCEL); + } + break; + case MBFLAGS.MB_CANCELTRYCONTINUE: + { + pfCreateButton(801, MBRET.IDCANCEL); + pfCreateButton(803, MBRET.IDRETRY); + pfCreateButton(810, MBRET.IDCONTINUE); + } + break; + } + } + } + var btns = msgctrls.querySelectorAll("button"); + var defaultBtnCnt = 0; + if ((_uType & MBFLAGS.MB_DEFBUTTON1) === MBFLAGS.MB_DEFBUTTON1) defaultBtnCnt = 0; + if ((_uType & MBFLAGS.MB_DEFBUTTON2) === MBFLAGS.MB_DEFBUTTON2) defaultBtnCnt = 1; + if ((_uType & MBFLAGS.MB_DEFBUTTON3) === MBFLAGS.MB_DEFBUTTON3) defaultBtnCnt = 2; + if ((_uType & MBFLAGS.MB_DEFBUTTON4) === MBFLAGS.MB_DEFBUTTON4) defaultBtnCnt = 3; + for (cnt = 0; cnt < btns.length; cnt++) { + if (cnt === defaultBtnCnt) { + btns[cnt].focus(); + break; + } + } + document.body.appendChild(msgbox); + setTimeout(function() { + msgbox.style.opacity = 1; + }, 1); + return msgbox.id; +} + +function MsgBoxObj() { + this.elementId = ""; + this.callback = null; + this.type = MBFLAGS.MB_OK; + this._boundCallback = this._internalCallback.bind(this); + this._text = ""; + this._title = ""; + this._color = "#0078d7"; + this.show = function() { + this.elementId = MessageBoxForJS( + this._text, + this._title, + this.type, + this._color, + this._boundCallback + ); + setTimeout(function() { + var element = document.getElementById(this.elementId); + if (element) { + var bodyElement = element.querySelector(".notice-body"); + if (bodyElement) { + bodyElement.style.transition = "all 0.5s linear"; + } + } + }.bind(this), 100); + } + Object.defineProperty(this, "text", { + get: function() { + return this._text; + }, + set: function(value) { + this._text = value; + if (this.elementId) { + var element = document.getElementById(this.elementId); + if (element) { + var textElement = element.querySelector(".notice-text"); + if (textElement) { + if (value instanceof HTMLElement) { + value.classList.add("notice-text"); + textElement.parentNode.replaceChild(value, textElement); + } else { + textElement.innerHTML = value; + } + } + } + } + } + }); + Object.defineProperty(this, "title", { + get: function() { + return this._title; + }, + set: function(value) { + this._title = value; + if (this.elementId) { + var element = document.getElementById(this.elementId); + if (element) { + var titleElement = element.querySelector(".notice-title"); + if (titleElement) { + titleElement.innerHTML = value; + } + } + } + } + }); + Object.defineProperty(this, "color", { + get: function() { + return this._color; + }, + set: function(value) { + this._color = value; + if (this.elementId) { + var element = document.getElementById(this.elementId); + if (element) { + var bodyElement = element.querySelector(".notice-body"); + if (bodyElement) { + bodyElement.style.backgroundColor = value; + } + } + } + } + }); + this.getElement = function() { + return document.getElementById(this.elementId); + }; +} + +MsgBoxObj.prototype._internalCallback = function(returnValue) { + if (typeof this.callback === "function") { + this.callback(returnValue); + } +}; +/** + * 异步显示消息框,返回一个 Promise 对象。 + * @param {string | HTMLElement} swText 内容 + * @param {string} swTitle 标题 + * @param {MBFLAGS} uType 标志,使用 MBFLAGS 常量 + * @param {string} swColor 背景颜色文本。 + * @returns {Promise} + */ +function messageBoxAsync(swText, swTitle, uType, swColor, pfCallback) { + if (typeof Promise === "undefined") { + console.error("Promise is not supported in this environment."); + MessageBoxForJS(swText, swTitle, uType, swColor, pfCallback); + } + return new Promise(function(resolve, reject) { + try { + MessageBoxForJS(swText, swTitle, uType, swColor, function(valueReturn) { + if (resolve) resolve(valueReturn); + }); + } catch (ex) { + if (reject) reject(ex); + } + }); +} + +function MessageBoxButton(swDisplayName, nValueReturn) { + this.displayName = swDisplayName; + this.value = nValueReturn; +} + +function messageBoxAdvance(swText, swCaption, aCommands, swColor, pfCallback) { + var _lpText = swText; + var _lpCaption = swCaption; + var msgbox = document.createElement("div"); + msgbox.classList.add("notice-back"); + msgbox.classList.add("win-ui-dark"); + var uniqueId = "msgbox_" + new Date().getTime(); + msgbox.id = uniqueId; + var msgbody = document.createElement("div"); + msgbody.classList.add("notice-body"); + if (!IsBlackLabel(swColor)) { + msgbody.style.backgroundColor = swColor; + } + msgbox.appendChild(msgbody); + var msgcontainter = document.createElement("div"); + msgcontainter.style.height = "100%"; + msgcontainter.style.width = "100%"; + msgcontainter.style.maxHeight = "100%"; + msgcontainter.style.minHeight = "0px"; + msgcontainter.style.boxSizing = "border-box"; + msgbody.appendChild(msgcontainter); + var msgcaption = document.createElement("div"); + msgcontainter.appendChild(msgcaption); + msgcontainter.style.display = "flex"; + msgcontainter.style.flexDirection = "column"; + var msgcontent = document.createElement("div"); + msgcontent.style.flex = "1 1 auto"; + msgcontent.style.marginRight = "3px"; + msgcontent.style.overflowX = "hidden"; + msgcontent.style.overflowY = "auto"; + msgcontent.style.minHeight = "0px"; + msgcontainter.appendChild(msgcontent); + if (_lpCaption instanceof HTMLElement) { + msgcaption.appendChild(_lpCaption); + msgcaption.classList.add("notice-title"); + } else { + if (!IsBlackLabel(_lpCaption)) { + var msgtitle = document.createElement("h2"); + msgtitle.textContent = _lpCaption; + msgtitle.classList.add("notice-title"); + msgcaption.appendChild(msgtitle); + } else { + var msgtitle = document.createElement("h2"); + msgtitle.textContent = ""; + msgtitle.classList.add("notice-title"); + msgcaption.appendChild(msgtitle); + } + } + if (_lpText instanceof HTMLElement || _lpText instanceof HTMLDivElement || typeof _lpText !== "string") { + try { + _lpText.classList.add("notice-text"); + msgcontent.appendChild(_lpText); + } catch (e) { + if (!IsBlackLabel(_lpText)) { + var msgtext = document.createElement("p"); + msgtext.textContent = _lpText; + msgtext.classList.add("notice-text"); + if (IsBlackLabel(_lpCaption)) { + msgtext.style.marginTop = "0"; + } + msgcontent.appendChild(msgtext); + } else { + var msgtext = document.createElement("p"); + msgtext.innerText = ""; + msgtext.classList.add("notice-text"); + if (IsBlackLabel(_lpCaption)) { + msgtext.style.marginTop = "0"; + } + msgcontent.appendChild(msgtext); + } + } + } else { + if (!IsBlackLabel(_lpText)) { + var msgtext = document.createElement("p"); + msgtext.textContent = _lpText; + msgtext.classList.add("notice-text"); + if (IsBlackLabel(_lpCaption)) { + msgtext.style.marginTop = "0"; + } + msgcontent.appendChild(msgtext); + } else { + var msgtext = document.createElement("p"); + msgtext.innerText = ""; + msgtext.classList.add("notice-text"); + if (IsBlackLabel(_lpCaption)) { + msgtext.style.marginTop = "0"; + } + msgcontent.appendChild(msgtext); + } + } + var msgctrls = document.createElement("div"); + msgctrls.classList.add("notice-controls"); + msgcontainter.appendChild(msgctrls); + if (aCommands.length <= 0) { + aCommands.push(new MessageBoxButton(GetLocaleStringFromResId(800) || "OK", MBRET.IDOK)); + } + for (var i = 0; i < aCommands.length; i++) { + var cmd = aCommands[i]; + var btn = document.createElement("button"); + btn.textContent = cmd.displayName; + btn.setAttribute("data-msgbox-value", cmd.value); + Windows.UI.Event.Util.addEvent(btn, "click", function(event) { + var btns = this.parentNode.querySelectorAll("button"); + var lastbtnstatus = []; + for (var j = 0; j < btns.length; j++) { + lastbtnstatus.push(btns[j].disabled); + btns[j].disabled = true; + } + try { + pfCallback(this.getAttribute("data-msgbox-value")); + } catch (e) {} + msgbox.style.opacity = 0; + setTimeout(function(nodes, laststatus) { + for (var k = 0; k < nodes.length; k++) { + nodes[k].disabled = laststatus[k]; + } + document.body.removeChild(msgbox); + }, 500, btns, lastbtnstatus); + }); + msgctrls.appendChild(btn); + } + document.body.appendChild(msgbox); + setTimeout(function() { + msgbox.style.opacity = 1; + }, 1); + return msgbox.id; +} + +function messageBoxAdvanceAsync(swText, swCaption, aCommands, swColor) { + if (typeof Promise === "undefined") { + console.error("Promise is not supported in this environment."); + messageBoxAdvance(swText, swCaption, aCommands, swColor); + } + return new Promise(function(resolve, reject) { + try { + messageBoxAdvance(swText, swCaption, aCommands, swColor, function(valueReturn) { + if (resolve) resolve(valueReturn); + }); + } catch (ex) { + if (reject) reject(ex); + } + }); +} \ No newline at end of file diff --git a/shared/html/libs/msgbox/msgbox.js b/shared/html/libs/msgbox/msgbox.js index d85781c..01921f6 100644 --- a/shared/html/libs/msgbox/msgbox.js +++ b/shared/html/libs/msgbox/msgbox.js @@ -39,6 +39,7 @@ var MBRET = { Object.freeze(MBFLAGS); Object.freeze(MBRET); +// ==================== 资源加载部分(保持不变) ==================== (function(global) { try { var storage = Bridge.External.Storage; @@ -53,15 +54,197 @@ Object.freeze(MBRET); } catch (e) {} })(this); -function GetLocaleStringFromResId(resId) { try { return getPublicRes(resId); } catch (e) {} } +function GetLocaleStringFromResId(resId) { + try { return getPublicRes(resId); } catch (e) { return ""; } +} + +// ==================== 全局结果存储 ==================== var msgboxResult = {}; -function MessageBox(_lpText, _lpCaption, _uType, _objColor) { - var id = MessageBoxForJS(_lpText, _lpCaption, _uType, _objColor, function(valueReturn) { - getRes = valueReturn; - msgboxResult[id] = valueReturn; +function ClearAllMessageBoxResults() { + msgboxResult = {}; +} + +// ==================== 辅助函数 ==================== +var _msgboxIdCounter = 0; + +function _generateMsgBoxId() { + return "msgbox_" + new Date().getTime() + "_" + (++_msgboxIdCounter); +} + +// 根据 MBFLAGS 生成命令列表(返回 { commands, defaultIndex }) +function _buildCommandsFromFlags(uType) { + var commands = []; + var baseType = uType & 0xF; + var defaultIndex = 0; + var hasHelp = (uType & MBFLAGS.MB_HELP) === MBFLAGS.MB_HELP; + + // 辅助添加命令 + function addCommand(resId, returnValue) { + var label = GetLocaleStringFromResId(resId); + if (!label) label = "Button"; + commands.push({ label: label, value: returnValue }); + } + + // 先处理帮助按钮(原实现中帮助按钮总是在最前面) + if (hasHelp) { + addCommand(808, MBRET.IDHELP); + } + + // 根据基础类型添加按钮 + switch (baseType) { + case MBFLAGS.MB_OK: + addCommand(800, MBRET.IDOK); + break; + case MBFLAGS.MB_OKCANCEL: + addCommand(800, MBRET.IDOK); + addCommand(801, MBRET.IDCANCEL); + break; + case MBFLAGS.MB_ABORTRETRYIGNORE: + addCommand(802, MBRET.IDABORT); + addCommand(803, MBRET.IDRETRY); + addCommand(804, MBRET.IDIGNORE); + break; + case MBFLAGS.MB_YESNOCANCEL: + addCommand(805, MBRET.IDYES); + addCommand(806, MBRET.IDNO); + addCommand(801, MBRET.IDCANCEL); + break; + case MBFLAGS.MB_YESNO: + addCommand(805, MBRET.IDYES); + addCommand(806, MBRET.IDNO); + break; + case MBFLAGS.MB_RETRYCANCEL: + addCommand(803, MBRET.IDRETRY); + addCommand(801, MBRET.IDCANCEL); + break; + case MBFLAGS.MB_CANCELTRYCONTINUE: + addCommand(801, MBRET.IDCANCEL); + addCommand(803, MBRET.IDRETRY); + addCommand(810, MBRET.IDCONTINUE); + break; + default: + addCommand(800, MBRET.IDOK); + break; + } + + // 确定默认按钮索引(考虑帮助按钮占位) + var defFlag = uType & 0x300; // MB_DEFBUTTON1~4 + var defButtonNumber = 0; + if (defFlag === MBFLAGS.MB_DEFBUTTON2) defButtonNumber = 1; + else if (defFlag === MBFLAGS.MB_DEFBUTTON3) defButtonNumber = 2; + else if (defFlag === MBFLAGS.MB_DEFBUTTON4) defButtonNumber = 3; + else defButtonNumber = 0; + + // 默认索引需要加上帮助按钮的偏移 + var finalDefaultIndex = (hasHelp ? 1 : 0) + defButtonNumber; + if (finalDefaultIndex >= commands.length) finalDefaultIndex = commands.length - 1; + if (finalDefaultIndex < 0) finalDefaultIndex = 0; + + return { commands: commands, defaultIndex: finalDefaultIndex }; +} + +// 创建 ContentDialog 并应用公共属性 +function _createContentDialog(title, content, bgColor, commands, defaultIndex, callback) { + var container = document.createElement("div"); + document.body.appendChild(container); + + var dialog = new WinJS.UI.ContentDialog(container, { + //title: typeof title === "string" ? title : "", + //content: typeof content === "string" ? content : "", + autoShow: false }); - return id; + dialog.title = title; + dialog.content = content; + // 处理标题为 HTMLElement + if (title instanceof HTMLElement) { + var titleContainer = container.querySelector(".win-contentdialog-title"); + if (titleContainer) { + while (titleContainer.firstChild) titleContainer.removeChild(titleContainer.firstChild); + titleContainer.appendChild(title); + } + } + + // 处理内容为 HTMLElement + if (content instanceof HTMLElement) { + var contentContainer = container.querySelector(".win-contentdialog-content"); + if (contentContainer) { + while (contentContainer.firstChild) contentContainer.removeChild(contentContainer.firstChild); + contentContainer.appendChild(content); + } + } + + // 背景色 + if (!IsBlackLabel(bgColor)) { + dialog.backgroundColor = bgColor; + } + + // 添加命令 + for (var i = 0; i < commands.length; i++) { + var cmd = commands[i]; + var dialogCmd = new WinJS.UI.ContentDialogCommand(cmd.label, function(evt) { + // 阻止多次点击 + if (dialog._isClosing) return; + dialog._isClosing = true; + + // 调用回调传递返回值 + if (callback) callback(cmd.value); + + // 关闭并移除对话框 + dialog.hide().then(function() { + try { document.body.removeChild(container); } catch (e) {} + dialog._isClosing = false; + }); + + // 返回 false 会阻止关闭,但我们手动关闭,所以返回 undefined 即可 + }, cmd.value.toString()); + dialog.commands.push(dialogCmd); + } + + // 设置默认按钮 + if (defaultIndex >= 0 && defaultIndex < dialog.commands.length) { + dialog.primaryCommandIndex = defaultIndex; + } + + return dialog; +} + +// ==================== 核心 API 实现 ==================== + +// 新版 MessageBoxForJS(完全基于 ContentDialog) +function MessageBoxForJS(_lpText, _lpCaption, _uType, _objColor, _callback) { + var dialogId = _generateMsgBoxId(); + var commandsInfo = _buildCommandsFromFlags(_uType); + + var dialog = _createContentDialog( + _lpCaption, + _lpText, + _objColor, + commandsInfo.commands, + commandsInfo.defaultIndex, + function(returnValue) { + if (_callback) _callback(returnValue); + } + ); + + // 存储 dialog 引用以便可能的后续操作(如 GetMessageBoxResult 不需要,但保留) + if (!window._activeDialogs) window._activeDialogs = {}; + window._activeDialogs[dialogId] = dialog; + dialog.element.id = dialogId; + // 显示对话框 + dialog.show().then(null, function(err) { console.error("ContentDialog show error:", err); }); + + return dialogId; +} + +// MessageBox:返回 ID,结果通过 GetMessageBoxResult 获取 +function MessageBox(_lpText, _lpCaption, _uType, _objColor) { + var msgboxId = _generateMsgBoxId(); + MessageBoxForJS(_lpText, _lpCaption, _uType, _objColor, function(valueReturn) { + msgboxResult[msgboxId] = valueReturn; + if (window._activeDialogs) delete window._activeDialogs[msgboxId]; + }); + return msgboxId; } function GetMessageBoxResult(msgboxId) { @@ -71,201 +254,84 @@ function GetMessageBoxResult(msgboxId) { return result; } -function ClearAllMessageBoxResults() { - msgboxResult = null; - msgboxResult = {}; -} - -// 注意:callback 函数无返回值,传入参数:整数型 按下的按钮值。 -/* - 使用示例: - MessageBoxForJS("请选择一个按钮", "", MBFLAGS.MB_OKCANCEL, "#0078d7", function(value) { - console.log("MessageBoxForJS callback value: " + value); - }) -*/ -function MessageBoxForJS(_lpText, _lpCaption, _uType, _objColor, _callback) { - var msgbox = document.createElement("div"); - msgbox.classList.add("notice-back"); - msgbox.classList.add("win-ui-dark"); - var uniqueId = "msgbox_" + new Date().getTime(); - msgbox.id = uniqueId; - var msgbody = document.createElement("div"); - msgbody.classList.add("notice-body"); - if (!IsBlackLabel(_objColor)) { - msgbody.style.backgroundColor = _objColor; +// 异步版本(返回 Promise) +function messageBoxAsync(swText, swTitle, uType, swColor, pfCallback) { + if (typeof Promise === "undefined") { + console.error("Promise is not supported in this environment."); + MessageBoxForJS(swText, swTitle, uType, swColor, pfCallback); + return null; } - msgbox.appendChild(msgbody); - var msgcontainter = document.createElement("div"); - msgcontainter.style.height = "100%"; - msgcontainter.style.width = "100%"; - msgcontainter.style.maxHeight = "100%"; - msgcontainter.style.minHeight = "0px"; - msgcontainter.style.boxSizing = "border-box"; - msgbody.appendChild(msgcontainter); - var msgcaption = document.createElement("div"); - msgcontainter.appendChild(msgcaption); - msgcontainter.style.display = "flex"; - msgcontainter.style.flexDirection = "column"; - var msgcontent = document.createElement("div"); - msgcontent.style.flex = "1 1 auto"; - msgcontent.style.marginRight = "3px"; - msgcontent.style.overflowX = "hidden"; - msgcontent.style.overflowY = "auto"; - msgcontent.style.minHeight = "0px"; - msgcontainter.appendChild(msgcontent); - if (_lpCaption instanceof HTMLElement) { - msgcaption.appendChild(_lpCaption); - msgcaption.classList.add("notice-title"); - } else { - if (!IsBlackLabel(_lpCaption)) { - var msgtitle = document.createElement("h2"); - msgtitle.textContent = _lpCaption; - msgtitle.classList.add("notice-title"); - msgcaption.appendChild(msgtitle); - } else { - var msgtitle = document.createElement("h2"); - msgtitle.textContent = ""; - msgtitle.classList.add("notice-title"); - msgcaption.appendChild(msgtitle); - } - } - if (_lpText instanceof HTMLElement || _lpText instanceof HTMLDivElement || typeof _lpText !== "string") { + return new Promise(function(resolve, reject) { try { - _lpText.classList.add("notice-text"); - msgcontent.appendChild(_lpText); - } catch (e) { - if (!IsBlackLabel(_lpText)) { - var msgtext = document.createElement("p"); - msgtext.textContent = _lpText; - msgtext.classList.add("notice-text"); - if (IsBlackLabel(_lpCaption)) { - msgtext.style.marginTop = "0"; - } - msgcontent.appendChild(msgtext); - } else { - var msgtext = document.createElement("p"); - msgtext.innerText = ""; - msgtext.classList.add("notice-text"); - if (IsBlackLabel(_lpCaption)) { - msgtext.style.marginTop = "0"; - } - msgcontent.appendChild(msgtext); - } + MessageBoxForJS(swText, swTitle, uType, swColor, function(valueReturn) { + if (pfCallback) pfCallback(valueReturn); + resolve(valueReturn); + }); + } catch (ex) { + reject(ex); } - } else { - if (!IsBlackLabel(_lpText)) { - var msgtext = document.createElement("p"); - msgtext.textContent = _lpText; - msgtext.classList.add("notice-text"); - if (IsBlackLabel(_lpCaption)) { - msgtext.style.marginTop = "0"; - } - msgcontent.appendChild(msgtext); - } else { - var msgtext = document.createElement("p"); - msgtext.innerText = ""; - msgtext.classList.add("notice-text"); - if (IsBlackLabel(_lpCaption)) { - msgtext.style.marginTop = "0"; - } - msgcontent.appendChild(msgtext); - } - } - var msgctrls = document.createElement("div"); - msgctrls.classList.add("notice-controls"); - msgcontainter.appendChild(msgctrls); - var cnt = 0; - var cbFuncPress = function(valueReturn) { - getRes = valueReturn; - msgbox.style.opacity = 0; - setTimeout(function() { - document.body.removeChild(msgbox); - }, 500); - if (_callback) { - _callback(valueReturn); - } - }; - var pfCreateButton = function(displayNameResId, valueReturn) { - var btn = document.createElement("button"); - btn.innerHTML = GetLocaleStringFromResId(displayNameResId); - btn.classList.add("notice-btn"); - btn.addEventListener("click", function() { - cbFuncPress(valueReturn); - }); - msgctrls.appendChild(btn); - }; - if ((_uType & MBFLAGS.MB_HELP) === MBFLAGS.MB_HELP) { - pfCreateButton(808, MBRET.IDHELP); - } - for (cnt = 0; cnt <= MBFLAGS.MB_RETRYCANCEL; cnt++) { - if ((_uType & 0xF) === cnt) { - switch (cnt) { - case MBFLAGS.MB_OK: - { - pfCreateButton(800, MBRET.IDOK); - } - break; - case MBFLAGS.MB_OKCANCEL: - { - pfCreateButton(800, MBRET.IDOK); - pfCreateButton(801, MBRET.IDCANCEL); - } - break; - case MBFLAGS.MB_ABORTRETRYIGNORE: - { - pfCreateButton(802, MBRET.IDABORT); - pfCreateButton(803, MBRET.IDRETRY); - pfCreateButton(804, MBRET.IDIGNORE); - } - break; - case MBFLAGS.MB_YESNOCANCEL: - { - pfCreateButton(805, MBRET.IDYES); - pfCreateButton(806, MBRET.IDNO); - pfCreateButton(801, MBRET.IDCANCEL); - } - break; - case MBFLAGS.MB_YESNO: - { - pfCreateButton(805, MBRET.IDYES); - pfCreateButton(806, MBRET.IDNO); - } - break; - case MBFLAGS.MB_RETRYCANCEL: - { - pfCreateButton(803, MBRET.IDRETRY); - pfCreateButton(801, MBRET.IDCANCEL); - } - break; - case MBFLAGS.MB_CANCELTRYCONTINUE: - { - pfCreateButton(801, MBRET.IDCANCEL); - pfCreateButton(803, MBRET.IDRETRY); - pfCreateButton(810, MBRET.IDCONTINUE); - } - break; - } - } - } - var btns = msgctrls.querySelectorAll("button"); - var defaultBtnCnt = 0; - if ((_uType & MBFLAGS.MB_DEFBUTTON1) === MBFLAGS.MB_DEFBUTTON1) defaultBtnCnt = 0; - if ((_uType & MBFLAGS.MB_DEFBUTTON2) === MBFLAGS.MB_DEFBUTTON2) defaultBtnCnt = 1; - if ((_uType & MBFLAGS.MB_DEFBUTTON3) === MBFLAGS.MB_DEFBUTTON3) defaultBtnCnt = 2; - if ((_uType & MBFLAGS.MB_DEFBUTTON4) === MBFLAGS.MB_DEFBUTTON4) defaultBtnCnt = 3; - for (cnt = 0; cnt < btns.length; cnt++) { - if (cnt === defaultBtnCnt) { - btns[cnt].focus(); - break; - } - } - document.body.appendChild(msgbox); - setTimeout(function() { - msgbox.style.opacity = 1; - }, 1); - return msgbox.id; + }); } +// MessageBoxButton 类(保持不变) +function MessageBoxButton(swDisplayName, nValueReturn) { + this.displayName = swDisplayName; + this.value = nValueReturn; +} + +// 高级自定义按钮对话框 +function messageBoxAdvance(swText, swCaption, aCommands, swColor, pfCallback) { + var dialogId = _generateMsgBoxId(); + + // 转换 aCommands 为内部格式 + var commands = []; + for (var i = 0; i < aCommands.length; i++) { + var cmd = aCommands[i]; + commands.push({ + label: cmd.displayName, + value: cmd.value + }); + } + if (commands.length === 0) { + commands.push({ label: GetLocaleStringFromResId(800) || "OK", value: MBRET.IDOK }); + } + + var dialog = _createContentDialog( + swCaption, + swText, + swColor, + commands, + 0, // 默认第一个按钮为默认 + function(returnValue) { + if (pfCallback) pfCallback(returnValue); + } + ); + dialog.element.id = dialogId; + if (!window._activeDialogs) window._activeDialogs = {}; + window._activeDialogs[dialogId] = dialog; + + dialog.show(); + return dialogId; +} + +function messageBoxAdvanceAsync(swText, swCaption, aCommands, swColor) { + if (typeof Promise === "undefined") { + console.error("Promise is not supported in this environment."); + messageBoxAdvance(swText, swCaption, aCommands, swColor); + return null; + } + return new Promise(function(resolve, reject) { + try { + messageBoxAdvance(swText, swCaption, aCommands, swColor, function(valueReturn) { + resolve(valueReturn); + }); + } catch (ex) { + reject(ex); + } + }); +} + +// ==================== MsgBoxObj 类(保持原接口,内部已适配) ==================== function MsgBoxObj() { this.elementId = ""; this.callback = null; @@ -274,28 +340,31 @@ function MsgBoxObj() { this._text = ""; this._title = ""; this._color = "#0078d7"; + this.show = function() { + var self = this; this.elementId = MessageBoxForJS( this._text, this._title, this.type, this._color, - this._boundCallback + function(valueReturn) { + self._boundCallback(valueReturn); + } ); setTimeout(function() { - var element = document.getElementById(this.elementId); + var element = document.getElementById(self.elementId); if (element) { var bodyElement = element.querySelector(".notice-body"); if (bodyElement) { bodyElement.style.transition = "all 0.5s linear"; } } - }.bind(this), 100); - } + }, 100); + }; + Object.defineProperty(this, "text", { - get: function() { - return this._text; - }, + get: function() { return this._text; }, set: function(value) { this._text = value; if (this.elementId) { @@ -314,10 +383,9 @@ function MsgBoxObj() { } } }); + Object.defineProperty(this, "title", { - get: function() { - return this._title; - }, + get: function() { return this._title; }, set: function(value) { this._title = value; if (this.elementId) { @@ -331,10 +399,9 @@ function MsgBoxObj() { } } }); + Object.defineProperty(this, "color", { - get: function() { - return this._color; - }, + get: function() { return this._color; }, set: function(value) { this._color = value; if (this.elementId) { @@ -348,6 +415,7 @@ function MsgBoxObj() { } } }); + this.getElement = function() { return document.getElementById(this.elementId); }; @@ -357,176 +425,4 @@ MsgBoxObj.prototype._internalCallback = function(returnValue) { if (typeof this.callback === "function") { this.callback(returnValue); } -}; -/** - * 异步显示消息框,返回一个 Promise 对象。 - * @param {string | HTMLElement} swText 内容 - * @param {string} swTitle 标题 - * @param {MBFLAGS} uType 标志,使用 MBFLAGS 常量 - * @param {string} swColor 背景颜色文本。 - * @returns {Promise} - */ -function messageBoxAsync(swText, swTitle, uType, swColor, pfCallback) { - if (typeof Promise === "undefined") { - console.error("Promise is not supported in this environment."); - MessageBoxForJS(swText, swTitle, uType, swColor, pfCallback); - } - return new Promise(function(resolve, reject) { - try { - MessageBoxForJS(swText, swTitle, uType, swColor, function(valueReturn) { - if (resolve) resolve(valueReturn); - }); - } catch (ex) { - if (reject) reject(ex); - } - }); -} - -function MessageBoxButton(swDisplayName, nValueReturn) { - this.displayName = swDisplayName; - this.value = nValueReturn; -} - -function messageBoxAdvance(swText, swCaption, aCommands, swColor, pfCallback) { - var _lpText = swText; - var _lpCaption = swCaption; - var msgbox = document.createElement("div"); - msgbox.classList.add("notice-back"); - msgbox.classList.add("win-ui-dark"); - var uniqueId = "msgbox_" + new Date().getTime(); - msgbox.id = uniqueId; - var msgbody = document.createElement("div"); - msgbody.classList.add("notice-body"); - if (!IsBlackLabel(swColor)) { - msgbody.style.backgroundColor = swColor; - } - msgbox.appendChild(msgbody); - var msgcontainter = document.createElement("div"); - msgcontainter.style.height = "100%"; - msgcontainter.style.width = "100%"; - msgcontainter.style.maxHeight = "100%"; - msgcontainter.style.minHeight = "0px"; - msgcontainter.style.boxSizing = "border-box"; - msgbody.appendChild(msgcontainter); - var msgcaption = document.createElement("div"); - msgcontainter.appendChild(msgcaption); - msgcontainter.style.display = "flex"; - msgcontainter.style.flexDirection = "column"; - var msgcontent = document.createElement("div"); - msgcontent.style.flex = "1 1 auto"; - msgcontent.style.marginRight = "3px"; - msgcontent.style.overflowX = "hidden"; - msgcontent.style.overflowY = "auto"; - msgcontent.style.minHeight = "0px"; - msgcontainter.appendChild(msgcontent); - if (_lpCaption instanceof HTMLElement) { - msgcaption.appendChild(_lpCaption); - msgcaption.classList.add("notice-title"); - } else { - if (!IsBlackLabel(_lpCaption)) { - var msgtitle = document.createElement("h2"); - msgtitle.textContent = _lpCaption; - msgtitle.classList.add("notice-title"); - msgcaption.appendChild(msgtitle); - } else { - var msgtitle = document.createElement("h2"); - msgtitle.textContent = ""; - msgtitle.classList.add("notice-title"); - msgcaption.appendChild(msgtitle); - } - } - if (_lpText instanceof HTMLElement || _lpText instanceof HTMLDivElement || typeof _lpText !== "string") { - try { - _lpText.classList.add("notice-text"); - msgcontent.appendChild(_lpText); - } catch (e) { - if (!IsBlackLabel(_lpText)) { - var msgtext = document.createElement("p"); - msgtext.textContent = _lpText; - msgtext.classList.add("notice-text"); - if (IsBlackLabel(_lpCaption)) { - msgtext.style.marginTop = "0"; - } - msgcontent.appendChild(msgtext); - } else { - var msgtext = document.createElement("p"); - msgtext.innerText = ""; - msgtext.classList.add("notice-text"); - if (IsBlackLabel(_lpCaption)) { - msgtext.style.marginTop = "0"; - } - msgcontent.appendChild(msgtext); - } - } - } else { - if (!IsBlackLabel(_lpText)) { - var msgtext = document.createElement("p"); - msgtext.textContent = _lpText; - msgtext.classList.add("notice-text"); - if (IsBlackLabel(_lpCaption)) { - msgtext.style.marginTop = "0"; - } - msgcontent.appendChild(msgtext); - } else { - var msgtext = document.createElement("p"); - msgtext.innerText = ""; - msgtext.classList.add("notice-text"); - if (IsBlackLabel(_lpCaption)) { - msgtext.style.marginTop = "0"; - } - msgcontent.appendChild(msgtext); - } - } - var msgctrls = document.createElement("div"); - msgctrls.classList.add("notice-controls"); - msgcontainter.appendChild(msgctrls); - if (aCommands.length <= 0) { - aCommands.push(new MessageBoxButton(GetLocaleStringFromResId(800) || "OK", MBRET.IDOK)); - } - for (var i = 0; i < aCommands.length; i++) { - var cmd = aCommands[i]; - var btn = document.createElement("button"); - btn.textContent = cmd.displayName; - btn.setAttribute("data-msgbox-value", cmd.value); - Windows.UI.Event.Util.addEvent(btn, "click", function(event) { - var btns = this.parentNode.querySelectorAll("button"); - var lastbtnstatus = []; - for (var j = 0; j < btns.length; j++) { - lastbtnstatus.push(btns[j].disabled); - btns[j].disabled = true; - } - try { - pfCallback(this.getAttribute("data-msgbox-value")); - } catch (e) {} - msgbox.style.opacity = 0; - setTimeout(function(nodes, laststatus) { - for (var k = 0; k < nodes.length; k++) { - nodes[k].disabled = laststatus[k]; - } - document.body.removeChild(msgbox); - }, 500, btns, lastbtnstatus); - }); - msgctrls.appendChild(btn); - } - document.body.appendChild(msgbox); - setTimeout(function() { - msgbox.style.opacity = 1; - }, 1); - return msgbox.id; -} - -function messageBoxAdvanceAsync(swText, swCaption, aCommands, swColor) { - if (typeof Promise === "undefined") { - console.error("Promise is not supported in this environment."); - messageBoxAdvance(swText, swCaption, aCommands, swColor); - } - return new Promise(function(resolve, reject) { - try { - messageBoxAdvance(swText, swCaption, aCommands, swColor, function(valueReturn) { - if (resolve) resolve(valueReturn); - }); - } catch (ex) { - if (reject) reject(ex); - } - }); -} \ No newline at end of file +}; \ No newline at end of file diff --git a/shared/html/manager.html b/shared/html/manager.html index 5894ef0..d8d2f94 100644 --- a/shared/html/manager.html +++ b/shared/html/manager.html @@ -27,6 +27,8 @@ + + diff --git a/shared/html/reader.html b/shared/html/reader.html index 819fd3a..32d4f90 100644 --- a/shared/html/reader.html +++ b/shared/html/reader.html @@ -26,6 +26,8 @@ + + @@ -60,14 +62,14 @@
- - + +
- +
- -

读取结果:

-
+ + + + + +
+ +

读取结果:

+ + @@ -130,7 +372,7 @@
  • - +
  • + + + \ No newline at end of file diff --git a/shared/html/settings.html b/shared/html/settings.html index f4a1e3f..ab89ca5 100644 --- a/shared/html/settings.html +++ b/shared/html/settings.html @@ -21,6 +21,8 @@ + + diff --git a/shared/html/settings/appinstaller.html b/shared/html/settings/appinstaller.html index d1e0c0e..52c8b8b 100644 --- a/shared/html/settings/appinstaller.html +++ b/shared/html/settings/appinstaller.html @@ -21,6 +21,8 @@ + + diff --git a/shared/html/settings/appinstaller/about.html b/shared/html/settings/appinstaller/about.html index d2f243a..90d8939 100644 --- a/shared/html/settings/appinstaller/about.html +++ b/shared/html/settings/appinstaller/about.html @@ -21,6 +21,8 @@ + + diff --git a/shared/html/settings/appinstaller/cssedit.html b/shared/html/settings/appinstaller/cssedit.html index dc6a99a..08b688e 100644 --- a/shared/html/settings/appinstaller/cssedit.html +++ b/shared/html/settings/appinstaller/cssedit.html @@ -22,8 +22,12 @@ + + + + diff --git a/shared/html/settings/appinstaller/general.html b/shared/html/settings/appinstaller/general.html index f05e16a..cd90d53 100644 --- a/shared/html/settings/appinstaller/general.html +++ b/shared/html/settings/appinstaller/general.html @@ -21,6 +21,8 @@ + + diff --git a/shared/html/settings/appinstaller/guide.html b/shared/html/settings/appinstaller/guide.html index e047431..b4196da 100644 --- a/shared/html/settings/appinstaller/guide.html +++ b/shared/html/settings/appinstaller/guide.html @@ -21,6 +21,8 @@ + + diff --git a/shared/html/settings/appinstaller/theme.html b/shared/html/settings/appinstaller/theme.html index da37605..4cc5081 100644 --- a/shared/html/settings/appinstaller/theme.html +++ b/shared/html/settings/appinstaller/theme.html @@ -21,6 +21,8 @@ + + diff --git a/shared/html/settings/manager.html b/shared/html/settings/manager.html index a6533ed..edbfc43 100644 --- a/shared/html/settings/manager.html +++ b/shared/html/settings/manager.html @@ -21,6 +21,8 @@ + + diff --git a/shared/html/settings/manager/general.html b/shared/html/settings/manager/general.html index 6f79050..4d33332 100644 --- a/shared/html/settings/manager/general.html +++ b/shared/html/settings/manager/general.html @@ -21,6 +21,8 @@ + + diff --git a/shared/html/settings/manager/guide.html b/shared/html/settings/manager/guide.html index 7e0c67d..058a047 100644 --- a/shared/html/settings/manager/guide.html +++ b/shared/html/settings/manager/guide.html @@ -21,6 +21,8 @@ + + diff --git a/shared/html/settings/settings.html b/shared/html/settings/settings.html index f5e5371..c5041b3 100644 --- a/shared/html/settings/settings.html +++ b/shared/html/settings/settings.html @@ -21,6 +21,8 @@ + + diff --git a/shared/html/settings/settings/general.html b/shared/html/settings/settings/general.html index 664e39e..2104c8a 100644 --- a/shared/html/settings/settings/general.html +++ b/shared/html/settings/settings/general.html @@ -21,6 +21,8 @@ + + diff --git a/shared/html/settings/settings/guide.html b/shared/html/settings/settings/guide.html index 906de3b..f395274 100644 --- a/shared/html/settings/settings/guide.html +++ b/shared/html/settings/settings/guide.html @@ -21,6 +21,8 @@ + + diff --git a/shared/html/settings/update.html b/shared/html/settings/update.html index d69dd27..16c3af1 100644 --- a/shared/html/settings/update.html +++ b/shared/html/settings/update.html @@ -22,6 +22,8 @@ + + diff --git a/shared/locale/resources.xml b/shared/locale/resources.xml index 41ef461..a4a93e1 100644 --- a/shared/locale/resources.xml +++ b/shared/locale/resources.xml @@ -614,4 +614,8 @@ 更新完成 Update Complete. + + Package Reader + Package Reader + \ No newline at end of file