diff --git a/AppInstallerReset.sln b/AppInstallerReset.sln index 806d252..7aa137a 100644 --- a/AppInstallerReset.sln +++ b/AppInstallerReset.sln @@ -61,6 +61,9 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WAShell", "WAShell\WAShell.csproj", "{4EC16578-EFBF-41E6-8D7F-976E3646DD1D}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Manager", "Manager\Manager.csproj", "{DC074727-72E4-43C5-BAAF-E0D548104797}" + ProjectSection(ProjectDependencies) = postProject + {3AE2A022-ED83-41F1-948A-12A7593CBD00} = {3AE2A022-ED83-41F1-948A-12A7593CBD00} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IEHelper", "IEHelper\IEHelper.vcxproj", "{E4CA78A9-9408-4F5F-ADD6-730FD501FF8E}" EndProject diff --git a/AppxPackage/AppxPackage.csproj b/AppxPackage/AppxPackage.csproj index c008200..f1694e0 100644 --- a/AppxPackage/AppxPackage.csproj +++ b/AppxPackage/AppxPackage.csproj @@ -62,6 +62,7 @@ + diff --git a/AppxPackage/ManifestReader.cs b/AppxPackage/ManifestReader.cs new file mode 100644 index 0000000..59311c6 --- /dev/null +++ b/AppxPackage/ManifestReader.cs @@ -0,0 +1,1000 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using AppxPackage.Info; +using NativeWrappers; +using System.IO; +namespace AppxPackage +{ + public static class DataUrlHelper + { + [DllImport ("urlmon.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] + private static extern int FindMimeFromData ( + IntPtr pBC, + string pwzUrl, + byte [] pBuffer, + int cbSize, + string pwzMimeProposed, + int dwMimeFlags, + out IntPtr ppwzMimeOut, + int dwReserved); + private const int FMFD_RETURNUPDATEDIMGMIMES = 0x00000001; + private const int FMFD_IGNOREMIMETEXTPLAIN = 0x00000010; + private const int FMFD_URLASFILENAME = 0x00000020; + private static string GetMimeTypeFromStream (Stream stream) + { + if (stream == null) return string.Empty; + long originalPos = 0; + try + { + if (stream.CanSeek) + { + originalPos = stream.Position; + stream.Seek (0, SeekOrigin.Begin); + } + byte [] buffer = new byte [256]; + int bytesRead = stream.Read (buffer, 0, buffer.Length); + if (stream.CanSeek) stream.Seek (originalPos, SeekOrigin.Begin); + if (bytesRead == 0) return string.Empty; + IntPtr mimePtr; + int hr = FindMimeFromData ( + IntPtr.Zero, + null, + buffer, + bytesRead, + null, + FMFD_RETURNUPDATEDIMGMIMES | FMFD_IGNOREMIMETEXTPLAIN | FMFD_URLASFILENAME, + out mimePtr, + 0); + string mime = string.Empty; + if (hr == 0 && mimePtr != IntPtr.Zero) + { + mime = Marshal.PtrToStringUni (mimePtr); + Marshal.FreeCoTaskMem (mimePtr); + } + if (string.IsNullOrEmpty (mime)) + { + // fallback by magic bytes + if (bytesRead >= 8 && buffer [0] == 0x89 && buffer [1] == 0x50 && buffer [2] == 0x4E && buffer [3] == 0x47 && + buffer [4] == 0x0D && buffer [5] == 0x0A && buffer [6] == 0x1A && buffer [7] == 0x0A) + mime = "image/png"; + else if (bytesRead >= 3 && buffer [0] == 0xFF && buffer [1] == 0xD8) + mime = "image/jpeg"; + else if (bytesRead >= 6 && Encoding.ASCII.GetString (buffer, 0, 6) == "GIF89a") + mime = "image/gif"; + else if (bytesRead >= 2 && buffer [0] == 'B' && buffer [1] == 'M') + mime = "image/bmp"; + else if (bytesRead >= 12 && Encoding.ASCII.GetString (buffer, 0, 4) == "RIFF" && + Encoding.ASCII.GetString (buffer, 8, 4) == "WEBP") + mime = "image/webp"; + else if (bytesRead >= 4 && buffer [0] == 0x00 && buffer [1] == 0x00 && buffer [2] == 0x01 && buffer [3] == 0x00) + mime = "image/x-icon"; + else + mime = "application/octet-stream"; + } + return mime; + } + catch + { + return string.Empty; + } + } + public static string FileToDataUrl (string filePath) + { + if (string.IsNullOrEmpty (filePath)) return string.Empty; + try + { + using (FileStream fs = new FileStream (filePath, FileMode.Open, FileAccess.Read)) + { + if (fs.Length == 0) return string.Empty; + string mime = GetMimeTypeFromStream (fs); + if (string.IsNullOrEmpty (mime)) return string.Empty; + byte [] bytes = new byte [fs.Length]; + fs.Seek (0, SeekOrigin.Begin); + int read = fs.Read (bytes, 0, bytes.Length); + if (read != bytes.Length) return string.Empty; + string base64 = Convert.ToBase64String (bytes); + return $"data:{mime};base64,{base64}"; + } + } + catch + { + return string.Empty; + } + } + } + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDual)] + public class BaseInfoSectWithPRISingle: BaseInfoSection + { + protected Ref m_reader = null; + protected Ref m_pri = null; + protected Ref m_usePri = false; + protected Ref m_enablePri = false; + public BaseInfoSectWithPRISingle (ref IntPtr hReader, ManifestReader reader, ref PriReader pri, ref bool usePri, ref bool enablePri) : base (ref hReader) + { + m_reader.Set (reader); + m_pri.Set (pri); + m_usePri.Set (usePri); + m_enablePri.Set (enablePri); + } + public new void Dispose () + { + try { m_reader.Set (null); } catch (Exception) { } + try { m_pri.Set (null); } catch (Exception) { } + m_usePri = null; + m_enablePri = null; + m_hReader = null; + } + ~BaseInfoSectWithPRISingle () { Dispose (); } + } + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDual)] + public class MRIdentity: BaseInfoSection, Info.IIdentity + { + public MRIdentity (ref IntPtr hReader) : base (ref hReader) { } + protected string StringValue (uint name) + { + var ptr = PackageReadHelper.GetManifestIdentityStringValue (m_hReader, name); + return PackageReadHelper.GetStringAndFreeFromPkgRead (ptr) ?? ""; + } + public string FamilyName { get { return StringValue (2); } } + public string FullName { get { return StringValue (3); } } + public string Name { get { return StringValue (0); } } + public List ProcessArchitecture + { + get + { + var list = new List (); + uint uarch = 0; + PackageReadHelper.GetManifestIdentityArchitecture (m_hReader, out uarch); + var t = PackageReadHelper.GetManifestType (m_hReader); + switch (t) + { + case 1: + switch (uarch) + { + case 0x1: list.Add (Architecture.x86); break; + case 0x2: list.Add (Architecture.x64); break; + case 0x4: list.Add (Architecture.ARM); break; + case 0x8: list.Add (Architecture.ARM64); break; + case 0xE: list.Add (Architecture.Neutral); break; + } + break; + case 2: + if ((uarch & 0x1) != 0) list.Add (Architecture.x86); + if ((uarch & 0x2) != 0) list.Add (Architecture.x64); + if ((uarch & 0x4) != 0) list.Add (Architecture.ARM); + if ((uarch & 0x8) != 0) list.Add (Architecture.ARM64); + break; + } + return list; + } + } + public string Publisher { get { return StringValue (1); } } + public string ResourceId { get { return StringValue (4); } } + public DataUtils.Version Version + { + get + { + PackageReadHelper.VERSION ver = new PackageReadHelper.VERSION (); + PackageReadHelper.GetManifestIdentityVersion (m_hReader, out ver); + return new DataUtils.Version (ver.major, ver.minor, ver.build, ver.revision); + } + } + public override object BuildJSON () + { + return new + { + name = Name, + package_full_name = FullName, + package_family_name = FamilyName, + publisher = Publisher, + resource_id = ResourceId, + architecture = ProcessArchitecture.Select (e => (int)e).ToList (), + version = Version.BuildJSON () + }; + } + } + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDual)] + public class MRProperties: BaseInfoSectWithPRISingle, Info.IProperties + { + public MRProperties (ref IntPtr hReader, ManifestReader reader, ref PriReader priBundle, ref bool usePri, ref bool enablePri) : base (ref hReader, reader, ref priBundle, ref usePri, ref enablePri) { } + protected string StringValue (string attr) + { + var ptr = PackageReadHelper.GetManifestPropertiesStringValue (m_hReader, attr); + return PackageReadHelper.GetStringAndFreeFromPkgRead (ptr) ?? ""; + } + protected bool BoolValue (string attr, bool defaultValue = false) + { + int ret = 0; + HRESULT hr = PackageReadHelper.GetManifestPropertiesBoolValue (m_hReader, attr, out ret); + if (hr.Succeeded) return ret != 0; + else return defaultValue; + } + protected string StringResValue (string attr) + { + var res = StringValue (attr); + try + { + if (m_usePri && m_enablePri) + { + if (PriFileHelper.IsMsResourcePrefix (res)) + return m_pri.Value.String (res) ?? res; + } + } + catch (Exception) { } + return res; + } + protected string PathResValue (string attr) + { + var res = StringValue (attr); + try + { + if (m_usePri && m_enablePri) + { + var resvalue = m_pri.Value.String (res); + if (!string.IsNullOrEmpty (resvalue)) return resvalue; + else return res; + } + } + catch (Exception) { } + return res; + } + public string Description { get { return StringResValue ("Description"); } } + public string DisplayName { get { return StringResValue ("DisplayName"); } } + public bool Framework { get { return BoolValue ("Framework"); } } + public string Logo { get { return PathResValue ("Logo"); } } + public string LogoBase64 + { + get + { + var root = m_reader.Value.FileRoot; + var logopath = Path.Combine (root, Logo); + var ret = DataUrlHelper.FileToDataUrl (logopath); + if (!string.IsNullOrWhiteSpace (ret)) return ret; + logopath = Path.Combine (root, StringValue ("Logo")); + ret = DataUrlHelper.FileToDataUrl (logopath); + if (!string.IsNullOrWhiteSpace (ret)) return ret; + return String.Empty; + } + } + public string Publisher { get { return StringResValue ("PublisherDisplayName"); } } + public bool ResourcePackage { get { return BoolValue ("ResourcePackage"); } } + public override object BuildJSON () + { + return new + { + display_name = DisplayName, + description = Description, + publisher_display_name = Publisher, + Framework = Framework, + resource_package = ResourcePackage, + logo = Logo, + logo_base64 = LogoBase64 + }; + } + } + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDual)] + public class MRApplication: Dictionary + { + protected Ref m_hReader = IntPtr.Zero; + protected Ref m_pri = null; + protected Ref m_usePri = false; + protected Ref m_enablePri = false; + protected string m_root = String.Empty; + public MRApplication (ref IntPtr hReader, ref PriReader priBundle, ref bool usePri, ref bool enablePri, string rootDir) : base (StringComparer.OrdinalIgnoreCase) + { + m_hReader = hReader; + m_pri = priBundle; + m_usePri = usePri; + m_enablePri = enablePri; + m_root = rootDir; + } + public MRApplication (ref Ref m_hReader, ref Ref m_priBundle, ref Ref m_usePri, ref Ref m_enablePri, string rootDir) + { + this.m_hReader = m_hReader; + this.m_pri = m_priBundle; + this.m_usePri = m_usePri; + this.m_enablePri = m_enablePri; + this.m_root = rootDir; + } + public string UserModelID { get { return this ["AppUserModelID"]; } } + protected bool EnablePri () + { + if (m_pri == null || m_pri.Value == null) return false; + if (!m_usePri.Value) return false; + return m_enablePri.Value; + } + protected string StringResValue (string attr) + { + try + { + var res = this [attr]; + try + { + if (m_usePri && m_enablePri) + { + if (PriFileHelper.IsMsResourcePrefix (res)) + return m_pri.Value.String (res) ?? res; + } + } + catch (Exception) { } + return res; + } + catch (Exception) { return String.Empty; } + } + protected string PriGetRes (string resName) + { + if (string.IsNullOrEmpty (resName)) return string.Empty; + if (m_pri == null || m_pri.Value == null) return string.Empty; + return m_pri.Value.Resource (resName); + } + protected bool IsFilePathKey (string key) + { + foreach (var i in ConstData.FilePathItems) + if ((i?.Trim ()?.ToLower () ?? "") == (key?.Trim ()?.ToLower () ?? "")) + return true; + return false; + } + public new string this [string key] + { + get + { + string value; + if (!TryGetValue (key, out value)) + { + value = string.Empty; + base [key] = value; + } + if (!EnablePri ()) return value; + if (PriFileHelper.IsMsResourcePrefix (value)) + { + string pri = PriGetRes (value); + return string.IsNullOrEmpty (pri) ? value : pri; + } + if (IsFilePathKey (key) && !string.IsNullOrEmpty (value)) + { + string pri = PriGetRes (value); + return string.IsNullOrEmpty (pri) ? value : pri; + } + return value; + } + } + public string At (string key) + { + string value; + if (!TryGetValue (key, out value)) throw new KeyNotFoundException ($"PRBaseApplication.At: key \"{key}\" not found"); + if (!EnablePri ()) return value; + if (PriFileHelper.IsMsResourcePrefix (value)) + { + string pri = PriGetRes (value); + if (!string.IsNullOrEmpty (pri)) + return pri; + } + return value; + } + public string NewAt (string key, bool toPriString) + { + string value; + if (!TryGetValue (key, out value)) + { + value = string.Empty; + base [key] = value; + } + if (!EnablePri () && toPriString) return value; + if (PriFileHelper.IsMsResourcePrefix (value)) + { + string pri = PriGetRes (value); + return string.IsNullOrEmpty (pri) ? value : pri; + } + if (IsFilePathKey (key) && !string.IsNullOrEmpty (value)) + { + string pri = PriGetRes (value); + return string.IsNullOrEmpty (pri) ? value : pri; + } + return value; + } + public string NewAtBase64 (string key) + { + string value = NewAt (key, true); + if (!IsFilePathKey (key) || string.IsNullOrEmpty (value)) return ""; + switch (PackageReadHelper.GetPackageType (m_hReader)) + { + case 1: // PKGTYPE_APPX + { + var root = m_root; + var logopath = Path.Combine (root, NewAt (key, true)); + var ret = DataUrlHelper.FileToDataUrl (logopath); + if (!string.IsNullOrWhiteSpace (ret)) return ret; + logopath = Path.Combine (root, NewAt (key, false)); + ret = DataUrlHelper.FileToDataUrl (logopath); + if (!string.IsNullOrWhiteSpace (ret)) return ret; + return String.Empty; + } break; + } + return ""; + } + public static bool operator == (MRApplication a, MRApplication b) + { + if (ReferenceEquals (a, b)) return true; + if ((object)a == null || (object)b == null) return false; + return string.Equals (a.UserModelID, b.UserModelID, StringComparison.OrdinalIgnoreCase); + } + public static bool operator != (MRApplication a, MRApplication b) + { + return !(a == b); + } + public override bool Equals (object obj) + { + var other = obj as MRApplication; + if (other == null) return false; + return this == other; + } + public override int GetHashCode () + { + return (UserModelID ?? "").ToLowerInvariant ().GetHashCode (); + } + } + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDual)] + public class MRApplications: BaseInfoSectWithPRISingle, IEnumerable + { + private IntPtr _hList = IntPtr.Zero; + private List _apps; + public MRApplications ( + ref IntPtr hReader, + ManifestReader reader, + ref PriReader priBundle, + ref bool usePri, + ref bool enablePri) + : base (ref hReader, reader, ref priBundle, ref usePri, ref enablePri) + { + if (IsValid) + { + _hList = PackageReadHelper.GetManifestApplications (m_hReader.Value); + } + } + #region Dispose + public new void Dispose () + { + if (_hList != IntPtr.Zero) + { + PackageReadHelper.DestroyManifestApplications (_hList); + _hList = IntPtr.Zero; + } + base.Dispose (); + } + ~MRApplications () + { + Dispose (); + } + #endregion + #region 属性:Applications + public List Applications + { + get + { + if (_apps == null) + _apps = ReadApplications (); + return _apps; + } + } + #endregion + #region 索引器 + public MRApplication this [int index] + { + get { return Applications [index]; } + } + public MRApplication this [string key] + { + get + { + foreach (var app in Applications) + { + if (string.Equals (app.UserModelID, key, StringComparison.OrdinalIgnoreCase)) + { + return app; + } + } + return null; + } + } + #endregion + #region IEnumerable + public IEnumerator GetEnumerator () + { + return Applications.GetEnumerator (); + } + IEnumerator IEnumerable.GetEnumerator () + { + return GetEnumerator (); + } + #endregion + #region 内部解析逻辑(核心等价 C++ get) + private List ReadApplications () + { + var list = new List (); + if (_hList == IntPtr.Zero) return list; + IntPtr hMapList = PackageReadHelper.ApplicationsToMap (_hList); + if (hMapList == IntPtr.Zero) return list; + try + { + uint count = (uint)Marshal.ReadInt32 (hMapList); + int baseOffset = Marshal.SizeOf (typeof (uint)); + for (int i = 0; i < count; i++) + { + IntPtr hKeyValues = Marshal.ReadIntPtr (hMapList, baseOffset + i * IntPtr.Size); + if (hKeyValues == IntPtr.Zero) continue; + list.Add (ReadSingleApplication (hKeyValues)); + } + } + finally + { + PackageReadHelper.DestroyApplicationsMap (hMapList); + } + return list; + } + private MRApplication ReadSingleApplication (IntPtr hKeyValues) + { + var app = new MRApplication (ref m_hReader, ref m_pri, ref m_usePri, ref m_enablePri, m_reader.Value.FileRoot); + uint pairCount = (uint)Marshal.ReadInt32 (hKeyValues); + int baseOffset = Marshal.SizeOf (typeof (uint)); + int pairSize = Marshal.SizeOf (typeof (PackageReadHelper.PAIR_PVOID)); + for (int j = 0; j < pairCount; j++) + { + IntPtr pPair = IntPtr.Add (hKeyValues, baseOffset + j * pairSize); + var pair = (PackageReadHelper.PAIR_PVOID)Marshal.PtrToStructure (pPair, typeof (PackageReadHelper.PAIR_PVOID)); + if (pair.lpKey == IntPtr.Zero) continue; + string key = Marshal.PtrToStringUni (pair.lpKey); + if (string.IsNullOrEmpty (key)) continue; + string value = pair.lpValue != IntPtr.Zero + ? Marshal.PtrToStringUni (pair.lpValue) + : string.Empty; + app.Add (key, value); + } + return app; + } + #endregion + public override object BuildJSON () + { + using (var apps = this) + { + return apps.Select (app => { + var dict = new Dictionary (StringComparer.OrdinalIgnoreCase); + foreach (var kv in app) + { + dict [kv.Key] = kv.Value; + if (ConstData.IsFilePathKey (kv.Key)) + { + dict [(kv.Key?.Trim () ?? "") + "_Base64"] = app.NewAtBase64 (kv.Key); + } + } + dict ["AppUserModelID"] = app.UserModelID; + return dict; + }).ToList (); + } + } + } + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDual)] + public class MRCapabilities: BaseInfoSection, ICapabilities + { + public MRCapabilities (ref IntPtr hReader) : base (ref hReader) { } + public List Capabilities + { + get + { + var ret = new List (); + if (!IsValid) return ret; + IntPtr hList = PackageReadHelper.GetCapabilitiesList (m_hReader.Value); + if (hList == IntPtr.Zero) return ret; + try + { + uint count = (uint)Marshal.ReadInt32 (hList); + int baseOffset = Marshal.SizeOf (typeof (uint)); // dwSize 后 + for (int i = 0; i < count; i++) + { + IntPtr pStr = Marshal.ReadIntPtr (hList, baseOffset + i * IntPtr.Size); + if (pStr == IntPtr.Zero) continue; + string s = Marshal.PtrToStringUni (pStr); + if (!string.IsNullOrEmpty (s)) ret.Add (s); + } + } + finally + { + PackageReadHelper.DestroyWStringList (hList); + } + return ret; + } + } + public List DeviceCapabilities + { + get + { + var ret = new List (); + if (!IsValid) return ret; + IntPtr hList = PackageReadHelper.GetDeviceCapabilitiesList (m_hReader.Value); + if (hList == IntPtr.Zero) return ret; + try + { + uint count = (uint)Marshal.ReadInt32 (hList); + int baseOffset = Marshal.SizeOf (typeof (uint)); // dwSize 后 + for (int i = 0; i < count; i++) + { + IntPtr pStr = Marshal.ReadIntPtr (hList, baseOffset + i * IntPtr.Size); + if (pStr == IntPtr.Zero) continue; + string s = Marshal.PtrToStringUni (pStr); + if (!string.IsNullOrEmpty (s)) ret.Add (s); + } + } + finally + { + PackageReadHelper.DestroyWStringList (hList); + } + return ret; + } + } + public List CapabilityDisplayNames + { + get + { + var caps = Capabilities; + var dev = DeviceCapabilities; + var ret = new List (); + foreach (var c in caps) + { + var capname = CacheData.GetPackageCapabilityDisplayName (c); + if (String.IsNullOrWhiteSpace (capname)) ret.Add (c); + else ret.Add (capname); + } + foreach (var d in dev) + { + var dcapname = CacheData.GetPackageCapabilityDisplayName (d); + if (!String.IsNullOrWhiteSpace (dcapname)) ret.Add (dcapname); + } + return ret; + } + } + public override object BuildJSON () + { + return new + { + capabilities_name = Capabilities, + device_capabilities = DeviceCapabilities, + scales = CapabilityDisplayNames + }; + } + } + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDual)] + public class MRDependencies: BaseInfoSection, IEnumerable + { + public MRDependencies (ref IntPtr hReader) : base (ref hReader) { } + public List Dependencies + { + get + { + var output = new List (); + if (!IsValid) return output; + IntPtr hList = PackageReadHelper.GetDependencesInfoList (m_hReader); + if (hList == IntPtr.Zero) return output; + try + { + var deps = PackageReadHelper.ReadDependencyInfoList (hList); + foreach (var dep in deps) + { + // dep.lpName / dep.lpPublisher 是 IntPtr + string name = Marshal.PtrToStringUni (dep.lpName) ?? ""; + string publisher = Marshal.PtrToStringUni (dep.lpPublisher) ?? ""; + // VERSION 直接映射为 System.Version + var ver = new DataUtils.Version (dep.verMin.major, dep.verMin.minor, dep.verMin.build, dep.verMin.revision); + output.Add (new DependencyInfo (name, publisher, ver)); + } + } + finally + { + PackageReadHelper.DestroyDependencesInfoList (hList); + } + return output; + } + } + public DependencyInfo this [int index] => Dependencies [index]; + public IEnumerator GetEnumerator () + { + return Dependencies.GetEnumerator (); + } + IEnumerator IEnumerable.GetEnumerator () + { + return GetEnumerator (); + } + public override object BuildJSON () + { + return this.Select (d => new { + name = d.Name, + publisher = d.Publisher, + vermin = d.Version.BuildJSON () + }).ToList (); + } + } + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDual)] + public class MRResources: BaseInfoSection, IResources + { + public MRResources (ref IntPtr hReader) : base (ref hReader) { } + public List DXFeatures + { + get + { + var ret = new List (); + try + { + var dw = PackageReadHelper.GetResourcesDxFeatureLevels (m_hReader); + if ((dw & 0x1) != 0) ret.Add (DXFeatureLevel.Level9); + if ((dw & 0x2) != 0) ret.Add (DXFeatureLevel.Level10); + if ((dw & 0x4) != 0) ret.Add (DXFeatureLevel.Level11); + if ((dw & 0x8) != 0) ret.Add (DXFeatureLevel.Level12); + } + catch (Exception) { } + return ret; + } + } + public List Languages + { + get + { + var ret = new List (); + if (!IsValid) return ret; + IntPtr hList = PackageReadHelper.GetResourcesLanguages (m_hReader.Value); + if (hList == IntPtr.Zero) return ret; + try + { + ret = PackageReadHelper.ReadWStringList (hList).ToList (); + } + finally + { + PackageReadHelper.DestroyWStringList (hList); + } + return ret; + } + } + public List Languages_LCID + { + get + { + var ret = new List (); + if (!IsValid) return ret; + IntPtr hList = PackageReadHelper.GetResourcesLanguagesToLcid (m_hReader.Value); + if (hList == IntPtr.Zero) return ret; + try + { + ret = PackageReadHelper.ReadLcidList (hList).ToList (); + } + finally + { + PackageReadHelper.DestroyResourcesLanguagesLcidList (hList); + } + return ret; + } + } + public List Scales + { + get + { + var ret = new List (); + if (!IsValid) return ret; + IntPtr hList = PackageReadHelper.GetResourcesLanguagesToLcid (m_hReader.Value); + if (hList == IntPtr.Zero) return ret; + try + { + ret = PackageReadHelper.ReadUInt32List (hList).Select (e => (int)e).ToList (); + } + finally + { + PackageReadHelper.DestroyUInt32List (hList); + } + return ret; + } + } + public override object BuildJSON () + { + return new + { + dx_feature_levels = DXFeatures.Select (e => (int)e).ToList (), + languages = Languages, + scales = Scales + }; + } + } + public class MRPrerequisites: BaseInfoSection, IPrerequisites + { + public MRPrerequisites (ref IntPtr hReader) : base (ref hReader) { } + protected DataUtils.Version GetVersion (string name) + { + PackageReadHelper.VERSION ver; + bool res = PackageReadHelper.GetManifestPrerequisite (m_hReader, name, out ver); + if (res) return new DataUtils.Version (ver.major, ver.minor, ver.build, ver.revision); + else return new DataUtils.Version (); + } + protected string GetVersionDescription (string name) + { + var ptr = PackageReadHelper.GetPackagePrerequistieSystemVersionName (m_hReader, name); + return PackageReadHelper.GetStringAndFreeFromPkgRead (ptr) ?? ""; + } + public string OSMaxVersionDescription { get { return GetVersionDescription ("OSMaxVersionTested"); } } + public DataUtils.Version OSMaxVersionTested { get { return GetVersion ("OSMaxVersionTested"); } } + public DataUtils.Version OSMinVersion { get { return GetVersion ("OSMinVersion"); } } + public string OSMinVersionDescription { get { return GetVersionDescription ("OSMinVersion"); } } + public override object BuildJSON () + { + return new + { + os_min_version = OSMinVersion.BuildJSON (), + os_min_version_description = OSMinVersionDescription, + os_max_version_tested = OSMaxVersionTested.BuildJSON (), + os_max_version_tested_description = OSMaxVersionDescription + }; + } + } + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDual)] + public class ManifestReader: IDisposable + { + private IntPtr m_hReader = PackageReadHelper.CreateManifestReader (); + private string m_filePath = string.Empty; + private bool m_usePRI = false; + private bool m_enablePRI = false; + private PriReader m_pri = new PriReader (); + public IntPtr Instance => m_hReader; + public string FileRoot{ get { return Path.GetPathRoot (m_filePath); } } + private void InitPri () + { + m_pri.Dispose (); + if (!m_usePRI) return; + #region Get PRI IStream + switch (Type) + { + case PackageType.Appx: + { + var pripath = Path.Combine (FileRoot, "resources.pri"); + m_pri.Create (pripath); + } + break; + } + #endregion + try + { + var resnames = new HashSet (); + using (var prop = Properties) + { + var temp = prop.Description; + if (PriFileHelper.IsMsResourcePrefix (temp)) resnames.Add (temp); + temp = prop.DisplayName; + if (PriFileHelper.IsMsResourcePrefix (temp)) resnames.Add (temp); + temp = prop.Publisher; + if (PriFileHelper.IsMsResourcePrefix (temp)) resnames.Add (temp); + resnames.Add (prop.Logo); + } + using (var apps = Applications) + { + foreach (var app in apps) + { + foreach (var pair in app) + { + foreach (var pathres in ConstData.FilePathItems) + { + if ((pathres?.Trim ()?.ToLower () ?? "") == (pair.Key?.Trim ()?.ToLower ())) + { + resnames.Add (pair.Value); + } + else if (PriFileHelper.IsMsResourcePrefix (pair.Value)) + resnames.Add (pair.Value); + } + } + } + } + m_pri.AddSearch (resnames); + } + catch (Exception) { } + } + public PackageType Type + { + get + { + var value = PackageReadHelper.GetManifestType (m_hReader); + switch (value) + { + case 0: return PackageType.Unknown; + case 1: return PackageType.Appx; + case 2: return PackageType.Bundle; + } + return PackageType.Unknown; + } + } + public PackageRole Role + { + get + { + var value = PackageReadHelper.GetManifestRole (m_hReader); + switch (value) + { + case 0: return PackageRole.Unknown; + case 1: return PackageRole.Application; + case 2: return PackageRole.Framework; + case 3: return PackageRole.Resource; + } + return PackageRole.Unknown; + } + } + public bool IsApplicationManifest { get { return Role == PackageRole.Application; } } + public bool IsValid { get { return m_hReader != IntPtr.Zero && Type != PackageType.Unknown; } } + /// 使用 PRI,启用后会预先处理 PRI 文件。 + public bool UsePri { get { return m_usePRI; } set { m_usePRI = value; InitPri (); } } + /// 允许 PRI,启用后会返回读取的 PRI 文件结果,需保证 UsePri 开启。 + public bool EnablePri { get { return m_enablePRI; } set { m_enablePRI = value; } } + public MRIdentity Identity { get { return new MRIdentity (ref m_hReader); } } + public MRProperties Properties { get { return new MRProperties (ref m_hReader, this, ref m_pri, ref m_usePRI, ref m_enablePRI); } } + public MRPrerequisites Prerequisites { get { return new MRPrerequisites (ref m_hReader); } } + public MRResources Resources { get { return new MRResources (ref m_hReader); } } + public MRApplications Applications { get { return new MRApplications (ref m_hReader, this, ref m_pri, ref m_usePRI, ref m_enablePRI); } } + public MRCapabilities Capabilities { get { return new MRCapabilities (ref m_hReader); } } + public MRDependencies Dependencies { get { return new MRDependencies (ref m_hReader); } } + public void Dispose () + { + if (m_hReader != IntPtr.Zero) + { + PackageReadHelper.DestroyManifestReader (m_hReader); + m_hReader = IntPtr.Zero; + } + var lastvalue = m_usePRI; + m_usePRI = false; + InitPri (); + m_usePRI = lastvalue; + } + ~ManifestReader () { Dispose (); } + public string FilePath + { + get + { + return m_filePath; + } + set + { + PackageReadHelper.LoadManifestFromFile (m_hReader, m_filePath = value); + } + } + public ManifestReader (string filePath) { FilePath = filePath; } + public ManifestReader () { } + public string JSONText { get { return BuildJsonText (); } } + public string BuildJsonText () + { + var obj = BuildJsonObject (); + return Newtonsoft.Json.JsonConvert.SerializeObject ( + obj, + Newtonsoft.Json.Formatting.Indented + ); + } + private object BuildJsonObject () + { + return new + { + valid = IsValid, + filepath = FilePath, + type = (int)Type, + role = (int)Role, + identity = Identity.BuildJSON (), + properties = Properties.BuildJSON (), + prerequisites = Prerequisites.BuildJSON (), + resources = Resources.BuildJSON (), + capabilities = Capabilities.BuildJSON (), + dependencies = Dependencies.BuildJSON (), + applications = Applications.BuildJSON () + }; + } + } +} diff --git a/AppxPackage/PackageManager.cs b/AppxPackage/PackageManager.cs index 3e33dfc..307f077 100644 --- a/AppxPackage/PackageManager.cs +++ b/AppxPackage/PackageManager.cs @@ -77,7 +77,8 @@ namespace AppxPackage private string familyName = ""; private string fullName = ""; private string resourceId = ""; - public PMIdentity (string _name, string _publisher, DataUtils.Version _ver, IEnumerable _archs, string _family, string _full, string _resid) + private string publisherId = ""; + public PMIdentity (string _name, string _publisher, DataUtils.Version _ver, IEnumerable _archs, string _family, string _full, string _resid, string _publisherId) { name = _name; publisher = _publisher; @@ -86,6 +87,7 @@ namespace AppxPackage familyName = _family; fullName = _full; resourceId = _resid; + publisherId = _publisherId; } public PMIdentity (PackageManageHelper.FIND_PACKAGE_ID pkgId) : this ( @@ -95,7 +97,8 @@ namespace AppxPackage new Architecture [] { (Architecture)pkgId.wProcessArchitecture }, Marshal.PtrToStringUni (pkgId.lpFamilyName), Marshal.PtrToStringUni (pkgId.lpFullName), - Marshal.PtrToStringUni (pkgId.lpResourceId) + Marshal.PtrToStringUni (pkgId.lpResourceId), + Marshal.PtrToStringUni (pkgId.lpPublisherId) ) { } public string FamilyName => familyName; @@ -103,8 +106,9 @@ namespace AppxPackage public string Name => name; public List ProcessArchitecture => archs.ToList (); public string Publisher => publisher; + public string PublisherId => publisherId; public string ResourceId => resourceId; - DataUtils.Version IIdentity.Version => version; + public DataUtils.Version Version => version; } [ComVisible (true)] [ClassInterface (ClassInterfaceType.AutoDual)] diff --git a/AppxPackage/PackageReader.cs b/AppxPackage/PackageReader.cs index e2bd163..a2ca103 100644 --- a/AppxPackage/PackageReader.cs +++ b/AppxPackage/PackageReader.cs @@ -104,10 +104,10 @@ namespace AppxPackage [ClassInterface (ClassInterfaceType.AutoDual)] public class BaseInfoSectWithPRI: BaseInfoSection { - protected Ref m_reader = null; - protected Ref m_priBundle = null; - protected Ref m_usePri = false; - protected Ref m_enablePri = false; + protected Ref m_reader = new Ref (null); + protected Ref m_priBundle = new Ref (null); + protected Ref m_usePri = new Ref (false); + protected Ref m_enablePri = new Ref (false); public BaseInfoSectWithPRI (ref IntPtr hReader, PackageReader reader, ref PriReaderBundle priBundle, ref bool usePri, ref bool enablePri) : base (ref hReader) { m_reader.Set (reader); @@ -1168,7 +1168,7 @@ namespace AppxPackage public PackageReader (string filePath) { FilePath = filePath; } public PackageReader () { } public string JSONText { get { return BuildJsonText (); } } - private string BuildJsonText () + public string BuildJsonText () { var obj = BuildJsonObject (); return Newtonsoft.Json.JsonConvert.SerializeObject ( diff --git a/AppxPackage/PkgReadNative.cs b/AppxPackage/PkgReadNative.cs index a26f1d4..2dea4de 100644 --- a/AppxPackage/PkgReadNative.cs +++ b/AppxPackage/PkgReadNative.cs @@ -210,7 +210,8 @@ namespace NativeWrappers string s = Marshal.PtrToStringUni (nativePtr); try { - crt_free (nativePtr); + PackageReaderFreeString (nativePtr); + nativePtr = IntPtr.Zero; } catch { @@ -303,5 +304,103 @@ namespace NativeWrappers { } } + // ================= Manifest Reader ================= + + [DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)] + public static extern IntPtr CreateManifestReader (); + + [DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)] + [return: MarshalAs (UnmanagedType.Bool)] + public static extern bool LoadManifestFromFile ( + IntPtr hReader, + string lpFilePath + ); + + [DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)] + public static extern void DestroyManifestReader (IntPtr hReader); + + [DllImport (DllName, CallingConvention = CallConv)] + public static extern ushort GetManifestType (IntPtr hReader); + + [DllImport (DllName, CallingConvention = CallConv)] + [return: MarshalAs (UnmanagedType.Bool)] + public static extern bool IsManifestValid (IntPtr hReader); + + [DllImport (DllName, CallingConvention = CallConv)] + public static extern ushort GetManifestRole (IntPtr hReader); + [DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)] + public static extern IntPtr GetManifestIdentityStringValue ( + IntPtr hReader, + uint dwName + ); + + [DllImport (DllName, CallingConvention = CallConv)] + [return: MarshalAs (UnmanagedType.Bool)] + public static extern bool GetManifestIdentityVersion ( + IntPtr hReader, + out VERSION pVersion + ); + + [DllImport (DllName, CallingConvention = CallConv)] + [return: MarshalAs (UnmanagedType.Bool)] + public static extern bool GetManifestIdentityArchitecture ( + IntPtr hReader, + out DWORD pdwArchi + ); + [DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)] + public static extern IntPtr GetManifestPropertiesStringValue ( + IntPtr hReader, + string lpName + ); + + [DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)] + public static extern HRESULT GetManifestPropertiesBoolValue ( + IntPtr hReader, + string lpName, + out BOOL pRet + ); + [DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)] + [return: MarshalAs (UnmanagedType.Bool)] + public static extern bool AddManifestApplicationItemGetName (string lpName); + + [DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)] + [return: MarshalAs (UnmanagedType.Bool)] + public static extern bool RemoveManifestApplicationItemGetName (string lpName); + + [DllImport (DllName, CallingConvention = CallConv)] + public static extern IntPtr GetManifestApplications (IntPtr hReader); + + [DllImport (DllName, CallingConvention = CallConv)] + public static extern void DestroyManifestApplications (IntPtr hEnumerator); + [DllImport (DllName, CallingConvention = CallConv)] + public static extern IntPtr GetManifestResourcesLanguages (IntPtr hReader); + + [DllImport (DllName, CallingConvention = CallConv)] + public static extern IntPtr GetManifestResourcesLanguagesToLcid (IntPtr hReader); + + [DllImport (DllName, CallingConvention = CallConv)] + public static extern IntPtr GetManifestResourcesScales (IntPtr hReader); + + [DllImport (DllName, CallingConvention = CallConv)] + public static extern DWORD GetManifestResourcesDxFeatureLevels (IntPtr hReader); + [DllImport (DllName, CallingConvention = CallConv)] + public static extern IntPtr GetManifestDependencesInfoList (IntPtr hReader); + + [DllImport (DllName, CallingConvention = CallConv)] + public static extern IntPtr GetManifestCapabilitiesList (IntPtr hReader); + + [DllImport (DllName, CallingConvention = CallConv)] + public static extern IntPtr GetManifestDeviceCapabilitiesList (IntPtr hReader); + + [DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)] + [return: MarshalAs (UnmanagedType.Bool)] + public static extern bool GetManifestPrerequisite ( + IntPtr hReader, + string lpName, + out VERSION pVerRet + ); + [DllImport (DllName, CallingConvention = CallConv)] + public static extern void PackageReaderFreeString (IntPtr p); + } } \ No newline at end of file diff --git a/AppxPackage/PriFileNative.cs b/AppxPackage/PriFileNative.cs index c8886c1..008fb74 100644 --- a/AppxPackage/PriFileNative.cs +++ b/AppxPackage/PriFileNative.cs @@ -57,11 +57,13 @@ namespace AppxPackage [DllImport (DLL, CallingConvention = CallingConvention.Cdecl)] [return: MarshalAs (UnmanagedType.Bool)] public static extern bool IsMsResourceUri ([MarshalAs (UnmanagedType.LPWStr)] string pResUri); + [DllImport (DLL, CallingConvention = CallingConvention.Cdecl)] + public static extern void PriFormatFreeString (IntPtr ptr); public static string PtrToString (IntPtr ptr) { if (ptr == IntPtr.Zero) return null; string s = Marshal.PtrToStringUni (ptr); - Marshal.FreeHGlobal (ptr); // 如果 DLL 返回的内存要求 free + PriFormatFreeString (ptr); // 如果 DLL 返回的内存要求 free return s; } [DllImport (DLL, CallingConvention = CallingConvention.Cdecl)] diff --git a/Bridge/SysInit.cs b/Bridge/SysInit.cs index 0f57ca8..5789cec 100644 --- a/Bridge/SysInit.cs +++ b/Bridge/SysInit.cs @@ -496,6 +496,8 @@ namespace Bridge { public AppxPackage.PackageReader Reader (string packagePath) { return new AppxPackage.PackageReader (packagePath); } public _I_PackageManager Manager => new _I_PackageManager (); + public AppxPackage.ManifestReader Manifest (string manifestPath) { return new AppxPackage.ManifestReader (manifestPath); } + public AppxPackage.ManifestReader FromInstallLocation (string installLocation) { return Manifest (Path.Combine (installLocation, "AppxManifest.xml")); } } [ComVisible (true)] [ClassInterface (ClassInterfaceType.AutoDual)] diff --git a/DataUtils/SysInit.cs b/DataUtils/SysInit.cs index cf79e0b..5bddabf 100644 --- a/DataUtils/SysInit.cs +++ b/DataUtils/SysInit.cs @@ -5,7 +5,7 @@ using System.Runtime.InteropServices; namespace DataUtils { - internal static class VisualElementsStore + public static class VisualElementsStore { // Publicly accessible instances for internal use public static readonly VisualElementManifest Vemanifest; diff --git a/DataUtils/Theme.cs b/DataUtils/Theme.cs index cca9ebe..b588ede 100644 --- a/DataUtils/Theme.cs +++ b/DataUtils/Theme.cs @@ -186,17 +186,6 @@ namespace DataUtils if (string.IsNullOrWhiteSpace (colorStr)) return Color.Transparent; string s = colorStr.Trim (); - // Named color - try - { - Color byName = Color.FromName (s); - if (byName.IsKnownColor || byName.IsNamedColor) - { - return byName; - } - } - catch { /* ignore */ } - // Hex: #RGB, #RRGGBB, #AARRGGBB if (s.StartsWith ("#")) { @@ -321,6 +310,17 @@ namespace DataUtils } } + // Named color + try + { + Color byName = Color.FromName (s); + if (byName.IsKnownColor || byName.IsNamedColor) + { + return byName; + } + } + catch { /* ignore */ } + // fallback: try parse as known color again (case-insensitive) try { diff --git a/Manager/Manager.csproj b/Manager/Manager.csproj index aafaa79..32c9304 100644 --- a/Manager/Manager.csproj +++ b/Manager/Manager.csproj @@ -53,6 +53,7 @@ ManagerShell.cs + @@ -66,6 +67,7 @@ True Resources.resx + True diff --git a/Manager/ManagerShell.Designer.cs b/Manager/ManagerShell.Designer.cs index 2f08544..fb6828d 100644 --- a/Manager/ManagerShell.Designer.cs +++ b/Manager/ManagerShell.Designer.cs @@ -40,6 +40,7 @@ this.PageScale = 125; this.Text = "Form1"; this.Load += new System.EventHandler(this.ManagerShell_Load); + this.Resize += new System.EventHandler(this.ManagerShell_Resize); this.ResumeLayout(false); } diff --git a/Manager/ManagerShell.cs b/Manager/ManagerShell.cs index 4fb81bd..8b3d53e 100644 --- a/Manager/ManagerShell.cs +++ b/Manager/ManagerShell.cs @@ -14,12 +14,82 @@ namespace Manager public ManagerShell () { InitializeComponent (); - SplashScreen.SplashBackgroundColor = Color.Honeydew; + try + { + var relativePath = DataUtils.VisualElementsStore.Vemanifest.SplashScreenImage (Program.g_appId); + var img = Image.FromFile (relativePath); + SplashScreen.SplashImage = img; + } catch (Exception e) { + var ex = e; + } + try + { + SplashScreen.SplashBackgroundColor = DataUtils.UITheme.StringToColor (DataUtils.VisualElementsStore.Vemanifest.SplashScreenBackgroundColor (Program.g_appId)); + } + catch { } + InitSize (); + } + private void InitSize () + { + uint ww = 0, wh = 0; + var ini = Bridge.InitFileStore.Config; + var setsect = ini ["Settings"]; + var savepos = setsect.GetKey ("PackageManager:SavePosAndSizeBeforeCancel"); + var lastw = setsect.GetKey ("PackageManager:LastWidth"); + var lasth = setsect.GetKey ("PackageManager:LastHeight"); + var defw = setsect.GetKey ("PackageManager:DefaultWidth"); + var defh = setsect.GetKey ("PackageManager:DefaultHeight"); + var minw = setsect.GetKey ("PackageManager:MinimumWidth"); + var minh = setsect.GetKey ("PackageManager:MinimumHeight"); + var lasts = setsect.GetKey ("PackageManager:LastWndState"); + if (savepos.ReadBool ()) + { + ww = lastw.ReadUInt (defw.ReadUInt (Properties.Resources.IDS_DEFAULTWIDTH.ParseTo ())); + wh = lasth.ReadUInt (defh.ReadUInt (Properties.Resources.IDS_DEFAULTHEIGHT.ParseTo ())); + } + else + { + ww = defw.ReadUInt (Properties.Resources.IDS_DEFAULTWIDTH.ParseTo ()); + wh = defh.ReadUInt (Properties.Resources.IDS_DEFAULTHEIGHT.ParseTo ()); + } + ClientSize = new Size ((int)(ww * DataUtils.UITheme.DPIDouble), (int)(wh * DataUtils.UITheme.DPIDouble)); + int hborder = Size.Width - ClientSize.Width, + vborder = Size.Height - ClientSize.Height; + MinimumSize = new Size ( + (int)(minw.ReadUInt (Properties.Resources.IDS_MINWIDTH.ParseTo ()) * DataUtils.UITheme.DPIDouble) + hborder, + (int)(minh.ReadUInt (Properties.Resources.IDS_MINHEIGHT.ParseTo ()) * DataUtils.UITheme.DPIDouble) + vborder + ); + WindowState = (FormWindowState)lasts.ReadInt ((int)FormWindowState.Normal); } private void ManagerShell_Load (object sender, EventArgs e) { var root = Path.GetDirectoryName (DataUtils.Utilities.GetCurrentProgramPath ()); WebUI.Navigate (Path.Combine (root, "html\\manager.html")); + var pkg = new AppxPackage.PackageReader (@"F:\新建文件夹 (2)\9E2F88E3.Twitter_1.1.13.8_x86__wgeqdkkx372wm.appx"); + pkg.EnablePri = true; + pkg.UsePri = true; + var displayName = pkg.Properties.LogoBase64; + } + private void ManagerShell_Resize (object sender, EventArgs e) + { + var ini = Bridge.InitFileStore.Config; + var setsect = ini ["Settings"]; + var savepos = setsect.GetKey ("PackageManager:SavePosAndSizeBeforeCancel"); + var lastw = setsect.GetKey ("PackageManager:LastWidth"); + var lasth = setsect.GetKey ("PackageManager:LastHeight"); + var lasts = setsect.GetKey ("PackageManager:LastWndState"); + switch (WindowState) + { + case FormWindowState.Normal: + case FormWindowState.Maximized: + lasts.Write ((int)WindowState); + break; + } + if (WindowState == FormWindowState.Normal && savepos.ReadBool ()) + { + lastw.Write ((int)(ClientSize.Width / DataUtils.UITheme.DPIDouble)); + lasth.Write ((int)(ClientSize.Height / DataUtils.UITheme.DPIDouble)); + } } } } diff --git a/Manager/Polyfill.cs b/Manager/Polyfill.cs new file mode 100644 index 0000000..ce8beea --- /dev/null +++ b/Manager/Polyfill.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.Linq; +using System.Text; + +namespace Manager +{ + public static class Polyfill + { + public static T ParseTo (this string src, T dflt = default (T)) + { + if (string.IsNullOrWhiteSpace (src)) return dflt; + try + { + Type targetType = typeof (T); + Type underlying = Nullable.GetUnderlyingType (targetType); + if (underlying != null) + { + object v = Convert.ChangeType (src, underlying, CultureInfo.InvariantCulture); + return (T)v; + } + if (targetType.IsEnum) + { + object enumValue = Enum.Parse (targetType, src, true); + return (T)enumValue; + } + TypeConverter converter = TypeDescriptor.GetConverter (targetType); + if (converter != null && converter.CanConvertFrom (typeof (string))) + { + object v = converter.ConvertFrom (null, CultureInfo.InvariantCulture, src); + return (T)v; + } + } + catch { } + return dflt; + } + } +} diff --git a/Manager/Program.cs b/Manager/Program.cs index 25ccbad..fdd20ad 100644 --- a/Manager/Program.cs +++ b/Manager/Program.cs @@ -7,6 +7,8 @@ namespace Manager { static class Program { + static public readonly string g_appUserId = "WindowsModern.PracticalToolsProject!Manager"; + static public readonly string g_appId = "Manager"; /// /// 应用程序的主入口点。 /// diff --git a/Manager/Properties/Resources.Designer.cs b/Manager/Properties/Resources.Designer.cs index d0cd4f2..e47740d 100644 --- a/Manager/Properties/Resources.Designer.cs +++ b/Manager/Properties/Resources.Designer.cs @@ -1,71 +1,99 @@ //------------------------------------------------------------------------------ // // 此代码由工具生成。 -// 运行时版本: 4.0.30319.42000 +// 运行时版本:4.0.30319.42000 // -// 对此文件的更改可能导致不正确的行为,如果 -// 重新生成代码,则所做更改将丢失。 +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 // //------------------------------------------------------------------------------ -namespace Manager.Properties -{ - - - /// - /// 强类型资源类,用于查找本地化字符串等。 - /// - // 此类是由 StronglyTypedResourceBuilder - // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 - // 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen - // (以 /str 作为命令选项),或重新生成 VS 项目。 - [global::System.CodeDom.Compiler.GeneratedCodeAttribute ("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute ()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute ()] - internal class Resources - { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute ("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources () - { - } - - /// - /// 返回此类使用的缓存 ResourceManager 实例。 - /// - [global::System.ComponentModel.EditorBrowsableAttribute (global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if ((resourceMan == null)) - { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager ("Manager.Properties.Resources", typeof (Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// 覆盖当前线程的 CurrentUICulture 属性 - /// 使用此强类型的资源类的资源查找。 - /// - [global::System.ComponentModel.EditorBrowsableAttribute (global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { - return resourceCulture; - } - set - { - resourceCulture = value; - } - } - } +namespace Manager.Properties { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Manager.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 使用此强类型资源类,为所有资源查找 + /// 重写当前线程的 CurrentUICulture 属性。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 查找类似 600 的本地化字符串。 + /// + internal static string IDS_DEFAULTHEIGHT { + get { + return ResourceManager.GetString("IDS_DEFAULTHEIGHT", resourceCulture); + } + } + + /// + /// 查找类似 800 的本地化字符串。 + /// + internal static string IDS_DEFAULTWIDTH { + get { + return ResourceManager.GetString("IDS_DEFAULTWIDTH", resourceCulture); + } + } + + /// + /// 查找类似 412 的本地化字符串。 + /// + internal static string IDS_MINHEIGHT { + get { + return ResourceManager.GetString("IDS_MINHEIGHT", resourceCulture); + } + } + + /// + /// 查找类似 504 的本地化字符串。 + /// + internal static string IDS_MINWIDTH { + get { + return ResourceManager.GetString("IDS_MINWIDTH", resourceCulture); + } + } + } } diff --git a/Manager/Properties/Resources.resx b/Manager/Properties/Resources.resx index af7dbeb..60b27a0 100644 --- a/Manager/Properties/Resources.resx +++ b/Manager/Properties/Resources.resx @@ -46,7 +46,7 @@ mimetype: application/x-microsoft.net.object.binary.base64 value : The object must be serialized with - : System.Serialization.Formatters.Binary.BinaryFormatter + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter : and then encoded with base64 encoding. mimetype: application/x-microsoft.net.object.soap.base64 @@ -60,6 +60,7 @@ : and then encoded with base64 encoding. --> + @@ -68,9 +69,10 @@ - + + @@ -85,9 +87,10 @@ - + + @@ -109,9 +112,25 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 600 + 默认窗口高度 + + + 800 + 默认窗口宽度 + + + 412 + 默认最小窗口高度 + + + 504 + 默认最小窗口宽度 + \ No newline at end of file diff --git a/Manager/app.manifest b/Manager/app.manifest index 7db33c3..b0b2bcf 100644 --- a/Manager/app.manifest +++ b/Manager/app.manifest @@ -8,16 +8,16 @@ 如果想要更改 Windows 用户帐户控制级别,请使用 以下节点之一替换 requestedExecutionLevel 节点。n - + --> - + - + diff --git a/PrivateInit/Win32.cs b/PrivateInit/Win32.cs index d9159e5..dd7a15a 100644 --- a/PrivateInit/Win32.cs +++ b/PrivateInit/Win32.cs @@ -186,7 +186,7 @@ namespace Win32 public object Get (string section, string key, object dflt) => GetKey (section, key).Get (dflt); public object Get (string section, string key) => GetKey (section, key).Get (); public bool Set (string section, string key, object value) => GetKey (section, key).Set (value); - public object this [string key] => GetSection (key); + public InitSection this [string key] => GetSection (key); public string [] GetAllSections () { var sections = new System.Collections.Generic.List (); diff --git a/Release.7z b/Release.7z new file mode 100644 index 0000000..abc7095 Binary files /dev/null and b/Release.7z differ diff --git a/WAShell/Properties/Resources.Designer.cs b/WAShell/Properties/Resources.Designer.cs new file mode 100644 index 0000000..fafc8ee --- /dev/null +++ b/WAShell/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace WAShell.Properties { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WAShell.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 使用此强类型资源类,为所有资源查找 + /// 重写当前线程的 CurrentUICulture 属性。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/WAShell/Properties/Resources.resx b/WAShell/Properties/Resources.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/WAShell/Properties/Resources.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/WAShell/SplashForm.Designer.cs b/WAShell/SplashForm.Designer.cs index 771ec4e..93f1c50 100644 --- a/WAShell/SplashForm.Designer.cs +++ b/WAShell/SplashForm.Designer.cs @@ -38,6 +38,7 @@ // this.picbox.Anchor = System.Windows.Forms.AnchorStyles.None; this.picbox.BackColor = System.Drawing.Color.Transparent; + this.picbox.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; this.picbox.Location = new System.Drawing.Point(6, 47); this.picbox.Name = "picbox"; this.picbox.Size = new System.Drawing.Size(620, 300); diff --git a/WAShell/SplashForm.cs b/WAShell/SplashForm.cs index e3b911e..385ce19 100644 --- a/WAShell/SplashForm.cs +++ b/WAShell/SplashForm.cs @@ -87,9 +87,9 @@ namespace WAShell set { splashImage = value; - if (picbox != null && picbox.IsHandleCreated) + if (picbox != null) { - picbox.Image = splashImage; + try { picbox.Image = splashImage; } catch { } } } } diff --git a/WAShell/WAShell.csproj b/WAShell/WAShell.csproj index 5c4b0a2..3665537 100644 --- a/WAShell/WAShell.csproj +++ b/WAShell/WAShell.csproj @@ -42,6 +42,11 @@ + + True + True + Resources.resx + Form @@ -78,6 +83,10 @@ + + ResXFileCodeGenerator + Resources.Designer.cs + SplashForm.cs diff --git a/pkgmgr/pkgmgr.cpp b/pkgmgr/pkgmgr.cpp index 2de779a..dea8dd2 100644 --- a/pkgmgr/pkgmgr.cpp +++ b/pkgmgr/pkgmgr.cpp @@ -298,10 +298,10 @@ struct pkg_info pi.users += sid; } { - std::wstring sid; - WAPParseSetStringValue (sid, it->UserSecurityId); + std::wstring sid2; + WAPParseSetStringValue (sid2, it->UserSecurityId); if (i) pi.sids += L';'; - pi.sids += sid; + pi.sids += sid2; } i ++; } @@ -857,4 +857,149 @@ HRESULT FindAppxPackagesByFamilyName (LPCWSTR lpPkgFamilyName, PKGMGR_FINDENUMCA void PackageManagerFreeString (LPWSTR lpString) { if (lpString) free (lpString); -} \ No newline at end of file +} +[STAThread] +HRESULT CreateAppDataManager (LPCWSTR lpFamilyName, HWRTAPPDATA *ppApplicationData, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + g_swExceptionCode = L""; + g_swExceptionDetail = L""; + try + { + auto adm = ApplicationDataManager::CreateForPackageFamily (ref new String (lpFamilyName ? lpFamilyName : L"")); + auto insp = reinterpret_cast (adm); + insp->AddRef (); + if (ppApplicationData) *ppApplicationData = (HWRTAPPDATA)insp; + return S_OK; + } + catch (AccessDeniedException ^e) + { + g_swExceptionDetail = e->ToString ()->Data (); + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return (SUCCEEDED ((HRESULT)e->HResult) ? E_FAIL : (HRESULT)e->HResult); + } + catch (Exception ^e) + { + g_swExceptionDetail = e->ToString ()->Data (); + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return (SUCCEEDED ((HRESULT)e->HResult) ? E_FAIL : (HRESULT)e->HResult); + } + catch (const std::exception &e) + { + g_swExceptionDetail = StringToWString (e.what () ? e.what () : "Unknown exception."); + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return E_FAIL; + } + catch (...) + { + g_swExceptionDetail = L"Unknown exception"; + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return E_FAIL; + } + return E_FAIL; +} +HRESULT RunAsyncActionOperation (Windows::Foundation::IAsyncAction ^asyncAction, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + g_swExceptionCode.clear (); + g_swExceptionDetail.clear (); + if (pErrorCode) *pErrorCode = nullptr; + if (pDetailMsg) *pDetailMsg = nullptr; + if (!asyncAction) return E_POINTER; + HANDLE hCompEvt = CreateEventExW ( + nullptr, + nullptr, + CREATE_EVENT_MANUAL_RESET, + EVENT_ALL_ACCESS + ); + if (!hCompEvt) return HRESULT_FROM_WIN32 (GetLastError ()); + auto closeEvt = destruct ([&] () { + CloseHandle (hCompEvt); + }); + try + { + asyncAction->Completed = + ref new Windows::Foundation::AsyncActionCompletedHandler ( + [&hCompEvt] ( + Windows::Foundation::IAsyncAction^, + Windows::Foundation::AsyncStatus) + { + SetEvent (hCompEvt); + }); + WaitForSingleObject (hCompEvt, INFINITE); + switch (asyncAction->Status) + { + case Windows::Foundation::AsyncStatus::Completed: return S_OK; + case Windows::Foundation::AsyncStatus::Canceled: + g_swExceptionDetail = L"Async action was canceled."; + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return E_ABORT; + case Windows::Foundation::AsyncStatus::Error: + { + auto err = asyncAction->ErrorCode; + HRESULT hr = (HRESULT)err.Value; + auto errStr = Platform::Exception::CreateException (err.Value)->ToString (); + if (errStr && errStr->Data ()) g_swExceptionCode = errStr->Data (); + if (pErrorCode) *pErrorCode = _wcsdup (g_swExceptionCode.c_str ()); + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return hr; + } + default: return E_FAIL; + } + } + catch (Platform::Exception^ e) + { + g_swExceptionDetail = e->ToString ()->Data (); + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return e->HResult; + } + catch (const std::exception& e) + { + g_swExceptionDetail = StringToWString (e.what () ? e.what () : "Unknown exception."); + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return E_FAIL; + } + catch (...) + { + g_swExceptionDetail = L"Unknown exception."; + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return E_FAIL; + } +} +#define HWRTAppDataToAppData(pInspectable) \ + safe_cast (reinterpret_cast (pInspectable)) +[MTAThread] +HRESULT WRTAppDataClearAll (HWRTAPPDATA hAppData, LPWSTR *pErrorCode, LPWSTR *pDetailMsg) +{ + g_swExceptionCode = L""; + g_swExceptionDetail = L""; + try + { + ApplicationData ^appData = HWRTAppDataToAppData (hAppData, appData, pErrorCode, pDetailMsg); + if (appData == nullptr) return E_FAIL; + return RunAsyncActionOperation (appData->ClearAsync (), pErrorCode, pDetailMsg); + } + catch (AccessDeniedException ^e) + { + g_swExceptionDetail = e->ToString ()->Data (); + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return (SUCCEEDED ((HRESULT)e->HResult) ? E_FAIL : (HRESULT)e->HResult); + } + catch (Exception ^e) + { + g_swExceptionDetail = e->ToString ()->Data (); + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return (SUCCEEDED ((HRESULT)e->HResult) ? E_FAIL : (HRESULT)e->HResult); + } + catch (const std::exception &e) + { + g_swExceptionDetail = StringToWString (e.what () ? e.what () : "Unknown exception."); + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return E_FAIL; + } + catch (...) + { + g_swExceptionDetail = L"Unknown exception"; + if (pDetailMsg) *pDetailMsg = _wcsdup (g_swExceptionDetail.c_str ()); + return E_FAIL; + } + return E_FAIL; +} diff --git a/pkgmgr/pkgmgr.h b/pkgmgr/pkgmgr.h index ca53289..3dec0ae 100644 --- a/pkgmgr/pkgmgr.h +++ b/pkgmgr/pkgmgr.h @@ -194,6 +194,15 @@ extern "C" PKGMGR_API HRESULT FindAppxPackagesByFamilyName (LPCWSTR lpPkgFamilyName, PKGMGR_FINDENUMCALLBACK pfCallback, void *pCustom _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pErrorCode _DEFAULT_INIT_VALUE_FORFUNC_ (NULL), LPWSTR *pDetailMsg _DEFAULT_INIT_VALUE_FORFUNC_ (NULL)); // ͷ pkgmgr.dll صĶַ̬ PKGMGR_API void PackageManagerFreeString (LPWSTR lpString); +#ifndef TEMPLATE_STRUCT +#define TEMPLATE_STRUCT(_typename_) typedef struct _typename_##__ _typename_ +#endif // ! TEMPLATE_STRUCT + TEMPLATE_STRUCT (WRTAPPDATA); + typedef WRTAPPDATA *HWRTAPPDATA; + // Ӧݹͨ Package Family Name + PKGMGR_API HRESULT CreateAppDataManager (LPCWSTR lpFamilyName, HWRTAPPDATA *ppApplicationData, LPWSTR *pErrorCode, LPWSTR *pDetailMsg); + // ӱءκʱӦݴ洢ɾӦóݡ + PKGMGR_API HRESULT WRTAppDataClearAll (HWRTAPPDATA hAppData, LPWSTR *pErrorCode, LPWSTR *pDetailMsg); #ifdef _DEFAULT_INIT_VALUE_ #undef _DEFAULT_INIT_VALUE_ #endif diff --git a/pkgmgr/stdafx.h b/pkgmgr/stdafx.h index c2220a4..1c04af3 100644 --- a/pkgmgr/stdafx.h +++ b/pkgmgr/stdafx.h @@ -32,3 +32,5 @@ using namespace Platform; using namespace Windows::Foundation; using namespace Windows::Management::Deployment; +using namespace Windows::Management::Core; +using namespace Windows::Storage; diff --git a/pkgread/pkgread.cpp b/pkgread/pkgread.cpp index ff4436d..db21d1d 100644 --- a/pkgread/pkgread.cpp +++ b/pkgread/pkgread.cpp @@ -1213,4 +1213,544 @@ LPWSTR GetPackageCapabilityDisplayName (LPCWSTR lpCapabilityName) std::wstring ret = GetCapabilityDisplayName (capname); if (IsNormalizeStringEmpty (ret)) return nullptr; else return _wcsdup (ret.c_str ()); -} \ No newline at end of file +} + +void PackageReaderFreeString (LPWSTR lpStrFromThisDll) +{ + if (!lpStrFromThisDll) return; + free (lpStrFromThisDll); +} + +// ========== Ƕ嵥ļĶȡ ========== +#define ToHandleMRead(_cpp_ptr_) reinterpret_cast (_cpp_ptr_) +#define ToPtrManifest(_cpp_ptr_) reinterpret_cast (_cpp_ptr_) +HPKGMANIFESTREAD CreateManifestReader () { return ToHandleMRead (new manifest ()); } +BOOL LoadManifestFromFile (_In_ HPKGMANIFESTREAD hReader, _In_ LPCWSTR lpFilePath) +{ + auto ptr = ToPtrManifest (hReader); + if (!ptr) return false; + return ptr->create (lpFilePath); +} +void DestroyManifestReader (_In_ HPKGMANIFESTREAD hReader) +{ + auto ptr = ToPtrManifest (hReader); + if (!ptr) return; + return delete ptr; +} +WORD GetManifestType (_In_ HPKGMANIFESTREAD hReader) +{ + auto ptr = ToPtrManifest (hReader); + if (!ptr) return PKGTYPE_UNKNOWN; + switch (ptr->type ()) + { + case PackageType::unknown: return PKGTYPE_UNKNOWN; + case PackageType::single: return PKGTYPE_APPX; + case PackageType::bundle: return PKGTYPE_BUNDLE; + } + return PKGTYPE_UNKNOWN; +} +BOOL IsManifestValid (_In_ HPKGMANIFESTREAD hReader) +{ + auto ptr = ToPtrManifest (hReader); + if (!ptr) return false; + return ptr->valid (); +} +WORD GetManifestRole (_In_ HPKGMANIFESTREAD hReader) +{ + auto ptr = ToPtrManifest (hReader); + if (!ptr) return PKGROLE_UNKNOWN; + switch (ptr->type ()) + { + case PackageType::unknown: return PKGROLE_UNKNOWN; + case PackageType::bundle: return PKGROLE_APPLICATION; + case PackageType::single: { + auto ar = ptr->appx_reader (); + switch (ar.package_role ()) + { + case PackageRole::unknown: return PKGROLE_UNKNOWN; + case PackageRole::application: return PKGROLE_APPLICATION; + case PackageRole::framework: return PKGROLE_FRAMEWORK; + case PackageRole::resource: return PKGROLE_RESOURCE; + } + } break; + } + return PKGROLE_UNKNOWN; +} +// Identity +LPWSTR GetManifestIdentityStringValue (_In_ HPKGMANIFESTREAD hReader, _In_ DWORD dwName) +{ + auto ptr = ToPtrManifest (hReader); + if (!ptr) return nullptr; + switch (ptr->type ()) + { + case PackageType::single: { + auto reader = ptr->appx_reader (); + auto id = reader.identity (); + switch (LOWORD (dwName)) + { + case PKG_IDENTITY_NAME: return _wcsdup (id.name ().c_str ()); + case PKG_IDENTITY_PUBLISHER: return _wcsdup (id.publisher ().c_str ()); + case PKG_IDENTITY_PACKAGEFAMILYNAME: return _wcsdup (id.package_family_name ().c_str ()); + case PKG_IDENTITY_PACKAGEFULLNAME: return _wcsdup (id.package_full_name ().c_str ()); + case PKG_IDENTITY_RESOURCEID: return _wcsdup (id.resource_id ().c_str ()); + } + } break; + case PackageType::bundle: { + auto reader = ptr->bundle_reader (); + auto id = reader.identity (); + { + switch (LOWORD (dwName)) + { + case PKG_IDENTITY_NAME: return _wcsdup (id.name ().c_str ()); + case PKG_IDENTITY_PUBLISHER: return _wcsdup (id.publisher ().c_str ()); + case PKG_IDENTITY_PACKAGEFAMILYNAME: return _wcsdup (id.package_family_name ().c_str ()); + case PKG_IDENTITY_PACKAGEFULLNAME: return _wcsdup (id.package_full_name ().c_str ()); + case PKG_IDENTITY_RESOURCEID: return _wcsdup (id.resource_id ().c_str ()); + } + } + } break; + } + return nullptr; +} +BOOL GetManifestIdentityVersion (_In_ HPKGMANIFESTREAD hReader, _Out_ VERSION *pVersion) +{ + auto ptr = ToPtrManifest (hReader); + if (!ptr) return FALSE; + if (!pVersion) return FALSE; + switch (ptr->type ()) + { + case PackageType::single: { + auto reader = ptr->appx_reader (); + auto id = reader.identity (); + auto ver = id.version (); + *pVersion = VersionClassToStruct (ver); + return !ver.empty (); + } break; + case PackageType::bundle: { + auto reader = ptr->bundle_reader (); + auto id = reader.identity (); + { + auto ver = id.version (); + *pVersion = VersionClassToStruct (ver); + return !ver.empty (); + } + } break; + } + return FALSE; +} +BOOL GetManifestIdentityArchitecture (_In_ HPKGMANIFESTREAD hReader, _Out_ DWORD *pdwArchi) +{ + auto ptr = ToPtrManifest (hReader); + if (!ptr) return FALSE; + if (!pdwArchi) return FALSE; + switch (ptr->type ()) + { + case PackageType::single: { + auto reader = ptr->appx_reader (); + auto id = reader.identity (); + auto archi = id.architecture (); + DWORD ret = 0; + switch (archi) + { + case APPX_PACKAGE_ARCHITECTURE::APPX_PACKAGE_ARCHITECTURE_X86: + ret = PKG_ARCHITECTURE_X86; break; + case APPX_PACKAGE_ARCHITECTURE::APPX_PACKAGE_ARCHITECTURE_ARM: + ret = PKG_ARCHITECTURE_ARM; break; + case APPX_PACKAGE_ARCHITECTURE::APPX_PACKAGE_ARCHITECTURE_X64: + ret = PKG_ARCHITECTURE_X64; break; + case APPX_PACKAGE_ARCHITECTURE::APPX_PACKAGE_ARCHITECTURE_NEUTRAL: + ret = PKG_ARCHITECTURE_NEUTRAL; break; + case (APPX_PACKAGE_ARCHITECTURE)12: // ARM64 + ret = PKG_ARCHITECTURE_ARM64; break; + } + *pdwArchi = ret; + return ret != PKG_ARCHITECTURE_UNKNOWN; + } break; + case PackageType::bundle: { + auto reader = ptr->bundle_reader (); + auto ids = reader.package_id_items (); + std::vector apps; + ids.application_packages (apps); + DWORD ret = 0; + for (auto &it : apps) + { + auto id = it.identity (); + auto archi = id.architecture (); + switch (archi) + { + case APPX_PACKAGE_ARCHITECTURE::APPX_PACKAGE_ARCHITECTURE_X86: + ret |= PKG_ARCHITECTURE_X86; break; + case APPX_PACKAGE_ARCHITECTURE::APPX_PACKAGE_ARCHITECTURE_ARM: + ret |= PKG_ARCHITECTURE_ARM; break; + case APPX_PACKAGE_ARCHITECTURE::APPX_PACKAGE_ARCHITECTURE_X64: + ret |= PKG_ARCHITECTURE_X64; break; + case APPX_PACKAGE_ARCHITECTURE::APPX_PACKAGE_ARCHITECTURE_NEUTRAL: + ret |= PKG_ARCHITECTURE_NEUTRAL; break; + case (APPX_PACKAGE_ARCHITECTURE)12: // ARM64 + ret |= PKG_ARCHITECTURE_ARM64; break; + } + } + *pdwArchi = ret; + return ret != PKG_ARCHITECTURE_UNKNOWN; + } break; + } + return FALSE; +} +// Properties +LPWSTR GetManifestPropertiesStringValue (_In_ HPKGMANIFESTREAD hReader, _In_ LPCWSTR lpName) +{ + auto ptr = ToPtrManifest (hReader); + if (!ptr) return nullptr; + switch (ptr->type ()) + { + case PackageType::single: { + auto reader = ptr->appx_reader (); + auto prop = reader.properties (); + return _wcsdup (prop.string_value (lpName ? lpName : L"").c_str ()); + } break; + } + return nullptr; +} +HRESULT GetManifestPropertiesBoolValue (_In_ HPKGMANIFESTREAD hReader, _In_ LPCWSTR lpName, _Outptr_ BOOL *pRet) +{ + auto ptr = ToPtrManifest (hReader); + if (!ptr) return E_INVALIDARG; + if (!pRet) return E_INVALIDARG; + *pRet = FALSE; + switch (ptr->type ()) + { + case PackageType::single: { + auto reader = ptr->appx_reader (); + IAppxManifestReader *m = reader.manifest (); + if (!m) return E_FAIL; + CComPtr p; + HRESULT hr = m->GetProperties (&p); + if (FAILED (hr)) return hr; + return p->GetBoolValue (lpName, pRet); + } break; + } + return E_FAIL; +} +// Applications +BOOL AddManifestApplicationItemGetName (_In_ LPCWSTR lpName) +{ + if (std::wnstring (lpName ? lpName : L"").empty ()) return FALSE; + return PushApplicationAttributeItem (lpName); +} +BOOL RemoveManifestApplicationItemGetName (_In_ LPCWSTR lpName) +{ + if (std::wnstring (lpName ? lpName : L"").empty ()) return FALSE; + return RemoveApplicationAttributeItem (lpName); +} +HAPPENUMERATOR GetManifestApplications (_In_ HPKGMANIFESTREAD hReader) +{ + auto ptr = ToPtrManifest (hReader); + if (!ptr) return nullptr; + switch (ptr->type ()) + { + case PackageType::single: { + auto reader = ptr->appx_reader (); + auto app = reader.applications (); + auto appvec = new app_enumerator (); + app.applications (*appvec); + return ToHandleAppEnumerator (appvec); + } break; + } + return nullptr; +} +void DestroyManifestApplications (_In_ HAPPENUMERATOR hEnumerator) +{ + auto ptr = ToPtrAppxApps (hEnumerator); + if (ptr) delete ptr; +} +// Resources +HLIST_PVOID GetManifestResourcesLanguages (_In_ HPKGMANIFESTREAD hReader) +{ + auto ptr = ToPtrManifest (hReader); + if (!ptr) return nullptr; + std::vector langs; + switch (ptr->type ()) + { + case PackageType::single: + { + auto reader = ptr->appx_reader (); + auto res = reader.resources (); + res.languages (langs); + break; + } + case PackageType::bundle: + { + auto br = ptr->bundle_reader (); + auto res = br.package_id_items (); + res.enumerate ([&langs] (IAppxBundleManifestPackageInfo *inf) { + auto item = appx_info::appx_iditem (inf); + std::vector l; + auto qr = item.qualified_resources (); + qr.languages (l); + for (auto &it : l) push_unique (langs, it); + }); + break; + } + default: return nullptr; + } + if (langs.empty ()) return nullptr; + size_t count = langs.size (); + size_t bytes = sizeof (LIST_PVOID) + sizeof (LPWSTR) * (count - 1); + auto list = (HLIST_PVOID)malloc (bytes); + ZeroMemory (list, bytes); + if (!list) return nullptr; + list->dwSize = 0; + for (auto &it : langs) list->alpVoid [list->dwSize ++] = _wcsdup (it.c_str ()); + return list; +} +HLIST_LCID GetManifestResourcesLanguagesToLcid (_In_ HPKGMANIFESTREAD hReader) +{ + auto ptr = ToPtrManifest (hReader); + if (!ptr) return nullptr; + std::vector langs; + switch (ptr->type ()) + { + case PackageType::single: + { + auto reader = ptr->appx_reader (); + auto res = reader.resources (); + res.languages (langs); + break; + } + case PackageType::bundle: + { + auto br = ptr->bundle_reader (); + auto res = br.package_id_items (); + res.enumerate ([&langs] (IAppxBundleManifestPackageInfo *inf) { + auto item = appx_info::appx_iditem (inf); + std::vector l; + auto qr = item.qualified_resources (); + qr.languages (l); + for (auto &it : l) push_unique (langs, it); + }); + break; + } + default: return nullptr; + } + if (langs.empty ()) return nullptr; + size_t len = sizeof (LIST_LCID) + sizeof (LCID) * langs.size (); + HLIST_LCID hList = (HLIST_LCID)malloc (len); + ZeroMemory (hList, len); + hList->dwSize = 0; + for (auto &it : langs) + { + LCID lcid = LocaleCodeToLcid (it); + if (lcid) + { + hList->aLcid [hList->dwSize ++] = lcid; + } + } + return hList; +} +HLIST_UINT32 GetManifestResourcesScales (_In_ HPKGMANIFESTREAD hReader) + +{ + auto ptr = ToPtrManifest (hReader); + if (!ptr) return nullptr; + std::vector scales; + switch (ptr->type ()) + { + case PackageType::single: + { + auto reader = ptr->appx_reader (); + auto res = reader.resources (); + res.scales (scales); + break; + } + case PackageType::bundle: + { + auto br = ptr->bundle_reader (); + auto res = br.package_id_items (); + res.enumerate ([&scales] (IAppxBundleManifestPackageInfo *inf) { + auto item = appx_info::appx_iditem (inf); + std::vector s; + auto qr = item.qualified_resources (); + qr.scales (s); + for (auto &it : s) push_unique (scales, it); + }); + break; + } + default: return nullptr; + } + if (scales.empty ()) return nullptr; + size_t len = sizeof (LIST_UINT32) + sizeof (UINT32) * scales.size (); + HLIST_UINT32 hList = (HLIST_UINT32)malloc (len); + ZeroMemory (hList, len); + hList->dwSize = 0; + for (auto &it : scales) + { + if (!it) continue; + hList->aUI32 [hList->dwSize ++] = it; + } + return hList; +} +DWORD GetManifestResourcesDxFeatureLevels (_In_ HPKGMANIFESTREAD hReader) + +{ + auto ptr = ToPtrManifest (hReader); + if (!ptr) return 0; + DWORD dwFlags = 0; + switch (ptr->type ()) + { + case PackageType::single: + { + auto reader = ptr->appx_reader (); + auto res = reader.resources (); + std::vector dxlevels; + res.dx_feature_level (dxlevels); + for (auto &it : dxlevels) + { + switch (it) + { + case DX_FEATURE_LEVEL::DX_FEATURE_LEVEL_9: + dwFlags |= PKG_RESOURCES_DXFEATURE_LEVEL9; break; + case DX_FEATURE_LEVEL::DX_FEATURE_LEVEL_10: + dwFlags |= PKG_RESOURCES_DXFEATURE_LEVEL10; break; + case DX_FEATURE_LEVEL::DX_FEATURE_LEVEL_11: + dwFlags |= PKG_RESOURCES_DXFEATURE_LEVEL11; break; + case (DX_FEATURE_LEVEL)4: + dwFlags |= PKG_RESOURCES_DXFEATURE_LEVEL12; break; + } + } + break; + } + case PackageType::bundle: + { + auto br = ptr->bundle_reader (); + auto res = br.package_id_items (); + res.enumerate ([&dwFlags] (IAppxBundleManifestPackageInfo *inf) { + auto item = appx_info::appx_iditem (inf); + std::vector dxlevels; + auto qr = item.qualified_resources (); + qr.dx_feature_level (dxlevels); + for (auto &it : dxlevels) + { + switch (it) + { + case DX_FEATURE_LEVEL::DX_FEATURE_LEVEL_9: + dwFlags |= PKG_RESOURCES_DXFEATURE_LEVEL9; break; + case DX_FEATURE_LEVEL::DX_FEATURE_LEVEL_10: + dwFlags |= PKG_RESOURCES_DXFEATURE_LEVEL10; break; + case DX_FEATURE_LEVEL::DX_FEATURE_LEVEL_11: + dwFlags |= PKG_RESOURCES_DXFEATURE_LEVEL11; break; + case (DX_FEATURE_LEVEL)4: + dwFlags |= PKG_RESOURCES_DXFEATURE_LEVEL12; break; + } + } + }); + break; + } + default: return 0; + } + return dwFlags; +} +// Dependencies +HLIST_DEPINFO GetManifestDependencesInfoList (_In_ HPKGMANIFESTREAD hReader) +{ + auto ptr = ToPtrManifest (hReader); + if (!ptr) return nullptr; + std::vector vec; + switch (ptr->type ()) + { + case PackageType::single: { + auto reader = ptr->appx_reader (); + auto deps = reader.dependencies (); + deps.dependencies (vec); + } break; + } + size_t len = sizeof (LIST_DEPINFO) + sizeof (DEPENDENCY_INFO) * vec.size (); + HLIST_DEPINFO hList = (HLIST_DEPINFO)malloc (len); + ZeroMemory (hList, len); + hList->dwSize = 0; + for (auto &it : vec) + { + auto &dep = hList->aDepInfo [hList->dwSize ++]; + dep.lpName = _wcsdup (it.name.c_str ()); + dep.lpPublisher = _wcsdup (it.publisher.c_str ()); + dep.verMin = VersionClassToStruct (it.minversion); + } + return hList; +} +// Capabilities +HLIST_PVOID GetManifestCapabilitiesList (_In_ HPKGMANIFESTREAD hReader) +{ + auto ptr = ToPtrManifest (hReader); + if (!ptr) return nullptr; + std::vector caps; + switch (ptr->type ()) + { + case PackageType::single: { + auto reader = ptr->appx_reader (); + auto cap = reader.capabilities (); + std::vector vec; + cap.capabilities_names (vec); + for (auto &it : vec) + { + auto cname = std::wnstring (it.c_str ()); + if (cname.empty ()) continue; + push_unique (caps, cname); + } + } break; + } + size_t len = sizeof (LIST_PVOID) + sizeof (LPWSTR) * caps.size (); + HLIST_PVOID hList = (HLIST_PVOID)malloc (len); + ZeroMemory (hList, len); + hList->dwSize = 0; + for (auto &it : caps) + { + hList->alpVoid [hList->dwSize ++] = (LPVOID)_wcsdup (it.c_str ()); + } + return hList; +} +HLIST_PVOID GetManifestDeviceCapabilitiesList (_In_ HPKGMANIFESTREAD hReader) +{ + auto ptr = ToPtrManifest (hReader); + if (!ptr) return nullptr; + std::vector caps; + switch (ptr->type ()) + { + case PackageType::single: { + auto reader = ptr->appx_reader (); + auto cap = reader.capabilities (); + std::vector vec; + cap.device_capabilities (vec); + for (auto &it : vec) + { + auto cname = std::wnstring (it.c_str ()); + if (cname.empty ()) continue; + push_unique (caps, cname); + } + } break; + } + size_t len = sizeof (LIST_PVOID) + sizeof (LPWSTR) * caps.size (); + HLIST_PVOID hList = (HLIST_PVOID)malloc (len); + ZeroMemory (hList, len); + hList->dwSize = 0; + for (auto &it : caps) + { + hList->alpVoid [hList->dwSize ++] = (LPVOID)_wcsdup (it.c_str ()); + } + return hList; +} +// Prerequisite +BOOL GetManifestPrerequisite (_In_ HPKGMANIFESTREAD hReader, _In_ LPCWSTR lpName, _Outptr_ VERSION *pVerRet) +{ + auto ptr = ToPtrManifest (hReader); + if (!ptr) return FALSE; + switch (ptr->type ()) + { + case PackageType::single: { + auto reader = ptr->appx_reader (); + auto pre = reader.prerequisites (); + auto ver = pre.get_version (lpName ? lpName : L""); + *pVerRet = VersionClassToStruct (ver); + return !ver.empty (); + } break; + } + return FALSE; +} diff --git a/pkgread/pkgread.h b/pkgread/pkgread.h index f5d4df7..42c62a3 100644 --- a/pkgread/pkgread.h +++ b/pkgread/pkgread.h @@ -87,7 +87,7 @@ extern "C" #define PKGROLE_APPLICATION 1 #define PKGROLE_FRAMEWORK 2 #define PKGROLE_RESOURCE 3 -// ȡ + // ȡ PKGREAD_API HPKGREAD CreatePackageReader (); // ͨȡ򿪰 PKGREAD_API BOOL LoadPackageFromFile (_In_ HPKGREAD hReader, _In_ LPCWSTR lpFilePath); @@ -286,6 +286,155 @@ extern "C" // ȡʾ internetClient Ӧ Internet ӡصӦϵͳԵı // ע⣺صַһҪͨ free ͷš PKGREAD_API LPWSTR GetPackageCapabilityDisplayName (LPCWSTR lpCapabilityName); + // ͷŴӱзصַ + // ʵͨ free ͷżɣǵ⣬ôд˸ + PKGREAD_API void PackageReaderFreeString (LPWSTR lpStrFromThisDll); + + // ========= Ӧ嵥ĶȡһЩ͵Ǹõ ========= + + TEMPLATE_STRUCT (PKGMANIFESTREAD); + typedef PKGMANIFESTREAD *HPKGMANIFESTREAD; + // Manifest ȡ + // һ Manifest Reader ʼ״̬δκļ + PKGREAD_API HPKGMANIFESTREAD CreateManifestReader (); + // ļ Manifest + // ֵ֧룺 + // - AppxManifest.xml + // - .appx / .msix + // - .appxbundle / .msixbundle + // سɹ󣬶ȡԶʶ Manifest ͡ + PKGREAD_API BOOL LoadManifestFromFile (_In_ HPKGMANIFESTREAD hReader, _In_ LPCWSTR lpFilePath); + // ļ Manifest + // ֵ֧룺 + // - AppxManifest.xml + // - .appx / .msix + // - .appxbundle / .msixbundle + // سɹ󣬶ȡԶʶ Manifest ͡ + PKGREAD_API BOOL LoadManifestFromFile (_In_ HPKGMANIFESTREAD hReader, _In_ LPCWSTR lpFilePath); + // Manifest ȡã + // ͷڲԴڴ֮󲻿ʹá + PKGREAD_API void DestroyManifestReader (_In_ HPKGMANIFESTREAD hReader); + // ȡ Manifest ͡ + // ֵ + // - PKGTYPE_APPX һ Appx / Msix + // - PKGTYPE_BUNDLE AppxBundle / MsixBundle + // - PKGTYPE_UNKNOWN δ֪δ + PKGREAD_API WORD GetManifestType (_In_ HPKGMANIFESTREAD hReader); + // ȡ Manifest ͡ + // ֵ + // - PKGTYPE_APPX һ Appx / Msix + // - PKGTYPE_BUNDLE AppxBundle / MsixBundle + // - PKGTYPE_UNKNOWN δ֪δ + PKGREAD_API WORD GetManifestType (_In_ HPKGMANIFESTREAD hReader); + // ж Manifest ǷЧ + // Manifest ʧܡṹǷδأ FALSE + PKGREAD_API BOOL IsManifestValid (_In_ HPKGMANIFESTREAD hReader); + // ȡ Manifest ʾĽɫ + // ֵ + // - PKGROLE_APPLICATION Ӧð + // - PKGROLE_FRAMEWORK ܰ + // - PKGROLE_RESOURCE Դ + // - PKGROLE_UNKNOWN δ֪ + // + // ˵ + // - AppxBundleԶ PKGROLE_APPLICATION + PKGREAD_API WORD GetManifestRole (_In_ HPKGMANIFESTREAD hReader); + // ȡ Identity ֶַΡ + // dwName ȡֵ + // - PKG_IDENTITY_NAME + // - PKG_IDENTITY_PUBLISHER + // - PKG_IDENTITY_PACKAGEFAMILYNAME + // - PKG_IDENTITY_PACKAGEFULLNAME + // - PKG_IDENTITY_RESOURCEID + // + // ֵ + // - ɹ·ַ߸ͷţ + // - ʧܣ NULL + PKGREAD_API LPWSTR GetManifestIdentityStringValue (_In_ HPKGMANIFESTREAD hReader, _In_ DWORD dwName); +#define GetManifestIdentityName(_In_hReader_) GetManifestIdentityStringValue (_In_hReader_, PKG_IDENTITY_NAME) +#define GetManifestIdentityPublisher(_In_hReader_) GetManifestIdentityStringValue (_In_hReader_, PKG_IDENTITY_PUBLISHER) +#define GetManifestIdentityPackageFamilyName(_In_hReader_) GetManifestIdentityStringValue (_In_hReader_, PKG_IDENTITY_PACKAGEFAMILYNAME) +#define GetManifestIdentityPackageFullName(_In_hReader_) GetManifestIdentityStringValue (_In_hReader_, PKG_IDENTITY_PACKAGEFULLNAME) +#define GetManifestIdentityResourceId(_In_hReader_) GetManifestIdentityStringValue (_In_hReader_, PKG_IDENTITY_RESOURCEID) + // ȡ Identity İ汾š + // + // pVersion ظʽ VERSION ṹ + // ֵ + // - TRUE ɹ + // - FALSE ʧܻ汾 + PKGREAD_API BOOL GetManifestIdentityVersion (_In_ HPKGMANIFESTREAD hReader, _Out_ VERSION *pVersion); + // ȡֵ֧ļܹϢ + // ڵһ Appx صһܹ + // BundleӰܹϣλ򣩡 + // + // ֵͨ pdwArchi ȡֵΪ PKG_ARCHITECTURE_* ꡣ + PKGREAD_API BOOL GetManifestIdentityArchitecture (_In_ HPKGMANIFESTREAD hReader, _Out_ DWORD *pdwArchi); + // ȡ Properties еֵַ + // lpName Ϊ "DisplayName" + // ֵ + // - ɹ·ַ߸ͷţ + // - ʧܣ NULL + // + // ˵ + // - ڵһ Appx + PKGREAD_API LPWSTR GetManifestPropertiesStringValue (_In_ HPKGMANIFESTREAD hReader, _In_ LPCWSTR lpName); + // ȡ Properties еIJֵ + // + // pRet ز + // HRESULTʧԭ + // + // ˵ + // - ڵһ Appx + PKGREAD_API HRESULT GetManifestPropertiesBoolValue (_In_ HPKGMANIFESTREAD hReader, _In_ LPCWSTR lpName, _Outptr_ BOOL *pRet); + // ӦöҪȡ Application + // FALSE ʾǷظ + PKGREAD_API BOOL AddManifestApplicationItemGetName (_In_ LPCWSTR lpName); + // ӦöƳָ Application + PKGREAD_API BOOL RemoveManifestApplicationItemGetName (_In_ LPCWSTR lpName); + // ȡ Applications ö + // һӦöֶ١ + // + // ˵ + // - ڵһ Appx + PKGREAD_API HAPPENUMERATOR GetManifestApplications (_In_ HPKGMANIFESTREAD hReader); + // Applications ö + PKGREAD_API void DestroyManifestApplications (_In_ HAPPENUMERATOR hEnumerator); + // ȡԴֵ֧бַʽ + // HLIST_PVOIDڲԪΪ LPWSTR + PKGREAD_API HLIST_PVOID GetManifestResourcesLanguages (_In_ HPKGMANIFESTREAD hReader); + // ȡԴֵ֧бLCID ʽ + // HLIST_LCID + PKGREAD_API HLIST_LCID GetManifestResourcesLanguagesToLcid (_In_ HPKGMANIFESTREAD hReader); + // ȡԴֵ֧űScale + // HLIST_UINT32 + PKGREAD_API HLIST_UINT32 GetManifestResourcesScales (_In_ HPKGMANIFESTREAD hReader); + // ȡԴֵ֧ DirectX Feature Level + // ֵΪ PKG_RESOURCES_DXFEATURE_LEVEL* λϡ + PKGREAD_API DWORD GetManifestResourcesDxFeatureLevels (_In_ HPKGMANIFESTREAD hReader); + // ȡϢб + // HLIST_DEPINFOаơ߼Ͱ汾 + // + // ˵ + // - ڵһ Appx + PKGREAD_API HLIST_DEPINFO GetManifestDependencesInfoList (_In_ HPKGMANIFESTREAD hReader); + // ȡ Capability бCapability + // صбԪΪ LPWSTR + // + // ˵ + // - ڵһ Appx + PKGREAD_API HLIST_PVOID GetManifestCapabilitiesList (_In_ HPKGMANIFESTREAD hReader); + // ȡ Device Capability б + // صбԪΪ LPWSTR + // + // ˵ + // - ڵһ Appx + PKGREAD_API HLIST_PVOID GetManifestDeviceCapabilitiesList (_In_ HPKGMANIFESTREAD hReader); + // ȡָǰͰ汾Ҫ + // lpName Ϊǰơ + // pVerRet ذ汾ṹ + // TRUE ʾڸǰ + PKGREAD_API BOOL GetManifestPrerequisite (_In_ HPKGMANIFESTREAD hReader, _In_ LPCWSTR lpName, _Outptr_ VERSION *pVerRet); + #ifdef _DEFAULT_INIT_VALUE_ #undef _DEFAULT_INIT_VALUE_ #endif diff --git a/pkgread/readobj.h b/pkgread/readobj.h index fbb603a..813d0f0 100644 --- a/pkgread/readobj.h +++ b/pkgread/readobj.h @@ -1336,3 +1336,202 @@ class package appxreader appx_reader () const { return appxreader (*(IAppxPackageReader **)&this->appx); } bundlereader bundle_reader () const { return bundlereader (*(IAppxBundleReader **)&this->bundle); } }; + +class appxmanifest: virtual public com_info_quote +{ + using Base = com_info_quote ; + template HRESULT get (IComPtr iptr, Fn func, ReturnType *retvalue) const { if (!iptr) return E_FAIL; return (iptr->*func) (retvalue); } + using Manifest = IAppxManifestReader; + public: + using Base::Base; + Manifest *manifest () { return pointer (); } + template HRESULT get_from_manifest (Func fn, _Outptr_ IComPtr *output) const + { + if (!pointer ()) return E_FAIL; + return get (pointer (), fn, output); + } + HRESULT get_identity (_Outptr_ IAppxManifestPackageId **output) const { return get_from_manifest (&Manifest::GetPackageId, output); } + appx_info::appx_id identity () const + { + IAppxManifestPackageId *ip = nullptr; + get_identity (&ip); + return appx_info::appx_id (ip); + } + appx_info::appx_res resources () const + { + return appx_info::appx_res (pointer ()); + } + HRESULT get_properties (_Outptr_ IAppxManifestProperties **output) const { return get_from_manifest (&Manifest::GetProperties, output); } + appx_info::appx_prop properties () const + { + IAppxManifestProperties *ip = nullptr; + HRESULT hr = get_properties (&ip); + return appx_info::appx_prop (ip); + } + appx_info::appx_preq prerequisites () const + { + return appx_info::appx_preq (pointer ()); + } + HRESULT get_applications (_Outptr_ IAppxManifestApplicationsEnumerator **output) const { return get_from_manifest (&Manifest::GetApplications, output); } + appx_info::appx_apps applications () const + { + IAppxManifestApplicationsEnumerator *ip = nullptr; + get_applications (&ip); + return appx_info::appx_apps (ip); + } + HRESULT get_capabilities (_Outptr_ APPX_CAPABILITIES *output) const { return get_from_manifest (&Manifest::GetCapabilities, output); } + HRESULT get_device_capabilities (_Outptr_ IAppxManifestDeviceCapabilitiesEnumerator **output) const { return get_from_manifest (&Manifest::GetDeviceCapabilities, output); } + appx_info::appx_capabs capabilities () const + { + APPX_CAPABILITIES caps; + IAppxManifestDeviceCapabilitiesEnumerator *ip = nullptr; + if (pointer ()) pointer ()->GetDeviceCapabilities (&ip); + auto im = pointer (); + if (SUCCEEDED (get_capabilities (&caps))) return appx_info::appx_capabs (ip, caps, im); + return appx_info::appx_capabs (ip); + } + HRESULT get_dependencies (_Outptr_ IAppxManifestPackageDependenciesEnumerator **output) const { return get_from_manifest (&Manifest::GetPackageDependencies, output); } + appx_info::appx_deps dependencies () const + { + IAppxManifestPackageDependenciesEnumerator *ip = nullptr; + get_dependencies (&ip); + return appx_info::appx_deps (ip); + } + PackageRole package_role () const + { + auto prop = properties (); + if (prop.framework ()) return PackageRole::framework; + try { if (prop.resource_package ()) return PackageRole::resource; } + catch (const std::exception &e) {} + auto app = applications (); + std::vector apps; + if (app.app_user_model_ids (apps)) return PackageRole::application; + else return PackageRole::unknown; + } +}; +class bundlemanifest: virtual public com_info_quote +{ + using Base = com_info_quote ; + public: + using Base::Base; + template HRESULT get (IComPtr iptr, Fn func, ReturnType *retvalue) const { if (!iptr) return E_FAIL; return (iptr->*func) (retvalue); } + using Manifest = IAppxBundleManifestReader; + Manifest *manifest () { return pointer (); } + template HRESULT get_from_manifest (Func fn, _Outptr_ IComPtr *output) const + { + if (!pointer ()) return E_FAIL; + return get (pointer (), fn, output); + } + HRESULT get_identity (_Outptr_ IAppxManifestPackageId **output) const { return get_from_manifest (&Manifest::GetPackageId, output); } + appx_info::appx_id identity () const + { + IAppxManifestPackageId *ip = nullptr; + get_identity (&ip); + return appx_info::appx_id (ip); + } + HRESULT get_package_id_items (_Outptr_ IAppxBundleManifestPackageInfoEnumerator **output) const { return get_from_manifest (&Manifest::GetPackageInfoItems, output); } + appx_info::appx_iditems package_id_items () const + { + IAppxBundleManifestPackageInfoEnumerator *ip = nullptr; + get_package_id_items (&ip); + return appx_info::appx_iditems (ip); + } +}; + +HRESULT GetAppxManifestReader (_In_ LPCWSTR inputPath, _Outptr_ IAppxManifestReader **manifestReader) +{ + if (!manifestReader) return E_POINTER; + *manifestReader = nullptr; + HRESULT hr; + CComPtr stream; + CComPtr factory; + CComPtr packageReader; + hr = SHCreateStreamOnFileEx ( + inputPath, + STGM_READ | STGM_SHARE_DENY_NONE, + FILE_ATTRIBUTE_NORMAL, + FALSE, + nullptr, + &stream + ); + if (FAILED (hr)) return hr; + hr = CoCreateInstance ( + __uuidof (AppxFactory), + nullptr, + CLSCTX_INPROC_SERVER, + IID_PPV_ARGS (&factory) + ); + if (FAILED (hr)) return hr; + hr = factory->CreatePackageReader (stream, &packageReader); + if (SUCCEEDED (hr)) + { + return packageReader->GetManifest (manifestReader); + } + hr = factory->CreateManifestReader (stream, manifestReader); + return hr; +} +HRESULT GetBundleManifestReader (_In_ LPCWSTR bundlePath, _Outptr_ IAppxBundleManifestReader **manifestReader) +{ + if (!manifestReader) return E_POINTER; + *manifestReader = nullptr; + HRESULT hr; + CComPtr stream; + CComPtr factory; + CComPtr bundleReader; + hr = SHCreateStreamOnFileEx ( + bundlePath, + STGM_READ | STGM_SHARE_DENY_NONE, + FILE_ATTRIBUTE_NORMAL, + FALSE, + nullptr, + &stream + ); + if (FAILED (hr)) return hr; + hr = CoCreateInstance ( + __uuidof(AppxBundleFactory), + nullptr, + CLSCTX_INPROC_SERVER, + IID_PPV_ARGS (&factory) + ); + if (FAILED (hr)) return hr; + hr = factory->CreateBundleReader (stream, &bundleReader); + if (FAILED (hr)) return hr; + hr = bundleReader->GetManifest (manifestReader); + if (FAILED (hr)) return hr = factory->CreateBundleManifestReader (stream, manifestReader); + return hr; +} + +class manifest +{ + IAppxManifestReader *appx = nullptr; + IAppxBundleManifestReader *bundle = nullptr; + public: + ~manifest () { destroy (); } + manifest (const std::wstring &filepath = L"") { create (filepath); } + void destroy () + { + if (appx) { appx->Release (); appx = nullptr; } + if (bundle) { bundle->Release (); bundle = nullptr; } + } + bool create (const std::wstring &filepath) + { + destroy (); + if (!IsFileExists (filepath)) return false; + HRESULT hr = GetBundleManifestReader (filepath.c_str (), &bundle); + if (SUCCEEDED (hr)) return true; + if (bundle) { bundle->Release (); bundle = nullptr; } + hr = GetAppxManifestReader (filepath.c_str (), &appx); + if (SUCCEEDED (hr)) return true; + if (appx) { appx->Release (); appx = nullptr; } + return false; + } + bool valid () const { return (bool)appx ^ (bool)bundle; } + PackageType type () const + { + if (appx) return PackageType::single; + if (bundle) return PackageType::bundle; + return PackageType::unknown; + } + appxmanifest appx_reader () const { return appxmanifest (*(IAppxManifestReader **)&this->appx); } + bundlemanifest bundle_reader () const { return bundlemanifest (*(IAppxBundleManifestReader **)&this->bundle); } +}; \ No newline at end of file diff --git a/priformatcli/priformatcli.cpp b/priformatcli/priformatcli.cpp index 8d21bfd..6407810 100644 --- a/priformatcli/priformatcli.cpp +++ b/priformatcli/priformatcli.cpp @@ -915,4 +915,10 @@ BOOL IsMsResourceUri (LPCWSTR pResUri) try { Uri ^uri = gcnew Uri (gcnew String (pResUri ? pResUri : L"")); delete uri; } catch (Exception ^e) { return false; } return true; +} + +void PriFormatFreeString (LPWSTR lpStrFromThisDll) +{ + if (!lpStrFromThisDll) return; + free (lpStrFromThisDll); } \ No newline at end of file diff --git a/priformatcli/priformatcli.h b/priformatcli/priformatcli.h index d69ca90..6a6b5b5 100644 --- a/priformatcli/priformatcli.h +++ b/priformatcli/priformatcli.h @@ -73,6 +73,8 @@ extern "C" { PRIFORMATCLI_API BOOL IsMsResourceUriFull (LPCWSTR pResUri); // ߺжǷΪ MS-Resource URI PRIFORMATCLI_API BOOL IsMsResourceUri (LPCWSTR pResUri); + // ߺͷű DLL صַ + PRIFORMATCLI_API void PriFormatFreeString (LPWSTR lpStrFromThisDll); #ifdef _DEFAULT_VALUE_SET #undef _DEFAULT_VALUE_SET #endif diff --git a/priread/ReadMe.txt b/priread/ReadMe.txt deleted file mode 100644 index 98d5062..0000000 --- a/priread/ReadMe.txt +++ /dev/null @@ -1,30 +0,0 @@ -======================================================================== - 动态链接库:priread 项目概述 -======================================================================== - -应用程序向导已为您创建了此 priread DLL。 - -本文件概要介绍组成 priread 应用程序的每个文件的内容。 - - -priread.vcxproj - 这是使用应用程序向导生成的 VC++ 项目的主项目文件,其中包含生成该文件的 Visual C++ 的版本信息,以及有关使用应用程序向导选择的平台、配置和项目功能的信息。 - -priread.vcxproj.filters - 这是使用“应用程序向导”生成的 VC++ 项目筛选器文件。它包含有关项目文件与筛选器之间的关联信息。在 IDE 中,通过这种关联,在特定节点下以分组形式显示具有相似扩展名的文件。例如,“.cpp”文件与“源文件”筛选器关联。 - -priread.cpp - 这是主 DLL 源文件。 - -///////////////////////////////////////////////////////////////////////////// -其他标准文件: - -StdAfx.h, StdAfx.cpp - 这些文件用于生成名为 priread.pch 的预编译头 (PCH) 文件和名为 StdAfx.obj 的预编译类型文件。 - -///////////////////////////////////////////////////////////////////////////// -其他注释: - -应用程序向导使用“TODO:”注释来指示应添加或自定义的源代码部分。 - -///////////////////////////////////////////////////////////////////////////// diff --git a/priread/dllmain.cpp b/priread/dllmain.cpp deleted file mode 100644 index 260abc6..0000000 --- a/priread/dllmain.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// dllmain.cpp : DLL Ӧóڵ㡣 -#include "stdafx.h" - -BOOL APIENTRY DllMain( HMODULE hModule, - DWORD ul_reason_for_call, - LPVOID lpReserved - ) -{ - switch (ul_reason_for_call) - { - case DLL_PROCESS_ATTACH: - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - case DLL_PROCESS_DETACH: - break; - } - return TRUE; -} - diff --git a/priread/localeex.h b/priread/localeex.h deleted file mode 100644 index b528d56..0000000 --- a/priread/localeex.h +++ /dev/null @@ -1,163 +0,0 @@ -#pragma once -#include -#include -static std::wstring StringToWString (const std::string &str, UINT codePage = CP_ACP) -{ - if (str.empty ()) return std::wstring (); - int len = MultiByteToWideChar (codePage, 0, str.c_str (), -1, nullptr, 0); - if (len == 0) return std::wstring (); - std::wstring wstr (len - 1, L'\0'); - MultiByteToWideChar (codePage, 0, str.c_str (), -1, &wstr [0], len); - return wstr; -} - -#undef GetLocaleInfo -std::string GetLocaleInfoA (LCID code, LCTYPE type) -{ - char buf [LOCALE_NAME_MAX_LENGTH] = {0}; - GetLocaleInfoA (code, type, buf, LOCALE_NAME_MAX_LENGTH); - return buf; -} -std::wstring GetLocaleInfoW (LCID code, LCTYPE type) -{ - WCHAR buf [LOCALE_NAME_MAX_LENGTH] = {0}; - GetLocaleInfoW (code, type, buf, LOCALE_NAME_MAX_LENGTH); - return buf; -} -void GetLocaleInfo (LCID code, LCTYPE type, std::wstring &output) -{ - output = GetLocaleInfoW (code, type); -} -void GetLocaleInfo (LCID code, LCTYPE type, std::string &output) -{ - output = GetLocaleInfoA (code, type); -} -int GetLocaleInfoEx (std::wstring lpLocaleName, LCTYPE type, std::wstring &output) -{ - WCHAR buf [LOCALE_NAME_MAX_LENGTH] = {0}; - int res = GetLocaleInfoEx (lpLocaleName.c_str (), type, buf, LOCALE_NAME_MAX_LENGTH); - if (&output) output = std::wstring (buf); - return res; -} - -#undef SetLocaleInfo -BOOL SetLocaleInfoA (LCID code, LCTYPE type, const std::string &lcData) -{ - return SetLocaleInfoA (code, type, lcData.c_str ()); -} -BOOL SetLocaleInfoW (LCID code, LCTYPE type, const std::wstring &lcData) -{ - return SetLocaleInfoW (code, type, lcData.c_str ()); -} -BOOL SetLocaleInfo (LCID code, LCTYPE type, const std::wstring &lcData) -{ - return SetLocaleInfoW (code, type, lcData); -} -BOOL SetLocaleInfo (LCID code, LCTYPE type, const std::string &lcData) -{ - return SetLocaleInfoA (code, type, lcData); -} - -std::string GetLocaleRestrictedCodeFromLcidA (LCID lcid) -{ - return GetLocaleInfoA (lcid, 89); -} -std::wstring GetLocaleRestrictedCodeFromLcidW (LCID lcid) -{ - return GetLocaleInfoW (lcid, 89); -} -void GetLocaleRestrictedCodeFromLcid (LCID lcid, std::string &ret) -{ - ret = GetLocaleRestrictedCodeFromLcidA (lcid); -} -void GetLocaleRestrictedCodeFromLcid (LCID lcid, std::wstring &ret) -{ - ret = GetLocaleRestrictedCodeFromLcidW (lcid); -} - -std::string GetLocaleElaboratedCodeFromLcidA (LCID lcid) -{ - return GetLocaleInfoA (lcid, 90); -} -std::wstring GetLocaleElaboratedCodeFromLcidW (LCID lcid) -{ - return GetLocaleInfoW (lcid, 90); -} -void GetLocaleElaboratedCodeFromLcid (LCID lcid, std::wstring &ret) -{ - ret = GetLocaleElaboratedCodeFromLcidW (lcid); -} -void GetLocaleElaboratedCodeFromLcid (LCID lcid, std::string &ret) -{ - ret = GetLocaleElaboratedCodeFromLcidA (lcid); -} - -LCID LocaleCodeToLcidW (LPCWSTR localeCode) -{ - BYTE buf [LOCALE_NAME_MAX_LENGTH * sizeof (WCHAR)] = {0}; - int res = GetLocaleInfoEx (localeCode, LOCALE_RETURN_NUMBER | LOCALE_ILANGUAGE, (LPWSTR)buf, LOCALE_NAME_MAX_LENGTH); - LCID lcid = *((LCID *)buf); - return lcid; -} -LCID LocaleCodeToLcidA (LPCSTR localeCode) -{ - std::wstring lcWide = StringToWString (std::string (localeCode)); - return LocaleCodeToLcidW (lcWide.c_str ()); -} -LCID LocaleCodeToLcid (const std::wstring &loccode) -{ - return LocaleCodeToLcidW (loccode.c_str ()); -} -LCID LocaleCodeToLcid (const std::string &loccode) -{ - return LocaleCodeToLcidA (loccode.c_str ()); -} - -std::string GetLocaleRestrictedCodeA (LPCSTR lc) -{ - return GetLocaleInfoA (LocaleCodeToLcidA (lc), 89); -} -std::string GetLocaleRestrictedCodeA (const std::string &lc) -{ - return GetLocaleInfoA (LocaleCodeToLcidA (lc.c_str ()), 89); -} -std::wstring GetLocaleRestrictedCodeW (LPCWSTR lc) -{ - return GetLocaleInfoW (LocaleCodeToLcidW (lc), 89); -} -std::wstring GetLocaleRestrictedCodeW (const std::wstring &lc) -{ - return GetLocaleInfoW (LocaleCodeToLcidW (lc.c_str ()), 89); -} -std::wstring GetLocaleRestrictedCode (const std::wstring &lc) { return GetLocaleRestrictedCodeW (lc); } -std::string GetLocaleRestrictedCode (const std::string &lc) { return GetLocaleRestrictedCodeA (lc); } - -std::string GetLocaleElaboratedCodeA (LPCSTR lc) -{ - return GetLocaleInfoA (LocaleCodeToLcidA (lc), 90); -} -std::string GetLocaleElaboratedCodeA (const std::string &lc) -{ - return GetLocaleInfoA (LocaleCodeToLcidA (lc.c_str ()), 90); -} -std::wstring GetLocaleElaboratedCodeW (LPCWSTR lc) -{ - return GetLocaleInfoW (LocaleCodeToLcidW (lc), 90); -} -std::wstring GetLocaleElaboratedCodeW (const std::wstring &lc) -{ - return GetLocaleInfoW (LocaleCodeToLcidW (lc.c_str ()), 90); -} -std::wstring GetLocaleElaboratedCode (const std::wstring &lc) { return GetLocaleElaboratedCodeW (lc); } -std::string GetLocaleElaboratedCode (const std::string &lc) { return GetLocaleElaboratedCodeA (lc); } - -std::string LcidToLocaleCodeA (LCID lcid, char divide = '-') -{ - return GetLocaleRestrictedCodeFromLcidA (lcid) + divide + GetLocaleElaboratedCodeFromLcidA (lcid); -} -std::wstring LcidToLocaleCodeW (LCID lcid, WCHAR divide = L'-') -{ - return GetLocaleRestrictedCodeFromLcidW (lcid) + divide + GetLocaleElaboratedCodeFromLcidW (lcid); -} -std::wstring LcidToLocaleCode (LCID lcid, WCHAR divide = L'-') { return LcidToLocaleCodeW (lcid, divide); } -std::string LcidToLocaleCode (LCID lcid, char divide = '-') { return LcidToLocaleCodeA (lcid, divide); } \ No newline at end of file diff --git a/priread/nstring.h b/priread/nstring.h deleted file mode 100644 index ba0e231..0000000 --- a/priread/nstring.h +++ /dev/null @@ -1,456 +0,0 @@ -#pragma once -#include -#include -#include -namespace l0km -{ - template , typename AL = std::allocator > inline std::basic_string toupper (const std::basic_string &src) - { - std::basic_string dst = src; - static const std::locale loc; - const std::ctype &ctype = std::use_facet > (loc); - for (typename std::basic_string ::size_type i = 0; i < src.size (); ++ i) - { - dst [i] = ctype.toupper (src [i]); - } - return dst; - } - template , typename AL = std::allocator > inline std::basic_string tolower (const std::basic_string &src) - { - std::basic_string dst = src; - static const std::locale loc; - const std::ctype &ctype = std::use_facet > (loc); - for (typename std::basic_string ::size_type i = 0; i < src.size (); ++ i) - { - dst [i] = ctype.tolower (src [i]); - } - return dst; - } - inline char toupper (char ch) - { - if (ch < -1) return ch; - static const std::locale loc; - return std::use_facet > (loc).toupper (ch); - } - inline char tolower (char ch) - { - if (ch < -1) return ch; - static const std::locale loc; - return std::use_facet > (loc).tolower (ch); - } - inline wchar_t toupper (wchar_t ch) - { - if (ch < -1) return ch; - static const std::locale loc; - return std::use_facet > (loc).toupper (ch); - } - inline wchar_t tolower (wchar_t ch) - { - if (ch < -1) return ch; - static const std::locale loc; - return std::use_facet > (loc).tolower (ch); - } - inline int toupper (int ch) - { - if (ch < -1) return ch; - static const std::locale loc; - return std::use_facet > (loc).toupper (ch); - } - inline int tolower (int ch) - { - if (ch < -1) return ch; - static const std::locale loc; - return std::use_facet > (loc).tolower (ch); - } -} -template bool is_blank (ct &ch) -{ - return ch == ct (' ') || ch == ct ('\t') || ch == ct ('\n'); -} -template , typename AL = std::allocator > std::basic_string NormalizeString (const std::basic_string &str, bool upper = false, bool includemidblank = false) -{ - typedef std::basic_string string_type; - string_type result; - if (str.empty ()) return result; - auto begin_it = str.begin (); - auto end_it = str.end (); - while (begin_it != end_it && is_blank (*begin_it)) ++begin_it; - while (end_it != begin_it && is_blank (*(end_it - 1))) --end_it; - bool in_space = false; - for (auto it = begin_it; it != end_it; ++ it) - { - if (is_blank (*it)) - { - if (includemidblank) - { - if (!in_space) - { - result.push_back (E (' ')); - in_space = true; - } - } - else - { - result.push_back (*it); - in_space = true; - } - } - else - { - result.push_back (*it); - in_space = false; - } - } - if (upper) return l0km::toupper (result); - else return l0km::tolower (result); -} -template , typename AL = std::allocator > bool IsNormalizeStringEquals (const std::basic_string &l, const std::basic_string &r, bool includemidblank = false) -{ - auto _local_strlen = [] (const E *p) -> size_t { - size_t cnt = 0; - while (*(p + cnt)) { cnt ++; } - return cnt; - }; - const E *pl = l.c_str (); - const E *pr = r.c_str (); - while (*pl && is_blank (*pl)) ++ pl; - while (*pr && is_blank (*pr)) ++ pr; - const E *el = l.c_str () + _local_strlen (l.c_str ()); - const E *er = r.c_str () + _local_strlen (r.c_str ()); - while (el > pl && is_blank (*(el - 1))) --el; - while (er > pr && is_blank (*(er - 1))) --er; - while (pl < el && pr < er) - { - if (includemidblank) - { - if (is_blank (*pl) && is_blank (*pr)) - { - while (pl < el && is_blank (*pl)) ++pl; - while (pr < er && is_blank (*pr)) ++pr; - continue; - } - else if (is_blank (*pl)) - { - while (pl < el && is_blank (*pl)) ++pl; - continue; - } - else if (is_blank (*pr)) - { - while (pr < er && is_blank (*pr)) ++pr; - continue; - } - } - if (l0km::tolower (*pl) != l0km::tolower (*pr)) return false; - ++ pl; - ++ pr; - } - while (pl < el && is_blank (*pl)) ++ pl; - while (pr < er && is_blank (*pr)) ++ pr; - return pl == el && pr == er; -} -template , typename AL = std::allocator > int64_t NormalizeStringCompare (const std::basic_string &l, const std::basic_string &r, bool includemidblank = false) -{ - auto _local_strlen = [] (const E *p) -> size_t { - size_t cnt = 0; - while (*(p + cnt)) { cnt ++; } - return cnt; - }; - const E *pl = l.c_str (); - const E *pr = r.c_str (); - while (*pl && is_blank (*pl)) ++ pl; - while (*pr && is_blank (*pr)) ++ pr; - const E *el = l.c_str () + _local_strlen (l.c_str ()); - const E *er = r.c_str () + _local_strlen (r.c_str ()); - while (el > pl && is_blank (*(el - 1))) -- el; - while (er > pr && is_blank (*(er - 1))) -- er; - while (pl < el && pr < er) - { - if (includemidblank) - { - if (is_blank (*pl) && is_blank (*pr)) - { - while (pl < el && is_blank (*pl)) ++pl; - while (pr < er && is_blank (*pr)) ++pr; - continue; - } - else if (is_blank (*pl)) - { - while (pl < el && is_blank (*pl)) ++pl; - continue; - } - else if (is_blank (*pr)) - { - while (pr < er && is_blank (*pr)) ++pr; - continue; - } - } - E chl = l0km::tolower (*pl); - E chr = l0km::tolower (*pr); - if (chl != chr) return (int64_t)chl - (int64_t)chr; - ++ pl; - ++ pr; - } - while (pl < el && is_blank (*pl)) ++ pl; - while (pr < er && is_blank (*pr)) ++ pr; - if (pl == el && pr == er) return 0; - if (pl == el) return -1; - if (pr == er) return 1; - return (int64_t)l0km::tolower (*pl) - (int64_t)l0km::tolower (*pr); -} -template bool IsNormalizeStringEquals (const CharT *l, const CharT *r, bool includemidblank = false) -{ - if (!l || !r) return l == r; - auto skip_blank = [] (const CharT *&p) - { - while (*p && is_blank (*p)) ++ p; - }; - const CharT *p1 = l; - const CharT *p2 = r; - skip_blank (p1); - skip_blank (p2); - while (*p1 && *p2) - { - CharT ch1 = l0km::tolower (*p1); - CharT ch2 = l0km::tolower (*p2); - if (ch1 != ch2) return false; - ++ p1; - ++ p2; - if (includemidblank) - { - if (is_blank (*p1) || is_blank (*p2)) - { - skip_blank (p1); - skip_blank (p2); - } - } - } - skip_blank (p1); - skip_blank (p2); - return *p1 == 0 && *p2 == 0; -} -template int64_t NormalizeStringCompare (const CharT *l, const CharT *r, bool includemidblank = false) -{ - if (!l || !r) return l ? 1 : (r ? -1 : 0); - auto skip_blank = [] (const CharT *&p) - { - while (*p && is_blank (*p)) ++ p; - }; - const CharT *p1 = l; - const CharT *p2 = r; - skip_blank (p1); - skip_blank (p2); - while (*p1 && *p2) - { - CharT ch1 = l0km::tolower (*p1); - CharT ch2 = l0km::tolower (*p2); - if (ch1 != ch2) return (ch1 < ch2) ? -1 : 1; - ++ p1; - ++ p2; - if (includemidblank) - { - if (is_blank (*p1) || is_blank (*p2)) - { - skip_blank (p1); - skip_blank (p2); - } - } - } - skip_blank (p1); - skip_blank (p2); - if (*p1 == 0 && *p2 == 0) return 0; - if (*p1 == 0) return -1; - return 1; -} -template , typename AL = std::allocator > bool IsNormalizeStringEmpty (const std::basic_string &str) -{ - return IsNormalizeStringEquals (str, std::basic_string ()); -} -template , typename AL = std::allocator > std::basic_string StringTrim (const std::basic_string &str, bool includemidblank = false) -{ - typedef std::basic_string string_type; - typedef typename string_type::size_type size_type; - if (str.empty ()) return string_type (); - size_type first = 0; - size_type last = str.size (); - while (first < last && is_blank (str [first])) ++first; - while (last > first && is_blank (str [last - 1])) --last; - if (first == last) return string_type (); - string_type result; - result.reserve (last - first); - bool in_space = false; - for (size_type i = first; i < last; ++ i) - { - if (is_blank (str [i])) - { - if (includemidblank) - { - if (!in_space) - { - result.push_back (E (' ')); - in_space = true; - } - } - else - { - result.push_back (str [i]); - in_space = true; - } - } - else - { - result.push_back (str [i]); - in_space = false; - } - } - return result; -} -template , typename AL = std::allocator > size_t GetNormalizeStringLength (const std::basic_string &str, bool includemidblank = false) -{ - typedef typename std::basic_string ::size_type size_type; - if (str.empty ()) return 0; - size_type first = 0, last = str.size (); - while (first < last && is_blank (str [first])) ++first; - while (last > first && is_blank (str [last - 1])) --last; - if (first == last) return 0; - size_t length = 0; - bool in_space = false; - for (size_type i = first; i < last; ++i) - { - if (is_blank (str [i])) - { - if (includemidblank) - { - if (!in_space) - { - ++ length; - in_space = true; - } - } - else - { - ++ length; - in_space = true; - } - } - else - { - ++ length; - in_space = false; - } - } - return length; -} -namespace std -{ - - template , typename al = std::allocator > class basic_nstring: public std::basic_string - { - using base = std::basic_string ; - bool default_upper = false, default_include_blank_in_str = false; - public: - using typename base::size_type; - using typename base::value_type; - using base::base; - basic_nstring (): base (), default_upper (false), default_include_blank_in_str (false) {} - basic_nstring (const ct *pStr): base (pStr), default_upper (false), default_include_blank_in_str (false) {} - basic_nstring (const base &str): base (str) {} - basic_nstring (base &&str): base (std::move (str)) {} - basic_nstring (const ct *data, size_type count): base (data, count), default_upper (false), default_include_blank_in_str (false) {} - template basic_nstring (const ct (&arr) [N]) : base (arr, N) {} - template basic_nstring (InputIt first, InputIt last): base (first, last), default_upper (false), default_include_blank_in_str (false) {} - bool upper_default () const { return this->default_upper; } - bool upper_default (bool value) { return this->default_upper = value; } - bool include_blank_in_str_middle () const { return this->default_include_blank_in_str; } - bool include_blank_in_str_middle (bool value) { return this->default_include_blank_in_str = value; } - base normalize (bool upper, bool includemidblank) const - { - return NormalizeString (*this, upper, includemidblank); - } - base normalize (bool upper) const - { - return this->normalize (upper, default_include_blank_in_str); - } - base normalize () const { return this->normalize (default_upper); } - base upper (bool includemidblank) const - { - return NormalizeString (*this, true, includemidblank); - } - base upper () const { return this->upper (default_include_blank_in_str); } - base lower (bool includemidblank) const - { - return NormalizeString (*this, false, includemidblank); - } - base lower () const { return this->lower (default_include_blank_in_str); } - base trim (bool includemidblank) const - { - return StringTrim (*this, includemidblank); - } - base trim () const { return this->trim (default_include_blank_in_str); } - size_t length (bool includemidblank) const { return GetNormalizeStringLength (*this, includemidblank); } - size_t length () const { return length (default_include_blank_in_str); } - bool empty () const - { - return IsNormalizeStringEmpty (*this); - } - bool equals (const base &another, bool includemidblank) const - { - return IsNormalizeStringEquals (*this, another, includemidblank); - } - bool equals (const base &another) const { return equals (another, default_include_blank_in_str); } - int64_t compare (const base &another, bool includemidblank) const - { - return NormalizeStringCompare (*this, another, includemidblank); - } - int64_t compare (const base &another) const { return compare (another, default_include_blank_in_str); } - base &string () { return *this; } - base to_string (bool upper, bool includemidblank) const { return this->normalize (upper, includemidblank); } - base to_string (bool upper) const { return this->normalize (upper, default_include_blank_in_str); } - base to_string () const { return this->normalize (default_upper); } - bool operator == (const base &other) const { return equals (other, false); } - bool operator != (const base &other) const { return !equals (other, false); } - bool operator < (const base &other) const { return compare (other, false) < 0; } - bool operator > (const base &other) const { return compare (other, false) > 0; } - bool operator <= (const base &other) const { return compare (other, false) <= 0; } - bool operator >= (const base &other) const { return compare (other, false) >= 0; } - int64_t operator - (const base &other) const { return compare (other, false); } - template , typename AL = std::allocator > - static bool equals (const std::basic_string &l, const std::basic_string &r, bool remove_mid_blank = false) - { - return IsNormalizeStringEquals (l, r, remove_mid_blank); - } - template , typename AL = std::allocator > - static int64_t compare (const std::basic_string &l, const std::basic_string &r, bool remove_mid_blank = false) - { - return NormalizeStringCompare (l, r, remove_mid_blank); - } - template , typename AL = std::allocator > - static std::basic_string normalize (const std::basic_string &str, bool to_upper = false, bool remove_mid_blank = false) - { - return NormalizeString (str, to_upper, remove_mid_blank); - } - template , typename AL = std::allocator > - static std::basic_string trim (const std::basic_string &str, bool remove_mid_blank = false) - { - return StringTrim (str, remove_mid_blank); - } - template , typename AL = std::allocator > - static size_t length (const std::basic_string &str, bool remove_mid_blank = false) - { - return GetNormalizeStringLength (str, remove_mid_blank); - } - template , typename AL = std::allocator > - static bool empty (const std::basic_string &str) - { - return IsNormalizeStringEmpty (str); - } - template , typename AL = std::allocator > - static std::basic_nstring to_nstring (std::basic_string &str) { return std::basic_nstring (str); } - template , typename AL = std::allocator > - static std::basic_nstring toupper (const std::basic_nstring &str) { return l0km::toupper (str); } - template , typename AL = std::allocator > - static std::basic_nstring tolower (const std::basic_nstring &str) { return l0km::tolower (str); } - }; - - typedef basic_nstring nstring; - typedef basic_nstring wnstring; -} \ No newline at end of file diff --git a/priread/prifile.h b/priread/prifile.h deleted file mode 100644 index 273703c..0000000 --- a/priread/prifile.h +++ /dev/null @@ -1,2671 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef _CONSOLE -#include -#include -#endif -#include "nstring.h" -#include "localeex.h" -#include "themeinfo.h" -// #define UNALIGN_MEMORY - -#ifdef UNALIGN_MEMORY -#pragma pack(push, 1) -#endif -#ifdef min -#undef min -#endif -#ifdef max -#undef max -#endif -struct destruct -{ - std::function endtask = nullptr; - destruct (std::function init): endtask (init) {} - ~destruct () { if (endtask) endtask (); } -}; -template struct LargeIntBase -{ - BASE_INT val; - LargeIntBase () { val.QuadPart = 0; } - LargeIntBase (T v) { val.QuadPart = v; } - LargeIntBase (const LargeIntBase &other) { val.QuadPart = other.val.QuadPart; } - LargeIntBase (const BASE_INT &other) { val = other; } - operator BASE_INT () const { return val; } - operator T () const { return val.QuadPart; } - explicit operator bool () const { return val.QuadPart != 0; } - T *ptr_num () { return &val.QuadPart; } - BASE_INT *ptr_union () { return &val; } - size_t sizeof_num () const { return sizeof (val.QuadPart); } - size_t sizeof_union () const { return sizeof (val); } - T num () const { return val.QuadPart; } - BASE_INT win_union () const { return val; } - LargeIntBase operator + (const LargeIntBase &rhs) const { return LargeIntBase (val.QuadPart + rhs.val.QuadPart); } - LargeIntBase operator - (const LargeIntBase &rhs) const { return LargeIntBase (val.QuadPart - rhs.val.QuadPart); } - LargeIntBase operator * (const LargeIntBase &rhs) const { return LargeIntBase (val.QuadPart * rhs.val.QuadPart); } - LargeIntBase operator / (const LargeIntBase &rhs) const { return LargeIntBase (val.QuadPart / rhs.val.QuadPart); } - LargeIntBase operator % (const LargeIntBase &rhs) const { return LargeIntBase (val.QuadPart % rhs.val.QuadPart); } - LargeIntBase &operator += (const LargeIntBase &rhs) { val.QuadPart += rhs.val.QuadPart; return *this; } - LargeIntBase &operator -= (const LargeIntBase &rhs) { val.QuadPart -= rhs.val.QuadPart; return *this; } - LargeIntBase &operator *= (const LargeIntBase &rhs) { val.QuadPart *= rhs.val.QuadPart; return *this; } - LargeIntBase &operator /= (const LargeIntBase &rhs) { val.QuadPart /= rhs.val.QuadPart; return *this; } - LargeIntBase &operator %= (const LargeIntBase &rhs) { val.QuadPart %= rhs.val.QuadPart; return *this; } - LargeIntBase operator & (const LargeIntBase &rhs) const { return LargeIntBase (val.QuadPart & rhs.val.QuadPart); } - LargeIntBase operator | (const LargeIntBase &rhs) const { return LargeIntBase (val.QuadPart | rhs.val.QuadPart); } - LargeIntBase operator ^ (const LargeIntBase &rhs) const { return LargeIntBase (val.QuadPart ^ rhs.val.QuadPart); } - LargeIntBase operator << (int n) const { return LargeIntBase (val.QuadPart << n); } - LargeIntBase operator >> (int n) const { return LargeIntBase (val.QuadPart >> n); } - LargeIntBase &operator &= (const LargeIntBase &rhs) { val.QuadPart &= rhs.val.QuadPart; return *this; } - LargeIntBase &operator |= (const LargeIntBase &rhs) { val.QuadPart |= rhs.val.QuadPart; return *this; } - LargeIntBase &operator ^= (const LargeIntBase &rhs) { val.QuadPart ^= rhs.val.QuadPart; return *this; } - LargeIntBase &operator <<= (int n) { val.QuadPart <<= n; return *this; } - LargeIntBase &operator >>= (int n) { val.QuadPart >>= n; return *this; } - LargeIntBase &operator ++ () { ++val.QuadPart; return *this; } - LargeIntBase operator ++ (int) { LargeIntBase tmp (*this); ++val.QuadPart; return tmp; } - LargeIntBase &operator -- () { --val.QuadPart; return *this; } - LargeIntBase operator -- (int) { LargeIntBase tmp (*this); --val.QuadPart; return tmp; } - bool operator < (const LargeIntBase &rhs) const { return val.QuadPart < rhs.val.QuadPart; } - bool operator > (const LargeIntBase &rhs) const { return val.QuadPart > rhs.val.QuadPart; } - bool operator <= (const LargeIntBase &rhs) const { return val.QuadPart <= rhs.val.QuadPart; } - bool operator >= (const LargeIntBase &rhs) const { return val.QuadPart >= rhs.val.QuadPart; } - bool operator == (const LargeIntBase &rhs) const { return val.QuadPart == rhs.val.QuadPart; } - bool operator != (const LargeIntBase &rhs) const { return val.QuadPart != rhs.val.QuadPart; } - bool operator ! () const { return !val.QuadPart; } - LargeIntBase operator ~ () const { return LargeIntBase (~val.QuadPart); } -}; -typedef LargeIntBase LargeInt, lint; -typedef LargeIntBase ULargeInt, ulint; -template , typename al = std::allocator > class basic_priid: public std::basic_nstring -{ - using base = std::basic_nstring ; - public: - using typename base::size_type; - using typename base::value_type; - using base::base; - basic_priid (const ct *buf, size_t sz = 16): base (buf, sz) {} - template basic_priid (const ct (&arr) [N]) : base (arr, N) {} -}; -typedef basic_priid pri_sectid; -std::string ReadStringEndwithNullA (IStream *pStream) -{ - if (!pStream) return ""; - std::string result; - char ch = 0; - ULONG cbRead = 0; - while (true) - { - HRESULT hr = pStream->Read (&ch, 1, &cbRead); - if (FAILED (hr) || cbRead == 0) break; - if (ch == '\0') break; - result.push_back (ch); - } - return result; -} -std::wstring ReadStringEndwithNullW (IStream *pStream) -{ - if (!pStream) return L""; - std::wstring result; - WCHAR ch = 0; - ULONG cbRead = 0; - while (true) - { - HRESULT hr = pStream->Read (&ch, sizeof (WCHAR), &cbRead); - if (FAILED (hr) || cbRead < sizeof (WCHAR)) break; - if (ch == L'\0') break; - result.push_back (ch); - } - return result; -} -std::string ReadStringEndwithNull (IStream *ifile, std::string &ret) -{ - return ret = ReadStringEndwithNullA (ifile); -} -std::wstring ReadStringEndwithNull (IStream *ifile, std::wstring &ret) -{ - return ret = ReadStringEndwithNullW (ifile); -} -std::string ReadStringA (IStream *pStream, size_t length) -{ - if (!pStream || length <= 0) return ""; - std::string result; - result.resize (length); - ULONG cbRead = 0; - HRESULT hr = pStream->Read (&result [0], length, &cbRead); - if (FAILED (hr) || cbRead == 0) - { - result.clear (); - return result; - } - if (cbRead < (ULONG)length) result.resize (cbRead); - return result; -} -std::wstring ReadStringW (IStream *pStream, size_t length) -{ - if (!pStream || length <= 0) return L""; - std::wstring result; - result.resize (length); - ULONG cbRead = 0; - HRESULT hr = pStream->Read (&result [0], length * sizeof (WCHAR), &cbRead); - if (FAILED (hr) || cbRead == 0) - { - result.clear (); - return result; - } - if (cbRead < (ULONG)(length * sizeof (WCHAR))) result.resize (cbRead / sizeof (WCHAR)); - return result; -} -enum class seekpos: DWORD -{ - start = STREAM_SEEK_SET, - current = STREAM_SEEK_CUR, - end = STREAM_SEEK_END -}; -class bytesstream -{ - std::vector bytes; - size_t pos = 0; - public: - using seekpos = ::seekpos; - // ļ/ƫλá 0 ʼ - using fsize_t = uint64_t; - // ļָƶȣң - using fmove_t = int64_t; - bool read (void *p, size_t size, size_t *ret = nullptr) - { - if (!p || size == 0) return false; - size_t available = 0; - if (pos < bytes.size ()) available = bytes.size () - pos; - size_t readSize = (available >= size) ? size : available; - if (readSize > 0) memcpy_s (p, size, bytes.data () + pos, readSize); - else memset (p, 0, size); - pos += size; - if (ret) *ret = readSize; - return true; - } - template ::value>::type> size_t read (T &var) - { - size_t ret = 0; - read (&var, sizeof (var), &ret); - return ret; - } - template ::value>::type> friend bytesstream &operator >> (bytesstream &s, T &variable) - { - s.read (&variable, sizeof (variable)); - return s; - } - friend bytesstream &operator >> (bytesstream &in, std::string &ret) - { - in.read_string_endwith_null (ret); - return in; - } - friend bytesstream &operator >> (bytesstream &in, std::wstring &ret) - { - in.read_string_endwith_null (ret); - return in; - } - bytesstream (const std::vector &vec): bytes (vec) {} - bytesstream (const BYTE *ptr, size_t len = 0): bytes (len, *ptr) {} - bytesstream () = default; - auto &data () { return bytes; } - void set (const std::vector &bver) - { - bytes = bver; - } - auto position () - { - if (pos > bytes.size ()) pos = bytes.size (); - return pos; - } - auto position (size_t v) { pos = v; if (pos > bytes.size ()) pos = bytes.size (); return pos; } - auto length () const { return bytes.size (); } - auto size () const { return length (); } - std::string read_string_endwith_null_a (); - std::wstring read_string_endwith_null_w (); - size_t read_string_endwith_null (std::string &ret); - size_t read_string_endwith_null (std::wstring &ret); - std::string read_string_a (size_t length); - std::wstring read_string_w (size_t length); - size_t read_string (size_t length, std::wstring &ret); - size_t read_string (size_t length, std::string &ret); - HRESULT seek (fmove_t movelen = 0, seekpos origin = seekpos::current, fsize_t *newpos = nullptr) - { - if (bytes.empty ()) return E_INVALIDARG; - int64_t newPosition = 0; - switch (origin) - { - case seekpos::start: - newPosition = movelen; - break; - case seekpos::current: - newPosition = static_cast (pos) + movelen; - break; - case seekpos::end: - newPosition = static_cast (bytes.size ()) + movelen; - break; - default: return E_INVALIDARG; - } - if (newPosition < 0) newPosition = 0; - pos = static_cast (newPosition); - if (newpos) *newpos = static_cast (pos); - return S_OK; - } - auto &buffer () const { return bytes; } - auto &buffer () { return bytes; } - size_t remain () const - { - if (pos > size ()) return 0; - return size () - pos; - } - void clear () - { - bytes.clear (); - pos = 0; - } - void resize (size_t len) { bytes.resize (len); } - const BYTE *ptr () const { return bytes.data (); } - BYTE *ptr () { return bytes.data (); } - template ::value>::type> - T read_bytes (size_t byteslen = sizeof (T), size_t *returnread = nullptr) - { - std::vector bytesbuf (byteslen); - size_t rl = 0; - read (bytesbuf.data (), byteslen, &rl); - if (returnread) *returnread = rl; - bytesbuf.resize (!rl ? sizeof (T) : rl); - return *(T *)bytesbuf.data (); - } -}; -std::string ReadStringEndwithNullA (bytesstream &stream) -{ - std::string result; - char ch = 0; - size_t cbRead = 0; - while (true) - { - if (!stream.read (&ch, 1, &cbRead) || cbRead == 0) break; - if (ch == '\0') break; - result.push_back (ch); - } - return result; -} -std::wstring ReadStringEndwithNullW (bytesstream &stream) -{ - std::wstring result; - WCHAR ch = 0; - size_t cbRead = 0; - while (true) - { - if (!stream.read (&ch, sizeof (WCHAR), &cbRead) || cbRead < sizeof (WCHAR)) break; - if (ch == L'\0') break; - result.push_back (ch); - } - return result; -} -std::string ReadStringEndwithNull (bytesstream &stream, std::string &ret) -{ - return ret = ReadStringEndwithNullA (stream); -} -std::wstring ReadStringEndwithNull (bytesstream &stream, std::wstring &ret) -{ - return ret = ReadStringEndwithNullW (stream); -} -std::string ReadStringA (bytesstream &stream, size_t length) -{ - if (length == 0) return ""; - std::string result (length, '\0'); - size_t cbRead = 0; - if (!stream.read (&result [0], length, &cbRead) || cbRead == 0) - { - result.clear (); - return result; - } - if (cbRead < length) result.resize (cbRead); - return result; -} -std::wstring ReadStringW (bytesstream &stream, size_t length) -{ - if (length == 0) return L""; - std::wstring result (length, L'\0'); - size_t cbRead = 0; - if (!stream.read (&result [0], length * sizeof (WCHAR), &cbRead) || cbRead == 0) - { - result.clear (); - return result; - } - if (cbRead < length * sizeof (WCHAR)) result.resize (cbRead / sizeof (WCHAR)); - return result; -} -std::string bytesstream::read_string_endwith_null_a () { return ReadStringEndwithNullA (*this); } -std::wstring bytesstream::read_string_endwith_null_w () { return ReadStringEndwithNullW (*this); } -size_t bytesstream::read_string_endwith_null (std::string &ret) -{ - return (ret = read_string_endwith_null_a ()).length (); -} -size_t bytesstream::read_string_endwith_null (std::wstring &ret) -{ - return (ret = read_string_endwith_null_w ()).length (); -} -std::string bytesstream::read_string_a (size_t length) { return ReadStringA (*this, length); } -std::wstring bytesstream::read_string_w (size_t length) { return ReadStringW (*this, length); } -size_t bytesstream::read_string (size_t length, std::wstring &ret) { return (ret = read_string_w (length)).length (); } -size_t bytesstream::read_string (size_t length, std::string &ret) { return (ret = read_string_a (length)).length (); } -// עʱͷָ롣Ϊһֲ -class istreamstream -{ - private: - // COM ӿڣָ - IStream *comStream = nullptr; - // 棬 210 ֽ - bytesstream bsCache; - // Ϊڣ¼ļλá - uint64_t ulWndOffset = 0; - static const size_t MAX_CACHE_SIZE = 210; - public: - // ļ/ƫλá 0 ʼ - using fsize_t = uint64_t; - // ļָƶȣң - using fmove_t = int64_t; - using seekpos = ::seekpos; - istreamstream (IStream *iptr): comStream (iptr) - { - // bsCache.buffer ().reserve (MAX_CACHE_SIZE); - } - auto &buffer () const { return bsCache; } - auto &buffer () { return bsCache; } - void set_stream (IStream *iptr) { comStream = iptr; } - IStream *get_stream () { return comStream; } - // read - // 棺ȡ 210 ֽڵĻ - // ȡ棺ڻжȡֽڣָָֽһƶָֽ뾭һָȡ - HRESULT read (void *buf, size_t size, size_t *readbytes = nullptr) - { - if (!comStream || !buf) return E_INVALIDARG; - if (position () < ulWndOffset || position () >= ulWndOffset + bsCache.size () || position () != ulWndOffset + position ()) bsCache.buffer ().clear (); - if (size > MAX_CACHE_SIZE) - { - bsCache.clear (); - ULONG cbread = 0; - HRESULT hr = comStream->Read (buf, size, &cbread); - if (readbytes) *readbytes = cbread; - return hr; - } - else if (bsCache.remain () < size) - { - bsCache.clear (); - bsCache.resize (MAX_CACHE_SIZE); - auto nowpos = position (); - ULONG cbread = 0; - HRESULT hr = comStream->Read (bsCache.ptr (), MAX_CACHE_SIZE, &cbread); - comStream->Seek (lint (nowpos), STREAM_SEEK_SET, nullptr); - ulWndOffset = nowpos; - bsCache.resize (cbread); - size_t bufread = 0; - bool res = bsCache.read (buf, size, &bufread); - if (readbytes) *readbytes = bufread; - comStream->Seek (lint (bufread), STREAM_SEEK_CUR, nullptr); - if (res) return S_OK; - else return FAILED (hr) ? hr : E_FAIL; - } - else - { - size_t bufread = 0; - bool res = bsCache.read (buf, size, &bufread); - if (readbytes) *readbytes = bufread; - comStream->Seek (lint (bufread), STREAM_SEEK_CUR, nullptr); - return res ? S_OK : E_FAIL; - } - } - // ʹóޣҲִָ֧롣 - template ::value>::type> - HRESULT read (T &variable, size_t *readbytes = nullptr) - { - return read (&variable, sizeof (variable), readbytes); - } - std::string read_string_endwith_null_a () { return ReadStringEndwithNullA (comStream); } - std::wstring read_string_endwith_null_w () { return ReadStringEndwithNullW (comStream); } - size_t read_string_endwith_null (std::string &ret) - { - return (ret = read_string_endwith_null_a ()).length (); - } - size_t read_string_endwith_null (std::wstring &ret) - { - return (ret = read_string_endwith_null_w ()).length (); - } - std::string read_string_a (size_t length) { return ReadStringA (comStream, length); } - std::wstring read_string_w (size_t length) { return ReadStringW (comStream, length); } - size_t read_string (size_t length, std::wstring &ret) { return (ret = read_string_w (length)).length (); } - size_t read_string (size_t length, std::string &ret) { return (ret = read_string_a (length)).length (); } - HRESULT write (const void *bytes, size_t size, size_t *writebytes = nullptr) - { - if (!comStream) return E_INVALIDARG; - ULONG retsize = 0; - HRESULT hr = comStream->Write (bytes, size, &retsize); - if (writebytes) *writebytes = retsize; - return hr; - } - // ʹóޣҲִָ֧롣 - template ::value>::type> - HRESULT write (const T &variable, size_t *writebytes = nullptr) - { - return write (&variable, sizeof (variable), writebytes); - } - HRESULT seek (fmove_t movelen = 0, seekpos origin = seekpos::current, fsize_t *newpos = nullptr) - { - if (!comStream) return E_INVALIDARG; - ulint ret = 0; - HRESULT hr = comStream->Seek (lint (movelen), (DWORD)origin, ret.ptr_union ()); - if ((movelen != 0 || origin != seekpos::current) && bsCache.size ()) bsCache.clear (); - if (newpos) *newpos = ret; - return hr; - } - fsize_t position () - { - fsize_t pos = 0; - seek (0, seekpos::current, &pos); - return pos; - } - HRESULT stat (STATSTG *data, DWORD statflags) - { - if (!comStream) return E_INVALIDARG; - return comStream->Stat (data, statflags); - } - HRESULT size (fsize_t newsize) - { - if (!comStream) return E_INVALIDARG; - return comStream->SetSize (ulint (newsize)); - } - fsize_t size () - { - STATSTG stg = {0}; - if (SUCCEEDED (stat (&stg, STATFLAG_NONAME))) return stg.cbSize.QuadPart; - else return 0; - } - HRESULT copy_to (istreamstream &pstm, fsize_t cb, fsize_t *pcbRead = nullptr, fsize_t *pcbWritten = nullptr) - { - if (!comStream) return E_INVALIDARG; - ulint r = 0, w = 0; - HRESULT hr = comStream->CopyTo (pstm.comStream, ulint (cb), r.ptr_union (), w.ptr_union ()); - if (pcbRead) *pcbRead = r; - if (pcbWritten) *pcbWritten = w; - return hr; - } - HRESULT commit (DWORD grfCommitFlags) - { - if (!comStream) return E_INVALIDARG; - return comStream->Commit (grfCommitFlags); - } - HRESULT revert () - { - if (!comStream) return E_INVALIDARG; - return comStream->Revert (); - } - HRESULT lock_region (fsize_t libOffset, fsize_t cb, DWORD dwLockType) - { - if (!comStream) return E_INVALIDARG; - return comStream->LockRegion (ulint (libOffset), ulint (cb), dwLockType); - } - HRESULT unlock_region (fsize_t libOffset, fsize_t cb, DWORD dwLockType) - { - if (!comStream) return E_INVALIDARG; - return comStream->UnlockRegion (ulint (libOffset), ulint (cb), dwLockType); - } - HRESULT clone (istreamstream &anotherptr) - { - if (!comStream) return E_INVALIDARG; - return comStream->Clone (&anotherptr.comStream); - } - template ::value>::type> - friend istreamstream &operator >> (istreamstream &in, T &variable) - { - in.read (variable); - return in; - } - template ::value>::type> - friend istreamstream &operator << (istreamstream &out, const T &variable) - { - out.write (variable); - return out; - } - friend istreamstream &operator >> (istreamstream &in, std::string &ret) - { - in.read_string_endwith_null (ret); - return in; - } - friend istreamstream &operator >> (istreamstream &in, std::wstring &ret) - { - in.read_string_endwith_null (ret); - return in; - } - operator IStream * () { return comStream; } - IStream *operator -> () { return comStream; } - template ::value>::type> - // ȡһֵжǷԤڡthrowerror ΪʱֵԤͨ׳쳣жϡֵֻͨжϡ - bool expect (const T &expect_value, bool throwerror = true, T *retvalue = nullptr) - { - T value; - this->read (value); - if (retvalue) *retvalue = value; - bool res = value == expect_value; - if (!res && throwerror) throw std::exception ("Unexpected value read."); - return res; - } - template ::value>::type> - T read_bytes (size_t byteslen = sizeof (T), size_t *returnread = nullptr) - { - std::vector bytesbuf (byteslen); - size_t rl = 0; - read (bytesbuf.data (), byteslen, &rl); - if (returnread) *returnread = rl; - bytesbuf.resize (!rl ? sizeof (T) : rl); - return *(T *)bytesbuf.data (); - } -}; - -// 0 1 -// 012345678901234 -#define PRI_SECT_ID_PRI_DESCRIPTOR "[mrm_pridescex]" -#define PRI_SECT_ID_HIERARCHICAL_SCHEMA "[mrm_hschema] " -#define PRI_SECT_ID_HIERARCHICAL_SCHEMAEX "[mrm_hschemaex]" -#define PRI_SECT_ID_DECISION_INFO "[mrm_decn_info]" -#define PRI_SECT_ID_RESOURCE_MAP "[mrm_res_map__]" -#define PRI_SECT_ID_RESOURCE_MAP2 "[mrm_res_map2_]" -#define PRI_SECT_ID_DATA_ITEM "[mrm_dataitem] " -#define PRI_SECT_ID_REVERSE_MAP "[mrm_rev_map] " -#define PRI_SECT_ID_REFERENCED_FILE "[def_file_list]" -enum class SectionType -{ - Unknown, // δ֪ - δʶĽ - PriDescriptor, // PRI - ļṹϢ - HierarchicalSchema, // νṹģʽ - ԴռͲνṹ - HierarchicalSchemaEx, // νṹģʽ - ԴռͲνṹ - DecisionInfo, // Ϣ - Դ޶;߼ - ResourceMap, // Դӳ - Դӳ䵽ѡֵ - ResourceMap2, // Դӳ - Դӳ䵽ѡֵ - DataItem, // - 洢ʵʵԴ - ReverseMap, // ӳ - ṩԴIDӳ - ReferencedFile // ļ - õⲿļ -}; -std::wstring EnumToStringW (SectionType value) -{ - switch (value) - { - case SectionType::PriDescriptor: return L"PriDescriptor"; break; - case SectionType::HierarchicalSchema: return L"HierarchicalSchema"; break; - case SectionType::HierarchicalSchemaEx: return L"HierarchicalSchemaEx"; break; - case SectionType::DecisionInfo: return L"DecisionInfo"; break; - case SectionType::ResourceMap: return L"ResourceMap"; break; - case SectionType::ResourceMap2: return L"ResourceMap2"; break; - case SectionType::DataItem: return L"DataItem"; break; - case SectionType::ReverseMap: return L"ReverseMap"; break; - case SectionType::ReferencedFile: return L"ReferencedFile"; break; - default: - case SectionType::Unknown: return L"Unknown"; break; - } -} - -struct head -{ - // 汾ʶ / version identifier - // mrm_pri0ͻ 6.2.1Windows 8 - // mrm_pri1ͻ 6.3.0Windows 8.1 - // mrm_prifWindows Phone 6.3.1 - // mrm_pri2Universal 10.0.0Windows 10 - CHAR szMagic [8] = {}; - WORD wPlaceholder1 = -1, // δ֪0 / unknown, zero - wPlaceholder2 = 0; // δ֪1 / unknown, one - DWORD dwFileSize = 0, // ļܴС / total file size - dwToCOffset = 0, // Ŀ¼ƫ / offset of table of contents - dwSectStartOffset = 0; // һڵƫ / offset of first section - WORD wSectCount = 0, // / number of sections - wPlaceholder3 = 0; // δ֪0xFFFF / unknown, 0xFFFF - DWORD dwPlaceholder4 = -1; // δ֪0 / unknown, zero - bool valid () - { - CHAR m7 = szMagic [7]; - destruct endt ([this, m7] () { - if (m7) szMagic [7] = m7; - }); - szMagic [7] = '\0'; - if (_stricmp (szMagic, "mrm_pri")) return false; - switch (m7) - { - case '0': case '1': case '2': case 'f': case 'F': break; - default: return false; - } - if (wPlaceholder1 != 0) return false; - if (wPlaceholder2 != 1) return false; - if (wPlaceholder3 != 0xFFFF) return false; - if (dwPlaceholder4 != 0) return false; - return true; - } -}; -struct foot -{ - DWORD dwChkCode = 0; // 0xDEFFFADE - DWORD dwTotalFileSize = 0; // total file size, as in header - CHAR szMagic [8] = {0}; // version identifier, as in header - bool valid (const head &fh) - { - if (dwChkCode != 0xDEFFFADE) return false; - if (dwTotalFileSize != fh.dwFileSize) return false; - for (int i = 0; i < 8; i ++) - { - if (szMagic [i] != fh.szMagic [i] && tolower (szMagic [i]) != tolower (fh.szMagic [i])) return false; - } - return true; - } -}; -struct tocentry -{ - CHAR szIdentifier [16] = {0}; // ڱʶ / section identifier - WORD wFlags = 0; // ־ / flags - WORD wSectFlags = 0; // ڱ־ / section flags - DWORD dwSectQualifier = 0; // ޶ / section qualifier - DWORD dwSectOffset = 0; // ƫƣڵһƫƣ / section offset (relative to offset of first section) - DWORD dwSectLength = 0; // ڳ / section length -}; -struct section_header -{ - CHAR szIdentifier [16] = {0}; // ڱʶ / section identifier - DWORD dwQualifier = 0; // ޶ / section qualifier - WORD wFlags = 0; // ־ / flags - WORD wSectFlags = 0; // ڱ־ / section flags - DWORD dwLength = 0; // ڳ / section length - DWORD dwPlaceholder1 = -1; // δ֪0 / unknown, zero - bool valid () const { return szIdentifier [0] && !dwPlaceholder1; } -}; -struct section_check -{ - DWORD dwChkCode = 0; // ħ 0xF5DEDEFA - DWORD dwSectLength = 0; // ڳȣͷеͬ / section length, as in section header - bool valid (const section_header &h) const { return dwChkCode == 0xDEF5FADE && dwSectLength == h.dwLength; } -}; -struct substream -{ - IStream *&ifile; - ULONGLONG offset = 0; - ULONGLONG size = 0; - substream (IStream *&ifile, ulint ofs = 0, ulint siz = 0): ifile (ifile), offset (ofs), size (siz) {} - void set (ulint p_offset, ulint p_size) - { - offset = p_offset; - size = p_size; - } - HRESULT seek () - { - istreamstream iss (ifile); - return iss.seek (offset, istreamstream::seekpos::start); - } -}; -struct prifile; -struct section -{ - section_header head; - section_check foot; - substream childst; - // type ȡֱͣͨ sect_type ȡΪδʼ - SectionType sect_type = SectionType::Unknown; - section (IStream *&ifile, prifile &prif): childst (ifile), pri_file (prif) {} - bool valid () const { return head.valid () && foot.valid (head); } - SectionType type () - { - if (sect_type == SectionType::Unknown) - { - pri_sectid pid (head.szIdentifier, 16); - if (pid.equals (PRI_SECT_ID_PRI_DESCRIPTOR)) sect_type = SectionType::PriDescriptor; - else if (pid.equals (PRI_SECT_ID_HIERARCHICAL_SCHEMA)) sect_type = SectionType::HierarchicalSchema; - else if (pid.equals (PRI_SECT_ID_HIERARCHICAL_SCHEMAEX)) sect_type = SectionType::HierarchicalSchemaEx; - else if (pid.equals (PRI_SECT_ID_DECISION_INFO)) sect_type = SectionType::DecisionInfo; - else if (pid.equals (PRI_SECT_ID_RESOURCE_MAP)) sect_type = SectionType::ResourceMap; - else if (pid.equals (PRI_SECT_ID_RESOURCE_MAP2)) sect_type = SectionType::ResourceMap2; - else if (pid.equals (PRI_SECT_ID_DATA_ITEM)) sect_type = SectionType::DataItem; - else if (pid.equals (PRI_SECT_ID_REVERSE_MAP)) sect_type = SectionType::ReverseMap; - else if (pid.equals (PRI_SECT_ID_REFERENCED_FILE)) sect_type = SectionType::ReferencedFile; - else sect_type = SectionType::Unknown; - } - return sect_type; - } - size_t length () const { return head.dwLength; } - prifile &pri_file; -#ifdef _CONSOLE - friend std::wostream &operator << (std::wostream &o, section &s) - { - return o << L"Section " << EnumToStringW (s.type ()) << L" Length " << s.head.dwLength; - } -#endif -}; -namespace pri -{ - struct sect_pridesp; // PriDescriptor PRI - ļṹϢ - struct sect_hierasche; // HierarchicalSchema & HierarchicalSchemaEx νṹģʽ - ԴռͲνṹ - struct sect_decinfo; // DecisionInfo Ϣ - Դ޶;߼ - struct sect_resmap; // ResourceMap & ResourceMap2 Դӳ - Դӳ䵽ѡֵ - struct sect_dataitem; // DataItem - 洢ʵʵԴ - struct sect_revmap; // ReverseMap ӳ - ṩԴIDӳ - struct sect_reffile; // ReferencedFile ļ - õⲿļ - struct sect_unknown; // Unknown δ֪ - δʶĽ - - // PriDescriptorFlags - - enum class PRI_SEC_DESP: DWORD - { - INVALID = 0, - AUTOMERGE = 0x1, // AutoMerge - DEPLOY_MERGEABLE = 0x2, // IsDeploymentMergeable - DEPLOY_MERGE_RESULT = 0x4, // IsDeploymentMergeResult - AUTO_MERGE_RESULT = 0x8 // IsAutomergeMergeResult - }; - - // HierarchicalSchema & HierarchicalSchemaEx - - typedef struct _HSCHEMA_VERSION_INFO - { - WORD wMajor = 0; // 汾 / major version - WORD wMinor = 0; // ΰ汾 / minor version - DWORD dwUnknown1 = -1; // δ֪0 - // Уͣchecksum - // checksum: a CRC32-based checksum computed on the unique name, - // the name, the section indices of the Resource Map Section - // and Data Item Section, and the names of all scopes and items - DWORD dwCheckSum = 0; - DWORD dwScopeCount = 0; // scope - DWORD dwItemCount = 0; // item - bool empty () - { - return dwUnknown1 != 0; - } - } HSCHEMA_VERSION_INFO; - // Դƣscope/item¸ʽ洢ʾֶΣparent scope indexfull path ȡ - // ĸдֳȡƫơindex property ȡ - - typedef struct _SCOPE_ITEM_INFO - { - WORD wParentScopeIndex = -1; // parent scope index - WORD wFullPathLength = 0; // length of full path - WCHAR wchUpperFirst = L'\0'; // uppercase first character of name, '\0' if name is empty - // length of name in characters, null-terminator excluded, 0 if the length is bigger than 255 - // ԭߵ C# ôȡģuint nameOffset = binaryReader.ReadUInt16() | (uint)((flags & 0xF) << 16); - // ԲֱʹóԱ bNameLengthʹýṹ name_offset () ȡֵ - BYTE bNameLength = 0; - BYTE bFlags = 0; // flags and upper bits of name offset - WORD wNameOffset = 0; // offset of name in ASCII or Unicode name block in characters - // index property - // bits 0-3: upper bits 16-19 of name offset - // bit 4: set if resource name is a scope, unset if it is an item - // bit 5 : set if name is stored in the ASCII name block, unset if - // it is stored in the Unicode name block - WORD wIndexProp = 0; - bool is_scope () const { return bFlags & 0x10; } - bool name_in_ascii () const { return bFlags & 0x20; } - DWORD name_offset () const { return (DWORD)wNameOffset | ((DWORD)(bFlags & 0xF) << 16); } - DWORD index () const { return wIndexProp; } - //friend istreamstream &operator >> (istreamstream &i, _SCOPE_ITEM_INFO &s) - //{ - // i >> s.wParentScopeIndex >> - // s.wFullPathLength; - // s.wchUpperFirst = i.read_bytes (sizeof (UINT16)); - // s.bNameLength = i.read_bytes (); - // s.bFlags = i.read_bytes (); - // s.wNameOffset = i.read_bytes (); - // s.wIndexProp = i.read_bytes (); - // return i; - //} - //friend bytesstream &operator >> (bytesstream &i, _SCOPE_ITEM_INFO &s) - //{ - // i >> s.wParentScopeIndex >> - // s.wFullPathLength; - // s.wchUpperFirst = i.read_bytes (sizeof (UINT16)); - // s.bNameLength = i.read_bytes (); - // s.bFlags = i.read_bytes (); - // s.wNameOffset = i.read_bytes (); - // s.wIndexProp = i.read_bytes (); - // return i; - //} - } SCOPE_ITEM_INFO; - typedef struct _SCOPE_EX_INFO - { - WORD wScopeIndex = 0; // scope index - WORD wChildCount = 0; // child count - WORD wFirstChild = 0; // scope or item index of first child, all other children follow sequentially - WORD wUnknown1 = 0; // unknown, zero - //friend istreamstream &operator >> (istreamstream &i, _SCOPE_EX_INFO &e) - //{ - // i >> e.wScopeIndex >> - // e.wChildCount >> - // e.wFirstChild; - // i.expect (0, true, &e.wUnknown1); - // return i; - //} - bool valid () const { return !wUnknown1; } - } SCOPE_EX_INFO; - typedef WORD ITEM_INDEX; - enum class RES_MAP_OBJTYPE - { - ENTRY = 0, - SCOPE = 1, - ITEM = 2 - }; - class RES_MAP_SCOPE; - class RES_MAP_ENTRY - { - public: - ITEM_INDEX wIndex = 0; - std::wstring strName; - RES_MAP_SCOPE *pParent = nullptr; - RES_MAP_ENTRY (ITEM_INDEX index = 0, RES_MAP_SCOPE *parent = {}, const std::wstring &name = L"", RES_MAP_OBJTYPE type = RES_MAP_OBJTYPE::ENTRY, bool setnull = true): - wIndex (index), strName (name), pParent (parent), eType (type), bIsNull (setnull) {} - std::wstring full_name (WCHAR divide = L'\\'); - size_t path (std::vector &output); - void refresh_full_name () { strFullName.clear (); } - RES_MAP_OBJTYPE type () const { return eType; } - bool bIsNull = false; - protected: - std::wstring strFullName; - RES_MAP_OBJTYPE eType; - }; - class RES_MAP_SCOPE: public RES_MAP_ENTRY - { - public: - explicit RES_MAP_SCOPE (ITEM_INDEX index = 0, RES_MAP_SCOPE *parent = nullptr, const std::wstring &name = L"", bool setnull = true): - RES_MAP_ENTRY (index, parent, name, RES_MAP_OBJTYPE::SCOPE, setnull) {} - std::vector vecChild; - }; - std::wstring RES_MAP_ENTRY::full_name (WCHAR divide) - { - if (strFullName.empty ()) - { - if (pParent) strFullName = pParent->full_name (divide) + divide + strName; - else strFullName = strName; - } - return strFullName; - } - size_t RES_MAP_ENTRY::path (std::vector &output) - { - output.clear (); - if (pParent) pParent->path (output); - output.push_back (strName); - return output.size (); - } - class RES_MAP_ITEM: public RES_MAP_ENTRY - { - public: - RES_MAP_ITEM (ITEM_INDEX index = 0, RES_MAP_SCOPE *parent = nullptr, const std::wstring &name = L"", bool setnull = true): - RES_MAP_ENTRY (index, parent, name, RES_MAP_OBJTYPE::ITEM, setnull) {} - }; - - // DecisionInfo - - typedef struct _DECISION_INFO - { - WORD wFirstQualiIndex = 0; // index of the first qualifier set index in the index table - WORD wQualiSetsCount = 0; // number of qualifiers sets in decision - } DECISION_INFO; - typedef struct _QUALIFIER_SET_INFO - { - WORD wFirstQualiIndex = 0; // index of the first qualifier index in the index table // firstQualifierIndexIndex - WORD wQualiSetsCount = 0; // number of qualifiers in qualifier set // numQualifiersInSet - } QUALIFIER_SET_INFO; - typedef struct _QUALIFIER_INFO - { - WORD wDistQualiIndex = 0; // index of distinct qualifier - WORD wPriority = 0; // priority - WORD wFallbackScore = -1; // fallback score, values range from 0 to 1000 - WORD wUnknown1 = -1; // unknown, zero - } QUALIFIER_INFO; - enum class QUALIFIER_TYPE: WORD - { - LANGUAGE = 0, // (0) - CONTRAST = 1, // Աȶ (1) - SCALE = 2, // (2) - HOMEREGION = 3, // Ļ (3) - TARGETSIZE = 4, // Ŀߴ (4) - LAYOUTDIR = 5, // ַ (5) - THEME = 6, // (6) - ALTERNATEFORM = 7, // ʽ (7) - DXFEATURELEVEL = 8, // DX ܵȼ (8) - CONFIG = 9, // (9) - DEVICEFAMILY = 10, // 豸ϵ (10) - CUSTOM = 11, // Զ (11) - }; - std::wstring EnumToStringW (QUALIFIER_TYPE value) - { - switch (value) - { - case QUALIFIER_TYPE::LANGUAGE: return L"Language"; break; - case QUALIFIER_TYPE::CONTRAST: return L"Contrast"; break; - case QUALIFIER_TYPE::SCALE: return L"Scale"; break; - case QUALIFIER_TYPE::HOMEREGION: return L"HomeRegion"; break; - case QUALIFIER_TYPE::TARGETSIZE: return L"TargetSize"; break; - case QUALIFIER_TYPE::LAYOUTDIR: return L"LayoutDir"; break; - case QUALIFIER_TYPE::THEME: return L"Theme"; break; - case QUALIFIER_TYPE::ALTERNATEFORM: return L"AlternateForm"; break; - case QUALIFIER_TYPE::DXFEATURELEVEL: return L"DxFeatureLevel"; break; - case QUALIFIER_TYPE::CONFIG: return L"Configure"; break; - case QUALIFIER_TYPE::DEVICEFAMILY: return L"DeviceFamily"; break; - case QUALIFIER_TYPE::CUSTOM: return L"Custom"; break; - } - } - typedef struct _DISTINCE_QUALIFIER_INFO - { - WORD wUnknown1 = 0; // unknown - WORD wQualiType = 0; // qualifier type - WORD wUnknown2 = 0; // unknown - WORD wUnknown3 = 0; // unknown - DWORD wQualiValueOffset = 0; // offset of qualifier value in qualifier value block, in characters - } DISTINCE_QUALIFIER_INFO; - typedef struct _QUALIFIER - { - ITEM_INDEX wIndex = 0; - QUALIFIER_TYPE eType = QUALIFIER_TYPE::CUSTOM; - WORD wPriority = 0; - DOUBLE dFallbackScope = 0; - std::wstring swValue = 0; - _QUALIFIER (ITEM_INDEX index = 0, QUALIFIER_TYPE type = QUALIFIER_TYPE::CUSTOM, WORD priority = 0, DOUBLE fallbackScope = 0, const std::wstring &value = L""): - wIndex (index), eType (type), wPriority (priority), dFallbackScope (fallbackScope), swValue (value) {} - } QUALIFIER; - typedef struct _QUALIFIER_SET - { - WORD wIndex = 0; - std::vector vecQuals; - _QUALIFIER_SET (WORD index = 0, const std::vector &quals = {}): - wIndex (index), vecQuals (quals) {} - } QUALIFIER_SET; - typedef struct _DECISION - { - WORD wIndex = 0; - std::vector verQualSets; - _DECISION (WORD index, const std::vector &qualsets = {}): - wIndex (index), verQualSets (qualsets) {} - } DECISION; - - // ResourceMap & ResourceMap2 - - typedef struct _HSCHEMA_REF_BLOCK - { - HSCHEMA_VERSION_INFO verHschema; // hierarchical schema version info - struct - { - WORD wUniIdLength = 0; // length of unique id in characters, null-terminator included - WORD wUnknown1 = -1; // unknown, zero - DWORD dwUnknown2 = 0; // unknown - DWORD dwUnknown3 = 0; // unknown - } part2; - std::wstring swUniqueId = L""; // unique id - bool empty () - { - return swUniqueId.empty () && part2.wUnknown1 != 0; - } - } HSCHEMA_REF_BLOCK; - enum class RES_VALUE_TYPE: DWORD - { - STRING = 0, // String (0) - PATH = 1, // Path (1) - EMBEDDEDDATA = 2, // EmbeddedData (2) - ASCIISTRING = 3, // AsciiString (3) - UTF8STRING = 4, // Utf8String (4) - ASCIIPATH = 5, // AsciiPath (5) - UTF8PATH = 6 // Utf8Path (6) - }; - typedef struct _RES_VALUE_TYPE_TABLE - { - DWORD dwUnknown1 = 0; // unknown, 4 - DWORD dwResType = -1; // resource value type - } RES_VALUE_TYPE_TABLE; - typedef struct _ITEM_ITEMINFO_GROUP_TABLE_ENTRY - { - WORD wFirstIndexProperty = 0; // index property of first resource item - WORD wItemInfoGroupIndex = 0; // index of iteminfo group - } ITEM_ITEMINFO_GROUP_TABLE_ENTRY; - typedef struct _ITEMINFO_GROUP_TABLE_ENTRY - { - WORD wItemInfoCount; // number of iteminfos in this group - WORD wFirstItemIndex; // index of the first iteminfo in this group - _ITEMINFO_GROUP_TABLE_ENTRY (WORD count = 0, WORD firstIndex = 0): wItemInfoCount (count), wFirstItemIndex (firstIndex) {} - } ITEMINFO_GROUP_TABLE_ENTRY; - typedef struct _ITEM_ITEMINFO_TABLE_ENTRY - { - WORD wDecisionIndex = 0; // index of decision - WORD wFirstCandiIndex = 0; // index of first candidate - } ITEM_ITEMINFO_TABLE_ENTRY; - typedef struct _TABLE_EXT_BLOCK - { - DWORD dwItemAdditEntCount = 0; // number of additional entries of the item to iteminfo group table // ItemToItemInfoGroupCountLarge - DWORD dwItemGroupAdditEntCount = 0; // number of additional entries of the item info group table // itemInfoGroupCountLarge - DWORD dwItemTableAdditEntCount = 0; // number of additional entries of the iteminfo table // itemInfoCountLarge - } TABLE_EXT_BLOCK; - typedef BYTE CANDIDATE_TYPE; - typedef struct _CANDIDATE0_DATA - { - BYTE bResValueType = 0; // resource value type, specified as an index into the resource value type table - WORD wEmbeddedLength = 0; // embedded data length - DWORD dwEmbeddedOffset = 0; // offset of the embedded data in the embedded data block - } CANDIDATE0_DATA; - typedef struct _CANDIDATE1_DATA - { - BYTE bResValueType = 0; // resource value type, specified as an index into the resource value type table - WORD wSrcFile = 0; // source file // sourceFileIndex - WORD wDataIndex = 0; // index of the data item storing the data // valueLocation - WORD wSectIndex = 0; // section index of the Data Item Section storing the data // dataItemSection - } CANDIDATE1_DATA; - typedef struct _CANDIDATE_INFO - { - BYTE bCandidateType = 0; // 0 1 - union CANDIDATE - { - CANDIDATE0_DATA _0; - CANDIDATE1_DATA _1; - CANDIDATE (CANDIDATE0_DATA can0): _0 (can0) {} - CANDIDATE (CANDIDATE1_DATA can1): _1 (can1) {} - CANDIDATE () {} - } objCandidate; - _CANDIDATE_INFO (CANDIDATE0_DATA can0): bCandidateType (0), objCandidate (can0) {} - _CANDIDATE_INFO (CANDIDATE1_DATA can1): bCandidateType (1), objCandidate (can1) {} - _CANDIDATE_INFO (): bCandidateType (-1) {} - bool candidate_0 () const { return bCandidateType == 0; } - bool candidate_1 () const { return bCandidateType == 1; } - bool valid () const { return candidate_0 () ^ candidate_1 (); } - } CANDIDATE_INFO; - struct basic_sect; - template struct ref_sect - { - using classtype = ref_sect ; - // static_assert (std::is_base_of ::value, "SectionType must derive from basic_sect"); - int index; - ref_sect (int sect_index = -1): index (sect_index) {} - using sect_type = SectionType; - explicit operator int () { return index; } - bool valid () const { return index != -1; } - void reset () { index = -1; } - bool operator == (const classtype &another) const { return index == another.index; } - classtype &operator = (const classtype &another) { index = another.index; return *this; } - classtype &operator = (int newvalue) { index = newvalue; return *this; } - }; - typedef struct _RES_MAP_ITEM_REF - { - ref_sect wSchemaSect; - int iItemIndex; - _RES_MAP_ITEM_REF (const ref_sect &ssect, int itemindex): - wSchemaSect (ssect), iItemIndex (itemindex) {} - _RES_MAP_ITEM_REF () {} - } RES_MAP_ITEM_REF; - struct _CANDIDATE; - typedef struct _CANDIDATE_SET - { - RES_MAP_ITEM_REF refResMapItem; - WORD wDecisionIndex = 0; - std::vector <_CANDIDATE> vecCandidates; - } CANDIDATE_SET; - typedef struct _BASIC_REF - { - INT64 llIndex = -1; - bool valid () const { return llIndex >= 0; } - void reset () { llIndex = -1; } - void set (int index) { llIndex = index; } - void setnull () { llIndex = -1; } - int get () { return llIndex; } - bool isnull () { return !valid (); } - _BASIC_REF (int index = 0, bool isnull = false): - llIndex (isnull ? -1 : index) {} - operator int () { return get (); } - _BASIC_REF &operator = (int index) { set (index); return *this; } - _BASIC_REF &operator = (const _BASIC_REF &rfr) { this->llIndex = rfr.llIndex; return *this; } - bool operator == (const _BASIC_REF &another) const { return this->llIndex == another.llIndex; } - bool operator == (int index) const { return (int)this->llIndex == index; } - } BASIC_REF; - typedef struct _REF_FILE_REF: public BASIC_REF - { - using BASIC_REF::_BASIC_REF; - } REF_FILE_REF; - typedef struct _DATA_ITEM_REF: public BASIC_REF - { - ref_sect iDataSectIndex; - _DATA_ITEM_REF (int itemIndex = 0, int itemDataSectIndex = 0, bool isnull = false): - BASIC_REF (itemIndex, isnull), iDataSectIndex (itemDataSectIndex) {} - operator int () = delete; - _DATA_ITEM_REF &operator = (int) = delete; - _DATA_ITEM_REF &operator = (const _BASIC_REF &) = delete; - _DATA_ITEM_REF &operator = (const _DATA_ITEM_REF &another) - { - this->llIndex = another.llIndex; - this->iDataSectIndex = another.iDataSectIndex; - return *this; - } - bool operator == (int) = delete; - bool operator == (const _BASIC_REF &) = delete; - bool operator == (const _DATA_ITEM_REF &another) const - { return llIndex == another.llIndex && iDataSectIndex == another.iDataSectIndex; } - } DATA_ITEM_REF; - typedef struct _BYTE_SPAN - { - ulint offset = 0; - size_t length = 0; - bool isnull = false; - using classtype = _BYTE_SPAN; - _BYTE_SPAN (ulint p_of = 0, size_t len = 0, bool nullstatus = false): offset (p_of), length (len), isnull (nullstatus) {} - // ȡʱļָλ - HRESULT get_bytes (istreamstream istream, std::vector &retbytes, size_t *retbyteslen = nullptr, bool cutbytesnoread = false) - { - retbytes.clear (); - retbytes.resize (length); - size_t bytesread = 0; - if (retbyteslen) *retbyteslen = 0; - HRESULT hr = istream.seek (offset, istreamstream::seekpos::start); - #ifdef _DEBUG - auto allsize = istream.size (); - #endif - if (FAILED (hr)) return hr; - hr = istream.read (retbytes.data (), length, &bytesread); - if (retbyteslen) *retbyteslen = bytesread; - if (cutbytesnoread) retbytes.resize (bytesread); - return hr; - } - } BYTE_SPAN; - typedef struct _CANDIDATE - { - WORD wQualifierSet = 0; - RES_VALUE_TYPE dwResType = RES_VALUE_TYPE::STRING; - REF_FILE_REF iSrcFileIndex = 0; - DATA_ITEM_REF iDataItem = 0; - BYTE_SPAN posData; - _CANDIDATE (WORD qualifierSet, RES_VALUE_TYPE resType, REF_FILE_REF srcFile, DATA_ITEM_REF dataItem): - wQualifierSet (qualifierSet), dwResType (resType), iSrcFileIndex (srcFile), iDataItem (dataItem), posData (0, 0, true) {} - _CANDIDATE (WORD qualifierSet, RES_VALUE_TYPE resType, BYTE_SPAN data): - wQualifierSet (qualifierSet), dwResType (resType), iSrcFileIndex (-1, true), iDataItem (-1, 0, true), posData (data) {} - _CANDIDATE (): iSrcFileIndex (-1, true), iDataItem (-1, 0, true), posData (0, 0, true) {} - // Ч᷵ nullptr - REF_FILE_REF *source_file_index () { return iSrcFileIndex.valid () ? &iSrcFileIndex : nullptr; } - // Ч᷵ nullptr - DATA_ITEM_REF *data_item_ref () { return iDataItem.valid () ? &iDataItem : nullptr; } - // Ч᷵ nullptr - BYTE_SPAN *data_position () { return posData.isnull ? nullptr : &posData; } - } CANDIDATE; - - // DataItem - - typedef struct _STORED_STRING_INFO - { - WORD wStringOffset = 0; // string offset, relative to start of stored data - WORD wStringLength = 0; // string length in bytes - } STORED_STRING_INFO; - typedef struct _STORED_BLOB_INFO - { - DWORD dwBlobOffset = 0; // blob offset, relative to start of stored data - DWORD dwBlobLength = 0; // blob length in bytes - } STORED_BLOB_INFO; - - // ReferencedFile - - typedef struct _REF_FOLDER_INFO - { - WORD wUnknown1 = -1; // unknown, zero - WORD wParentIndex = 0xFFFF; // index of parent folder, 0xFFFF if no parent exists (root) - WORD wFolderCount = 0; // number of folders in this folder - WORD wFirstFolderIndex = 0; // index of first folder in this folder - WORD wFileCount = 0; // number of files in this folder - WORD wFirstFileIndex = 0; // index of first file in this folder - WORD wFolderNameLength = 0; // length of folder name in characters - WORD wFolderFullPathLength = 0; // length of full folder path - DWORD dwFolderNameOffset = 0; // offset of folder name in Unicode name block - friend istreamstream &operator >> (istreamstream &i, _REF_FOLDER_INFO &reff) - { - return i >> - reff.wUnknown1 >> - reff.wParentIndex >> - reff.wFolderCount >> - reff.wFirstFolderIndex >> - reff.wFileCount >> - reff.wFirstFileIndex >> - reff.wFolderNameLength >> - reff.wFolderFullPathLength >> - reff.dwFolderNameOffset; - } - friend bytesstream &operator >> (bytesstream &i, _REF_FOLDER_INFO &reff) - { - return i >> - reff.wUnknown1 >> - reff.wParentIndex >> - reff.wFolderCount >> - reff.wFirstFolderIndex >> - reff.wFileCount >> - reff.wFirstFileIndex >> - reff.wFolderNameLength >> - reff.wFolderFullPathLength >> - reff.dwFolderNameOffset; - } - } REF_FOLDER_INFO; - typedef struct _REF_FILE_INFO - { - WORD wUnknown1 = 0; // unknown - WORD wParentIndex = 0; // index of parent folder - WORD wFileFullPathLength = 0; // length of full file path - WORD wFileNameLength = 0; // length of file name in characters - DWORD dwFileNameOffset = 0; // offset of file name in Unicode name block - friend istreamstream &operator >> (istreamstream &i, _REF_FILE_INFO &r) - { - return i >> r.wUnknown1 >> - r.wParentIndex >> - r.wFileFullPathLength >> - r.wFileNameLength >> - r.dwFileNameOffset; - } - friend bytesstream &operator >> (bytesstream &i, _REF_FILE_INFO &r) - { - return i >> r.wUnknown1 >> - r.wParentIndex >> - r.wFileFullPathLength >> - r.wFileNameLength >> - r.dwFileNameOffset; - } - } REF_FILE_INFO; - struct _REF_FOLDER; - typedef struct _REF_FILE_ENTRY - { - enum class ENTRYTYPE - { - UNKNOWN = 0, - FOLDER = 1, - FILE = 2 - }; - _REF_FOLDER *rfParent; - std::wstring swName = L""; - std::wstring fullname (); - std::wstring refresh_fullname () { swFullName.clear (); } - size_t path (std::vector &output); - ENTRYTYPE type () const { return eType; } - _REF_FILE_ENTRY (const std::wstring &name = L"", _REF_FOLDER *parent = nullptr, ENTRYTYPE type = ENTRYTYPE::UNKNOWN): - swName (name), eType (type), rfParent (parent) {} - protected: - std::wstring swFullName = L""; - ENTRYTYPE eType = ENTRYTYPE::UNKNOWN; - } REF_FILE_ENTRY; - typedef struct _REF_FOLDER: public _REF_FILE_ENTRY - { - std::vector vecChildrens; - _REF_FOLDER (const std::wstring &name = L"", _REF_FOLDER *parent = nullptr): - REF_FILE_ENTRY (name, parent, REF_FILE_ENTRY::ENTRYTYPE::FOLDER) {} - } REF_FOLDER; - std::wstring _REF_FILE_ENTRY::fullname () - { - if (std::wnstring::empty (swFullName)) - { - if (rfParent) swFullName = rfParent->fullname () + L"\\" + swName; - else swFullName = swName; - } - return swFullName; - } - size_t _REF_FILE_ENTRY::path (std::vector &output) - { - output.clear (); - if (rfParent) rfParent->path (output); - output.push_back (swName); - return output.size (); - } - typedef struct _REF_FILE: public REF_FILE_ENTRY - { - _REF_FILE (const std::wstring &name = L"", _REF_FOLDER *parent = nullptr): - REF_FILE_ENTRY (name, parent, REF_FILE_ENTRY::ENTRYTYPE::FILE) {} - } REF_FILE; - - // ReverseMap - - typedef struct _SCOPE_AND_ITEM_INFO - { - WORD wParent; - WORD wFullPathLength; - DWORD dwHashCode; - // ֱʹãʹ÷ name_offset - WORD wNameOffset; - WORD wIndex; - DWORD name_offset () const - { - return (DWORD)wNameOffset | (((dwHashCode >> 24) & 0xF) << 16); - } - bool name_in_ascii () const { return dwHashCode & 0x20000000; } - bool is_scope () const { return dwHashCode & 0x10000000; } - auto Item1 () const { return wParent; } - auto Item2 () const { return wFullPathLength; } - auto Item3 () const { return dwHashCode; } - auto Item4 () const { return name_offset (); } - auto Item5 () const { return wIndex; } - } SCOPE_AND_ITEM_INFO; - - struct basic_sect - { - section § - basic_sect (section &s): sect (s) {} - explicit operator section () { return sect; } - SectionType type () const { return sect.type (); } - }; - struct basic_sect_func - { - public: - virtual bool valid () = 0; - virtual void reset () = 0; - virtual bool parse () = 0; - }; -#define counter(_count_, _variable_) for (size_t _variable_ = 0, _counter_##_variable_##_total_ = _count_; _variable_ < _counter_##_variable_##_total_; _variable_ ++) - struct sect_pridesp: public basic_sect, public basic_sect_func - { - sect_pridesp (section &s): basic_sect (s) - { - if (s.type () != SectionType::PriDescriptor) throw std::exception ("Error: Section type error."); - parse (); - } - struct ContentStruct - { - WORD wFlags = 0; // ־ / flags - WORD wIncFileListIndex = -1; // ļбڣIncluded File ListΪ 0xFFFF - WORD wUnknown1 = -1; // δ֪0 - WORD wHieraScheCount = 0; // Hierarchical Schema - WORD wDecInfoCount = 0; // Decision Info - WORD wResMapCount = 0; // Resource Map - WORD wResMapBegIndex = -1; // Դӳ䣨primary resource mapĽ 0xFFFF - WORD wRefFileCount = 0; // Referenced File - WORD wDataItemCount = 0; // Data Item - WORD wUnknown2 = -1; // δ֪0 - ContentStruct () = default; - ContentStruct (WORD f, WORD inc, WORD unk1, WORD hiera, WORD dec, WORD res, WORD resBeg, WORD ref, WORD data, WORD unk2) - : wFlags (f), wIncFileListIndex (inc), wUnknown1 (unk1), wHieraScheCount (hiera), - wDecInfoCount (dec), wResMapCount (res), wResMapBegIndex (resBeg), wRefFileCount (ref), - wDataItemCount (data), wUnknown2 (unk2) {} - } content; - std::vector > vec_ref_hs; - std::vector > vec_ref_deci; - std::vector > vec_ref_rm; - std::vector > vec_ref_rf; - std::vector > vec_ref_dati; - ref_sect primary_resmap; - bool valid () { return content.wUnknown1 == 0 && content.wUnknown2 == 0; } - void reset () - { - vec_ref_hs.clear (); - vec_ref_deci.clear (); - vec_ref_rm.clear (); - vec_ref_rf.clear (); - vec_ref_dati.clear (); - primary_resmap.reset (); - content = {0, (WORD)-1, (WORD)-1, 0, 0, 0, (WORD)-1, 0, 0, (WORD)-1}; - } - bool parse () - { - reset (); - HRESULT hr = sect.childst.seek (); - istreamstream fp (sect.childst.ifile); - DWORD dwContent = 0; - hr = sect.childst.ifile->Read (&content, sizeof (content), &dwContent); - if (!valid ()) return false; - if (content.wResMapBegIndex != 0xFFFF) primary_resmap.index = content.wResMapBegIndex; - counter (content.wHieraScheCount, i) - { - vec_ref_hs.push_back (fp.read_bytes ()); - } - counter (content.wDecInfoCount, i) - { - vec_ref_deci.push_back (fp.read_bytes ()); - } - counter (content.wResMapCount, i) - { - vec_ref_rm.push_back (fp.read_bytes ()); - } - counter (content.wRefFileCount, i) - { - vec_ref_rf.push_back (fp.read_bytes ()); - } - counter (content.wDataItemCount, i) - { - vec_ref_dati.push_back (fp.read_bytes ()); - } - return true; - } - }; - struct sect_hierasche: public basic_sect, public basic_sect_func - { - struct - { - struct - { - WORD wUnknown1 = 0; // δ֪1 - WORD wUniqRMNameLen = 0; // ԴӳΨһȣַֹ - WORD wResMapNameLen = 0; // ԴӳƳȣַֹ - WORD wUnknown2 = -1; // unknown, zero - } part1; - struct - { - // hname ʶ extended ڣ - // hname identifier: only present in the extended Hierarchical Schema Section. - // Observed values are "[def_hnames] \0" and "[def_hnamesx] \0". - CHAR szHNameExt [16] = {0}; - } part2; - struct - { - HSCHEMA_VERSION_INFO verSchema; // λ schema 汾Ϣ - } part3; - struct - { - std::wstring swUniqueRMName = L""; // ԴӳΨһunique name - std::wstring swResMapName = L""; // name of resource map - WORD wUnknown3 = -1; // unknown, zero - WORD wMaxFullPathLength = 0; // length of longest full path of all resource names - WORD wUnknown3_5 = -1; // unknown, zero - DWORD dwResNameCount = 0; // number of resource names, usually number of scopes + items - DWORD dwScopeCount = 0; // number of scopes - DWORD dwItemsCount = 0; // number of items - DWORD dwUniNameLemgth = 0; // length of Unicode name block - DWORD dwUnknown4 = 0; // unknown - // unknown at 70 + ?: only present in the extended Hierarchical - // Schema Section and if hname identifier is "[def_hnamesx] \0". - DWORD dwUnknown5 = 0; - void *get_buf_first_dir () { return &wUnknown3; } - size_t get_buf_size_of () - { - return sizeof (wUnknown3) + sizeof (wMaxFullPathLength) + sizeof (wUnknown3_5) + - sizeof (dwScopeCount) + sizeof (dwItemsCount) + sizeof (dwResNameCount) + - sizeof (dwUniNameLemgth) + sizeof (dwUnknown4) + - sizeof (dwUnknown5); - } - } part4; - } content; - BOOL ex = FALSE; - BOOL exHName = FALSE; - std::vector vec_scope_and_items; - std::vector vec_scope_ex; - std::vector vec_item_index; - std::vector vec_scopes; - std::vector vec_items; - sect_hierasche (section &s): basic_sect (s) - { - if (s.type () != SectionType::HierarchicalSchema && s.type () != SectionType::HierarchicalSchemaEx) throw std::exception ("Error: Section type error."); - if (s.type () == SectionType::HierarchicalSchemaEx) ex = TRUE; - } - void throwexpect (const std::string &reason = "Error: unexpected value.") - { - throw std::exception (reason.c_str ()); - } - bool valid () - { - return content.part1.wUnknown1 == 1 && - content.part1.wUnknown2 == 0 && - content.part3.verSchema.dwUnknown1 == 0 && - content.part4.wUnknown3 == 0 && - content.part4.wUnknown3_5 == 0 && - content.part4.dwResNameCount == content.part3.verSchema.dwScopeCount + content.part3.verSchema.dwItemCount && - content.part4.dwScopeCount == content.part3.verSchema.dwScopeCount && - content.part4.dwItemsCount == content.part3.verSchema.dwItemCount && - content.part4.dwUniNameLemgth == content.part3.verSchema.dwItemCount && - content.part4.swUniqueRMName.length () == content.part1.wUniqRMNameLen && - content.part4.swResMapName.length () == content.part1.wResMapNameLen - 1; - } - void reset () - { - vec_scope_and_items.clear (); - vec_scope_ex.clear (); - vec_item_index.clear (); - vec_items.clear (); - vec_scopes.clear (); - ZeroMemory (&content.part1, sizeof (content.part1)); - content.part1.wUnknown2 = -1; - ZeroMemory (&content.part2, sizeof (content.part2)); - ZeroMemory (&content.part3, sizeof (content.part3)); - content.part3.verSchema.dwUnknown1 = -1; - content.part4.swUniqueRMName = L""; - content.part4.swResMapName = L""; - ZeroMemory (content.part4.get_buf_first_dir (), content.part4.get_buf_size_of ()); - content.part4.wUnknown3 = -1; - content.part4.wUnknown3_5 = -1; - } - bool parse () - { - reset (); - sect.childst.seek (); - istreamstream fp (sect.childst.ifile); - if (sect.childst.size == 0) return true; - auto &uniqueNameLength = content.part1.wUniqRMNameLen; - auto &nameLength = content.part1.wResMapNameLen; - fp >> content.part1; - if (content.part1.wUnknown1 != 1 || content.part1.wUnknown2 != 0) throwexpect (); - auto &extendedVersion = ex; - if (ex) - { - fp >> content.part2; - if (pri_sectid (content.part2.szHNameExt, 16).equals ("[def_hnamesx]")) exHName = true; - else if (pri_sectid (content.part2.szHNameExt, 16).equals ("[def_hnames]")) exHName = false; - else return false; - } - else exHName = false; - auto &extendedHNames = exHName; - auto &majorVersion = content.part3.verSchema.wMajor; - auto &minorVersion = content.part3.verSchema.wMinor; - auto &checksum = content.part3.verSchema.dwCheckSum; - auto &numScopes = content.part3.verSchema.dwScopeCount; - auto &numItems = content.part3.verSchema.dwItemCount; - fp >> content.part3; - if (content.part3.verSchema.dwUnknown1 != 0) throwexpect (); - auto &Version = content.part3.verSchema; - auto &UniqueName = content.part4.swUniqueRMName; - auto &Name = content.part4.swResMapName; - content.part4.swUniqueRMName = fp.read_string_endwith_null_w (); - content.part4.swResMapName = fp.read_string_endwith_null_w (); - fp.expect (0, true, &content.part4.wUnknown3); - auto &maxFullPathLength = content.part4.wMaxFullPathLength; - fp >> content.part4.wMaxFullPathLength; - fp.expect (0, true, &content.part4.wUnknown3_5); - fp.expect (numScopes + numItems, true, &content.part4.dwResNameCount); - fp.expect (numScopes, true, &content.part4.dwScopeCount); - fp.expect (numItems, true, &content.part4.dwItemsCount); - auto &unicodeDataLength = content.part4.dwUniNameLemgth; - fp >> unicodeDataLength; - fp >> content.part4.dwUnknown4; - if (extendedHNames) fp >> content.part4.dwUnknown5; - auto &scopeAndItemInfos = vec_scope_and_items; - scopeAndItemInfos.resize (content.part4.dwResNameCount); - fp.read (scopeAndItemInfos.data (), (content.part4.dwResNameCount) * sizeof (SCOPE_ITEM_INFO)); - auto &scopeExInfos = vec_scope_ex; - scopeExInfos.resize (numScopes); - fp.read (scopeExInfos.data (), numScopes * sizeof (SCOPE_EX_INFO)); - auto &itemIndexPropertyToIndex = vec_item_index; - itemIndexPropertyToIndex.resize (numItems); - fp.read (itemIndexPropertyToIndex.data (), sizeof (ITEM_INDEX) * numItems); - auto unicodeDataOffset = fp.position (); - auto asciiDataOffset = fp.position () + unicodeDataOffset * 2; - auto &scopes = vec_scopes; - auto &items = vec_items; - scopes.resize (numScopes); - items.resize (numItems); - counter (content.part4.dwResNameCount, i) - { - istreamstream::fsize_t pos = 0; - if (scopeAndItemInfos [i].name_in_ascii ()) - pos = asciiDataOffset + scopeAndItemInfos [i].name_offset (); - else pos = unicodeDataOffset + scopeAndItemInfos [i].name_offset () * 2; - fp.seek (pos, istreamstream::seekpos::start); - std::wstring name; - if (scopeAndItemInfos [i].wFullPathLength != 0) - { - if (scopeAndItemInfos [i].name_in_ascii ()) - name = StringToWString (fp.read_string_endwith_null_a ()); - else name = fp.read_string_endwith_null_w (); - } - ITEM_INDEX index = scopeAndItemInfos [i].index (); - if (scopeAndItemInfos [i].is_scope ()) - { - if (!scopes [index].bIsNull) throwexpect (); - else scopes.at (index) = RES_MAP_SCOPE (index, nullptr, name, false); - } - else - { - if (!items [index].bIsNull) throwexpect (); - else items.at (index) = RES_MAP_ITEM (index, nullptr, name, false); - } - } - counter (content.part4.dwResNameCount, i) - { - ITEM_INDEX index = scopeAndItemInfos [i].index (); - WORD parent = scopeAndItemInfos [scopeAndItemInfos [i].wParentScopeIndex].index (); - if (parent != 0xFFFF) - { - if (scopeAndItemInfos [i].is_scope ()) - { - if (parent != index) scopes.at (index).pParent = &scopes [parent]; - } - else items.at (index).pParent = &scopes [parent]; - } - } - counter (numScopes, i) - { - auto &scope = scopes [i]; - auto &children = scope.vecChild; - counter (scopeExInfos [i].wChildCount, j) - { - auto &saiInfo = scopeAndItemInfos [scopeExInfos [i].wFirstChild + j]; - if (saiInfo.is_scope ()) children.push_back (&scopes.at (saiInfo.index ())); - else children.push_back (&items.at (saiInfo.index ())); - } - } - return valid (); - } - }; - struct sect_decinfo: public basic_sect, public basic_sect_func - { - sect_decinfo (section &s): basic_sect (s) - { - if (s.type () != SectionType::DecisionInfo) throw std::exception ("Error: Section type error."); - } - struct - { - WORD wDistQualiCount = 0; // ͬ distinct qualifiers / number of distinct qualifiers - WORD wQualifierCount = 0; // qualifiers - WORD wQualSetsCount = 0; // qualifier sets - WORD wDecisionCount = 0; // decisions / number of decisions - WORD wEntriesCount = 0; // index table Ŀ / number of entries in the index table - WORD wQualiValueLength = 0; // qualifier value block ȣַ / length of qualifier value block in characters - } content; - std::vector vec_qua_set; - std::vector vec_qua; - std::vector vec_dec; - bool valid () - { - return content.wDecisionCount || - content.wQualifierCount || - content.wDistQualiCount || - content.wQualSetsCount || - content.wEntriesCount || - content.wQualiValueLength || - vec_qua.size () || - vec_qua_set.size () || - vec_dec.size () || - 0; - } - void reset () - { - vec_qua.clear (); - vec_qua_set.clear (); - vec_dec.clear (); - ZeroMemory (&content, sizeof (content)); - } - bool parse () - { - reset (); - istreamstream fp (sect.childst.ifile); - sect.childst.seek (); - auto &numDistinctQualifiers = content.wDistQualiCount; - auto &numQualifiers = content.wQualifierCount; - auto &numQualifierSets = content.wQualSetsCount; - auto &numDecisions = content.wDecisionCount; - auto &numIndexTableEntries = content.wEntriesCount; - auto &totalDataLength = content.wQualiValueLength; - fp >> content; - std::vector decisionInfos (numDecisions); - std::vector qualifierSetInfos (numQualifierSets); - std::vector qualifierInfos (numQualifiers); - std::vector distinctQualifierInfos (numDistinctQualifiers); - std::vector indexTable (numIndexTableEntries); - auto &vec_dis_qua_info = distinctQualifierInfos; - auto &vec_qua_info = qualifierInfos; - auto &vec_qua_set_info = qualifierSetInfos; - auto &indexs = indexTable; - auto &vec_dec_info = decisionInfos; - fp.read (decisionInfos.data (), sizeof (DECISION_INFO) * numDecisions); - fp.read (qualifierSetInfos.data (), sizeof (DECISION_INFO) * numQualifierSets); - fp.read (qualifierInfos.data (), sizeof (QUALIFIER_INFO) * numQualifiers); - for (auto &it : qualifierInfos) { if (it.wUnknown1 != 0) throw std::exception ("Error: unexpective value."); } - fp.read (distinctQualifierInfos.data (), sizeof (DISTINCE_QUALIFIER_INFO) * numDistinctQualifiers); - fp.read (indexTable.data (), sizeof (ITEM_INDEX) * numIndexTableEntries); - auto currentpos = fp.position (); - std::vector buf (128); - fp.read (buf.data (), 128 * sizeof (WCHAR)); - fp.seek (currentpos, istreamstream::seekpos::start); - counter (content.wQualifierCount, i) - { - auto &dinfo = vec_dis_qua_info [vec_qua_info [i].wDistQualiIndex]; - auto &qinfo = vec_qua_info [i]; - fp.seek (currentpos + dinfo.wQualiValueOffset * 2, istreamstream::seekpos::start); - std::wstring value = fp.read_string_endwith_null_w (); - QUALIFIER qual (i, (QUALIFIER_TYPE)dinfo.wQualiType, qinfo.wPriority, (double)qinfo.wFallbackScore * 0.001, value); - vec_qua.push_back (qual); - } - counter (content.wQualSetsCount, i) - { - std::vector quals; - auto qset = vec_qua_set_info [i]; - counter (qset.wQualiSetsCount, j) - { - auto &ind = indexs [qset.wFirstQualiIndex + j]; - auto &qual = vec_qua [ind]; - quals.push_back (qual); - } - vec_qua_set.emplace_back (QUALIFIER_SET (i, quals)); - } - counter (content.wDecisionCount, i) - { - auto &dec = vec_dec_info [i]; - std::vector qsets; - counter (dec.wQualiSetsCount, j) - { - auto &ind = indexs [dec.wFirstQualiIndex + j]; - auto &qset = vec_qua_set.at (ind); - qsets.emplace_back (qset); - } - vec_dec.emplace_back (DECISION (i, qsets)); - } - return valid (); - } - }; - struct sect_resmap: public basic_sect, public basic_sect_func - { - sect_resmap (section &s): basic_sect (s) - { - if (s.type () != SectionType::ResourceMap && s.type () != SectionType::ResourceMap2) throw std::exception ("Error: Section type error."); - if (s.type () == SectionType::ResourceMap2) ver2 = true; - else ver2 = false; - } - struct - { - WORD wEnvRefLength = 0; // length of environment references block // environmentReferencesLength - WORD wRefCount = 0; // number of references in environment references block // numEnvironmentReferences - WORD wHSSectIndex = 0; // section index of Hierarchical Schema Section // SchemaSection - WORD wHSRefLength = 0; // length of hierarchical schema reference block // hierarchicalSchemaReferenceLength - WORD wDecInfSectIndex = 0; // section index of Decision Info Section // DecisionInfoSection - WORD wResTypeEntCount = 0; // number of entries in resource value type table // resourceValueTypeTableSize - WORD wItemEntCount = 0; // number of entries in item to iteminfo group table // ItemToItemInfoGroupCount - WORD wItemGroupEntCount = 0; // number of entries in iteminfo group table // itemInfoGroupCount - DWORD dwItemTableEntCount = 0; // number of entries in iteminfo table // itemInfoCount - DWORD dwCandidateCount = 0; // number of candidates // numCandidates - DWORD dwEmbededDataCount = 0; // length of embedded data bloc // dataLength - DWORD dwTableExtCount = 0; // length of table extension block // largeTableLength - } content; - BOOL ver2 = FALSE; - std::vector bvecEnvRefData; - std::vector bvecScheRefData; - HSCHEMA_REF_BLOCK hschema_ref; - std::vector vecResTypes; - std::vector vecItemToItemInfoGroup; - std::vector vecItemInfoGroups; - std::vector vecItemInfo; - std::vector vecCandidateInfo; - std::map mapCandidateSet; - bool valid () - { - if (parseError) return false; - UINT64 *p = (UINT64 *)&content; - bool res = false; - res = (!ver2) - ? (content.wEnvRefLength != 0 && content.wRefCount != 0) - : (content.wEnvRefLength == 0 && content.wRefCount == 0); - if (!res) return false; - if (content.wHSRefLength != 0) - { - if (hschema_ref.verHschema.dwUnknown1 != 0) return false; - if (hschema_ref.part2.wUnknown1 != 0) return false; - } - return res; - } - void reset () - { - parseError = false; - bvecEnvRefData.clear (); - bvecScheRefData.clear (); - vecResTypes.clear (); - vecItemToItemInfoGroup.clear (); - vecItemInfoGroups.clear (); - vecItemInfo.clear (); - vecCandidateInfo.clear (); - UINT64 *p = (UINT64 *)&content; - bool res = false; - size_t len = sizeof (content) / sizeof (UINT64); - for (size_t i = 0; i < len; i ++) p [i] = 0; - hschema_ref = HSCHEMA_REF_BLOCK (); - } - bool parse (); - private: - BOOL parseError = false; - }; - struct sect_dataitem: public basic_sect - { - sect_dataitem (section &s): basic_sect (s) - { - if (s.type () != SectionType::DataItem) throw std::exception ("Error: Section type error."); - } - struct - { - DWORD dwUnknown1 = -1; // unknown, zero - WORD wStrCount = 0; // number of stored strings - WORD wBlobCount = 0; // number of stored blobs - DWORD dwStoredLength = 0; // total length of stored data - } content; - std::vector vecDataItems; - bool valid () - { - return content.dwUnknown1 == 0; - } - void reset () - { - vecDataItems.clear (); - ZeroMemory (&content, sizeof (content)); - content.dwUnknown1 = -1; - } - bool parse () - { - reset (); - sect.childst.seek (); - istreamstream fp (sect.childst.ifile); - auto sectionPosition = fp.position (); - fp >> content; - std::vector &dataItems = vecDataItems; - istreamstream::fsize_t dataStartOffset = - fp.position () + - content.wStrCount * 2 * sizeof (WORD) + - content.wBlobCount * 2 * sizeof (DWORD); - dataItems.reserve (content.wStrCount + content.wBlobCount); - std::vector storedStringInfos (content.wStrCount); - std::vector storedBlobInfo (content.wBlobCount); - fp.read (storedStringInfos.data (), sizeof (STORED_STRING_INFO) * content.wStrCount); - fp.read (storedBlobInfo.data (), sizeof (STORED_BLOB_INFO) * content.wBlobCount); - size_t cnt = 0; - counter (content.wStrCount, i) - { - auto &sstr = storedStringInfos.at (i); - dataItems.push_back (BYTE_SPAN (dataStartOffset + sstr.wStringOffset, sstr.wStringLength)); - } - counter (content.wBlobCount, i) - { - auto &sblo = storedBlobInfo.at (i); - dataItems.push_back (BYTE_SPAN (dataStartOffset + sblo.dwBlobOffset, sblo.dwBlobLength)); - } - return valid (); - } - }; - struct sect_reffile: public basic_sect - { - sect_reffile (section &s): basic_sect (s) - { - if (s.type () != SectionType::ReferencedFile) throw std::exception ("Error: Section type error."); - } - struct - { - WORD wRootCount = 0; // number of roots - WORD wFolderCount = 0; // number of folders - WORD wFileCount = 0; // number of folders - WORD wUnknown1 = -1; // unknown, zero - DWORD dwNameLength = 0; // length of Unicode name block in characters - } content; - std::vector vecFolderInfo; - std::vector vecFileInfo; - std::vector vecRefFolders; - std::vector vecRefFiles; - bool valid () - { - return content.wUnknown1 == 0; - } - void reset () - { - vecFolderInfo.clear (); - vecFileInfo.clear (); - vecRefFiles.clear (); - vecRefFolders.clear (); - ZeroMemory (&content, sizeof (content)); - content.wUnknown1 = -1; - } - bool parse () - { - reset (); - sect.childst.seek (); - istreamstream fp (sect.childst.ifile); - fp >> content; - counter (content.wFolderCount, i) - { - REF_FOLDER_INFO folder; - fp >> folder; - if (folder.wUnknown1 != 0) throw std::exception ("Error: cannot get valid data in ReferencedFile Section."); - vecFolderInfo.push_back (folder); - } - counter (content.wFileCount, i) - { - REF_FILE_INFO file; - fp >> file; - vecFileInfo.push_back (file); - } - auto dataStartPosition = fp.position (); - auto &referencedFolders = vecRefFolders; - using seekpos = istreamstream::seekpos; - counter (content.wFolderCount, i) - { - fp.seek (dataStartPosition + vecFolderInfo [i].dwFolderNameOffset * 2, seekpos::start); - std::wstring name = fp.read_string_w (vecFolderInfo [i].wFolderNameLength); - referencedFolders.push_back (REF_FOLDER (name)); - } - counter (content.wFolderCount, i) - { - if (vecFolderInfo [i].wParentIndex != 0xFFFF) - { - referencedFolders [i].rfParent = &referencedFolders [vecFolderInfo [i].wParentIndex]; - } - } - counter (content.wFileCount, i) - { - REF_FILE file; - auto &fileInfo = vecFileInfo [i]; - fp.seek (dataStartPosition + fileInfo.dwFileNameOffset * 2, seekpos::start); - std::wstring name = fp.read_string_w (fileInfo.wFileNameLength); - file.swName = name; - REF_FOLDER *parent = nullptr; - if (vecFileInfo [i].wParentIndex != 0xFFFF) parent = &referencedFolders [fileInfo.wParentIndex]; - file.rfParent = parent; - vecRefFiles.push_back (file); - } - counter (content.wFolderCount, i) - { - auto &folderInfo = vecFolderInfo [i]; - auto &referencedFolder = referencedFolders [i]; - counter (folderInfo.wFolderCount, j) - { - auto &folder = referencedFolders [folderInfo.wFirstFolderIndex + j]; - referencedFolder.vecChildrens.push_back (&folder); - } - counter (folderInfo.wFileCount, j) - { - auto &file = vecRefFiles [folderInfo.wFirstFileIndex + j]; - referencedFolder.vecChildrens.push_back (&file); - } - } - return valid (); - } - }; - struct sect_revmap: public basic_sect, public basic_sect_func - { - sect_revmap (section &s): basic_sect (s) - { - if (s.type () != SectionType::ReverseMap) throw std::exception ("Error: Section type error."); - } - struct - { - struct - { - DWORD dwItemsNumber = 0; - DWORD dwCheckCode = 0; - } part1; - struct - { - WORD wFullPathLength = 0; - WORD wUnknown1 = -1; // 0 - DWORD dwEntries = 0; - DWORD dwScopes = 0; - DWORD dwCheckItemsNumber = 0; - DWORD dwUnicodeDataLength = 0; - DWORD dwSkipPadding = 0; - } part2; - } content; - std::vector adwMap; - std::vector aobjScopeAndItem; - std::vector aobjScopeExts; - std::vector awItemIndexs; - std::vector aobjScopes; - std::vector aobjItems; - bool valid () - { - bool res = content.part2.wUnknown1 == 0 && - content.part2.dwCheckItemsNumber == content.part1.dwItemsNumber || - 0; - return res; - } - void reset () - { - adwMap.clear (); - aobjScopeAndItem.clear (); - aobjScopeExts.clear (); - awItemIndexs.clear (); - aobjScopes.clear (); - aobjItems.clear (); - ZeroMemory (&content.part1, sizeof (content.part1)); - ZeroMemory (&content.part2, sizeof (content.part2)); - content.part2.wUnknown1 - 1; - } - bool parse () - { - reset (); - sect.childst.seek (); - istreamstream fp (sect.childst.ifile); - fp >> content.part1; - bool chk = content.part1.dwCheckCode == fp.size () - 8; - if (!chk) return false; - adwMap.resize (content.part1.dwItemsNumber); - fp.read (adwMap.data (), sizeof (DWORD) * content.part1.dwItemsNumber); - fp >> content.part2; - chk = content.part2.wUnknown1 == 0 && content.part2.dwCheckItemsNumber == content.part1.dwItemsNumber; - if (!chk) return false; - counter (content.part2.dwScopes + content.part1.dwItemsNumber, i) - { - SCOPE_AND_ITEM_INFO sii; - fp >> sii; - aobjScopeAndItem.push_back (sii); - } - counter (content.part2.dwScopes, i) - { - SCOPE_EX_INFO sei; - fp >> sei; - if (sei.wUnknown1 != 0) throw std::exception ("Error: read invalid data in ReverseMap Section."); - aobjScopeExts.push_back (sei); - } - awItemIndexs.resize (content.part1.dwItemsNumber); - fp.read (awItemIndexs.data (), content.part1.dwItemsNumber * sizeof (ITEM_INDEX)); - auto unicodeDataOffset = fp.position (), - asciiDataOffset = fp.position () + content.part2.dwUnicodeDataLength * 2; - aobjScopes.resize (content.part2.dwScopes); - aobjItems.resize (content.part1.dwItemsNumber); - counter (content.part1.dwItemsNumber + content.part2.dwScopes, i) - { - auto &sii = aobjScopeAndItem [i]; - bool nameInAscii = sii.name_in_ascii (); - UINT64 pos = (nameInAscii ? asciiDataOffset : unicodeDataOffset) + (sii.Item4 () * (nameInAscii ? 1 : 2)); - fp.seek (pos, istreamstream::seekpos::start); - std::wstring name; - if (sii.Item2 ()) - { - if (nameInAscii) name = StringToWString (fp.read_string_endwith_null_a ()); - else name = fp.read_string_endwith_null_w (); - } - auto index = sii.Item5 (); - bool isScope = sii.is_scope (); - if (isScope) - { - auto &it = aobjScopes.at (index); - if (!it.bIsNull) throw std::exception ("Error: invalid scope data in ReverseMap Section."); - else it = RES_MAP_SCOPE (index, nullptr, name); - } - else - { - auto &it = aobjItems.at (index); - if (!it.bIsNull) throw std::exception ("Error: invalid item data in ReverseMap Section."); - else it = RES_MAP_ITEM (index, nullptr, name); - } - } - counter (content.part1.dwItemsNumber + content.part2.dwScopes, i) - { - auto &sii = aobjScopeAndItem [i]; - auto index = sii.Item5 (); - bool isScope = sii.is_scope (); - auto parent = aobjScopeAndItem [sii.Item1 ()].Item5 (); - if (parent != 0xFFFF) - { - if (isScope && parent != index) - { - auto &it = aobjScopes.at (index); - it.pParent = &aobjScopes.at (parent); - } - else - { - auto &it = aobjItems.at (index); - it.pParent = &aobjScopes.at (parent); - } - } - - } - counter (content.part2.dwScopes, i) - { - auto &sei = aobjScopeExts [i]; - auto &scope = aobjScopes [i]; - counter (sei.wChildCount, j) - { - auto &saiInfo = aobjScopeAndItem [sei.wFirstChild + j]; - bool isScope = saiInfo.is_scope (); - if (isScope) - { - auto &prt = aobjScopes [saiInfo.Item5 ()]; - scope.vecChild.push_back (&prt); - } - else - { - auto &prt = aobjItems [saiInfo.Item5 ()]; - scope.vecChild.push_back (&prt); - } - } - } - return true; - } - }; - struct sect_unknown: public basic_sect - { - sect_unknown (section &s): basic_sect (s) {} - UINT64 dwLength = 0; - void reset () - { - dwLength = 0; - } - bool parse () - { - reset (); - sect.childst.seek (); - istreamstream fp (sect.childst.ifile); - dwLength = fp.size () - fp.position (); - return true; - } - size_t bytes (std::vector &bytes) - { - sect.childst.seek (); - istreamstream fp (sect.childst.ifile); - bytes.resize (dwLength); - size_t readlen = 0; - fp.read (bytes.data (), dwLength, &readlen); - bytes.resize (readlen > dwLength ? dwLength : readlen); - return readlen; - } - }; -} -class prifile -{ - private: - IStream *pfile = nullptr; - head header; foot footer; - std::vector toclist; - std::vector
sectlist; - enum class searchtype - { - unknown, - string, - file - }; - struct search_key - { - std::wnstring key = L""; - searchtype type = searchtype::unknown; - search_key (const std::wstring &k = L"", searchtype t = searchtype::unknown): - key (k), type (t) {} - bool operator == (const search_key &another) const { return key == another.key && type == another.type; } - bool operator == (const std::wstring &an_key) const { return key.equals (an_key); } - operator searchtype () const { return type; } - operator LPCWSTR () const { return key.c_str (); } - }; - struct search_value - { - std::wstring value = L""; - bool isfind = false; - int begindex = -1; - bool finishsearch = false; - operator LPCWSTR () const { return value.c_str (); } - operator bool () const { return isfind; } - }; - std::map vecTaskSearch; - bool isrunningtask = false; - public: - void close () - { - header = head (); - footer = foot (); - toclist.clear (); - sectlist.clear (); - } - bool load (IStream *ifile) - { - close (); - if (!ifile) return false; - ifile->Seek (lint (0), STREAM_SEEK_SET, nullptr); - DWORD dwhead = 0, dwfoot = 0; - ifile->Read (&header, sizeof (header), &dwhead); - if (!dwhead) return false; - if (!header.valid ()) return false; - ifile->Seek (lint (header.dwFileSize - 16), STREAM_SEEK_SET, nullptr); - ifile->Read (&footer, sizeof (footer), &dwfoot); - if (!dwfoot) return false; - if (!footer.valid (header)) return false; - pfile = ifile; - inittoc (); - initsect (); - return true; - } - operator istreamstream () { return istreamstream (pfile); } - pri::sect_pridesp section_pri_descriptor () - { - for (auto &it : sectlist) - { - if (it.type () == SectionType::PriDescriptor) - { - try - { - auto sect = pri::sect_pridesp (it); - sect.parse (); - return sect; - } - catch (const std::exception &e) { continue; } - } - } - throw std::exception ("Error: cannot get the pri descriptor section."); - } - section &get_section_by_ref (int index) - { - return sectlist.at (index); - } - template SectionT get_section_by_ref (pri::ref_sect ref) - { - return SectionT (sectlist.at (ref.index)); - } - void inittoc () - { - toclist.clear (); - pfile->Seek (lint (header.dwToCOffset), STREAM_SEEK_SET, nullptr); - for (size_t i = 0; i < header.wSectCount; i ++) - { - tocentry toc; - DWORD dwRead; - pfile->Read (&toc, sizeof (toc), &dwRead); - toclist.push_back (toc); - } - } - void initsect () - { - sectlist.clear (); - istreamstream iss (pfile); - for (size_t i = 0; i < header.wSectCount; i ++) - { - iss.seek (header.dwSectStartOffset + toclist [i].dwSectOffset, istreamstream::seekpos::start); - section sect (this->pfile, *this); - iss.read (sect.head); - iss.seek (sect.head.dwLength - 16 - 24); - iss.read (sect.foot); - iss.seek (header.dwSectStartOffset + toclist [i].dwSectOffset, istreamstream::seekpos::start); - iss.seek (32); - sect.childst.set (iss.position (), sect.head.dwLength - 16 - 24); - sectlist.push_back (sect); - } - } - // ÷ - // auto rmsect = this->get_resmap_sect_by_ref (candidateSet.refResMapItem); - // rmsect.parse (); - // auto item = rmsect.vec_items [candidateSet.refResMapItem.iItemIndex]; - auto get_resmap_sect_by_ref (pri::RES_MAP_ITEM_REF resourceMapItemRef) - { - return get_section_by_ref (resourceMapItemRef.wSchemaSect); - } - // ÷ - // auto ds = get_dataitem_sect_by_ref (dataItemRef); - // ds.parse (); - // ds.vecDataItems.at (dataItemRef.get ()); - auto get_dataitem_sect_by_ref (pri::DATA_ITEM_REF dataItemRef) - { - return get_section_by_ref (dataItemRef.iDataSectIndex); - } - bool get_reffile_by_ref (pri::REF_FILE_REF referencedFileRef, std::function callback) - { - try - { - auto sect = get_section_by_ref (section_pri_descriptor ().vec_ref_rf.front ()); - auto &rf = sect.vecRefFiles.at (referencedFileRef); - if (callback) callback (rf); - return true; - } - catch (const std::exception &e) - { - return false; - } - } - void end_taskrunning () { isrunningtask = false; } - static void search_task (prifile &priinst) - { - destruct ([&priinst] () { - priinst.end_taskrunning (); - }); - if (priinst.isrunningtask) return; - else priinst.isrunningtask = true; - auto &tasklist = priinst.vecTaskSearch; - - } - void across_all (std::wostream &out) - { - #ifdef _CONSOLE - struct loadingamine - { - const WCHAR *charcollect = L"-\\|/-\\|/"; - WCHAR nowchar = L' '; - bool isend = false; - bool enablecallback = true; - std::function callback = nullptr; - void exectask () - { - size_t cnt = 0; - size_t charlen = lstrlenW (charcollect); - std::function cb = callback; - while (!isend) - { - nowchar = charcollect [(cnt ++) % charlen]; - if (cb && enablecallback) cb (nowchar); - std::this_thread::sleep_for (std::chrono::milliseconds (300)); - } - } - void run () - { - std::thread th (&loadingamine::exectask, this); - th.detach (); - } - void jump () { isend = true; } - } loadchar; - destruct endt ([&loadchar] () { - loadchar.isend = true; - }); - std::wcout << L" 0 %"; - loadchar.callback = [] (const WCHAR &wch) { - wprintf (L"\r %c 0 %%", wch); - }; - loadchar.run (); - auto DiffSystemTimeMs = [] (const SYSTEMTIME &st1, const SYSTEMTIME &st2) -> LONGLONG - { - FILETIME ft1, ft2; - ULARGE_INTEGER t1, t2; - SystemTimeToFileTime (&st1, &ft1); - SystemTimeToFileTime (&st2, &ft2); - - t1.LowPart = ft1.dwLowDateTime; - t1.HighPart = ft1.dwHighDateTime; - t2.LowPart = ft2.dwLowDateTime; - t2.HighPart = ft2.dwHighDateTime; - - // FILETIME λ 100 루1 = 10,000,000 - LONGLONG diff100ns = t2.QuadPart - t1.QuadPart; - - // תΪ - return diff100ns / 10000; // 1 = 10,000 * 100ns - }; - out << L"Read Start: "; - WCHAR buf [64]; - SYSTEMTIME st_start; - GetLocalTime (&st_start); - swprintf (buf, 64, L"%4d.%02d.%02d %02d:%02d:%02d", - st_start.wYear, st_start.wMonth, st_start.wDay, - st_start.wHour, st_start.wMinute, st_start.wSecond); - out << buf << std::endl; - out << L"Sections: " << sectlist.size () << std::endl; - for (auto &it : sectlist) - { - out << L" " << it << std::endl; - } - out << std::endl; - auto pri_desp = this->section_pri_descriptor (); - loadchar.callback = nullptr; - loadchar.enablecallback = false; - out << L"Candidates: " << pri_desp.vec_ref_rm.size () << std::endl; - size_t cnt_i = 0; - for (auto &it : pri_desp.vec_ref_rm) - { - auto resmap_sect = this->get_section_by_ref (it); - resmap_sect.parse (); - if (!resmap_sect.hschema_ref.empty ()) continue; - auto decisionInfoSection = get_section_by_ref (resmap_sect.content.wDecInfSectIndex); - decisionInfoSection.parse (); - size_t cnt_j = 0; - for (auto &it_cs : resmap_sect.mapCandidateSet) - { - auto &candidateSet = it_cs.second; - auto rmsect = this->get_resmap_sect_by_ref (candidateSet.refResMapItem); - rmsect.parse (); - auto item = rmsect.vec_items [candidateSet.refResMapItem.iItemIndex]; - out << L" " << item.full_name () << std::endl; - size_t cnt_k = 0; - for (auto &candidate : candidateSet.vecCandidates) - { - std::wstring value; - if (candidate.source_file_index ()) - { - auto temp = get_reffile_by_ref (*candidate.source_file_index (), [&value] (pri::REF_FILE &rf) { - value += L""; - }); - } - else - { - pri::BYTE_SPAN byteSpan; - if (candidate.data_item_ref ()) - { - auto dis = this->get_dataitem_sect_by_ref (*candidate.data_item_ref ()); - dis.parse (); - byteSpan = dis.vecDataItems.at (candidate.data_item_ref ()->get ()); - } - else - { - if (candidate.data_position ()) byteSpan = *candidate.data_position (); - else byteSpan.isnull = true; - } - std::vector bytes (byteSpan.length + 2); - size_t ret; - HRESULT hr = byteSpan.get_bytes (pfile, bytes, &ret); - bytes.resize (bytes.size () + 2); - using restype = pri::RES_VALUE_TYPE; - switch (candidate.dwResType) - { - case restype::ASCIIPATH: - case restype::ASCIISTRING: - value += StringToWString ((CHAR *)bytes.data ()); break; - case restype::UTF8PATH: - case restype::UTF8STRING: - value += StringToWString ((CHAR *)bytes.data (), CP_UTF8); break; - case restype::STRING: - case restype::PATH: - value += (WCHAR *)bytes.data (); break; - case restype::EMBEDDEDDATA: - value += L"<" + std::to_wstring (ret) + L" bytes>"; break; - } - } - auto qualifierSet = decisionInfoSection.vec_qua_set [candidate.wQualifierSet]; - std::wstring qualifiers; - for (auto qual : qualifierSet.vecQuals) - { - std::wstring str = L" "; - str += EnumToStringW (qual.eType) + L" = " + qual.swValue + L"\n"; - qualifiers += str; - } - out << L" Value {" << value << L"}" << std::endl; - out << qualifiers; - double progress = (double)((cnt_i + (cnt_j + (double)cnt_k / candidateSet.vecCandidates.size ()) / resmap_sect.mapCandidateSet.size ()) / pri_desp.vec_ref_rm.size () * 100.0); - std::wcout << L"\r " - << loadchar.nowchar - << L" " - << std::fixed << std::setprecision (2) - << progress - << L" % [(" - << cnt_k - << L" / " - << candidateSet.vecCandidates.size () - << L") of (" - << cnt_j - << L" / " - << resmap_sect.mapCandidateSet.size () - << L") of (" - << cnt_i - << L" / " - << pri_desp.vec_ref_rm.size () - << L")]" - << L" " - ; - cnt_k ++; - } - cnt_j ++; - } - int i = 0; - cnt_i ++; - } - int j = 0; - std::wcout << L"\r 100 % " << std::endl; - out << L"Read Completed: "; - SYSTEMTIME st_end; - GetLocalTime (&st_end); - ZeroMemory (buf, 60 * sizeof (WCHAR)); - swprintf (buf, 64, L"%4d.%02d.%02d %02d:%02d:%02d", - st_end.wYear, st_end.wMonth, st_end.wDay, - st_end.wHour, st_end.wMinute, st_end.wSecond); - out << buf << std::endl; - out << L"Time Spend: " << DiffSystemTimeMs (st_start, st_end) * 0.001 << L"s" << std::endl; - #endif - } -}; -bool pri::sect_resmap::parse () - -{ - reset (); - istreamstream fp (sect.childst.ifile); - sect.childst.seek (); - ulint sectpos = 0; - fp->Seek (lint (0), STREAM_SEEK_CUR, sectpos.ptr_union ()); - fp->Read (&content, sizeof (content), nullptr); - bool res = (!ver2) ? (content.wEnvRefLength != 0 && content.wRefCount != 0) : (content.wEnvRefLength == 0 && content.wRefCount == 0); - if (!res) return false; - { - auto currpos = fp.position (); - try - { - auto dest = sect.pri_file.get_section_by_ref (ref_sect (content.wDecInfSectIndex)); - dest.parse (); - } - catch (const std::exception &e) - { - parseError = true; - return false; - } - fp.seek (currpos, istreamstream::seekpos::start); - } - bvecEnvRefData.resize (content.wEnvRefLength); - bvecScheRefData.resize (content.wHSRefLength); - ZeroMemory (bvecEnvRefData.data (), sizeof (BYTE) * content.wEnvRefLength); - ZeroMemory (bvecScheRefData.data (), sizeof (BYTE) * content.wHSRefLength); - fp->Read (bvecEnvRefData.data (), sizeof (BYTE) * content.wEnvRefLength, nullptr); - fp->Read (bvecScheRefData.data (), sizeof (BYTE) * content.wHSRefLength, nullptr); - if (content.wHSRefLength != 0) - { - bytesstream srdata (bvecScheRefData); - srdata.read (&hschema_ref.verHschema, sizeof (hschema_ref.verHschema)); - if (hschema_ref.verHschema.dwUnknown1 != 0) return false; - srdata.read (&hschema_ref.part2, sizeof (hschema_ref.part2)); - if (hschema_ref.part2.wUnknown1 != 0) return false; - hschema_ref.swUniqueId = ReadStringEndwithNullW (fp); - } - for (size_t i = 0; i < content.wResTypeEntCount; i ++) - { - RES_VALUE_TYPE_TABLE rvtt; - fp->Read (&rvtt, sizeof (rvtt), nullptr); - if (rvtt.dwUnknown1 != 4) return false; - vecResTypes.push_back ((RES_VALUE_TYPE)rvtt.dwResType); - } - for (size_t i = 0; i < content.wItemEntCount; i ++) - { - ITEM_ITEMINFO_GROUP_TABLE_ENTRY iigte; - fp->Read (&iigte, sizeof (iigte), nullptr); - vecItemToItemInfoGroup.push_back (iigte); - } - for (size_t i = 0; i < content.wItemGroupEntCount; i ++) - { - ITEMINFO_GROUP_TABLE_ENTRY iigte; - fp->Read (&iigte, sizeof (iigte), nullptr); - vecItemInfoGroups.push_back (iigte); - } - for (size_t i = 0; i < content.dwItemTableEntCount; i ++) - { - ITEM_ITEMINFO_TABLE_ENTRY iite; - fp->Read (&iite, sizeof (iite), nullptr); - vecItemInfo.push_back (iite); - } - std::vector largeTable (content.dwTableExtCount); - fp->Read (largeTable.data (), sizeof (BYTE) * content.dwTableExtCount, nullptr); - if (largeTable.size () != 0) - { - bytesstream bytes (largeTable); - TABLE_EXT_BLOCK teb; - bytes.read (&teb, sizeof (teb)); - for (size_t i = 0; i < teb.dwItemAdditEntCount; i ++) - { - ITEM_ITEMINFO_GROUP_TABLE_ENTRY iiigte; - bytes.read (&iiigte, sizeof (iiigte)); - vecItemToItemInfoGroup.push_back (iiigte); - } - for (size_t i = 0; i < teb.dwItemGroupAdditEntCount; i ++) - { - ITEMINFO_GROUP_TABLE_ENTRY iigte; - bytes.read (&iigte, sizeof (iigte)); - vecItemInfoGroups.push_back (iigte); - } - for (size_t i = 0; i < teb.dwItemTableAdditEntCount; i ++) - { - ITEM_ITEMINFO_TABLE_ENTRY iiite; - bytes.read (&iiite, sizeof (iiite)); - vecItemInfo.push_back (iiite); - } - if (bytes.position () > bytes.length ()) throw std::exception ("Error: invalid data in ResourceMap or ResourceMap2 Section."); - } - for (size_t i = 0; i < content.dwCandidateCount; i ++) - { - BYTE bType = -1; - fp->Read (&bType, sizeof (bType), nullptr); - switch (bType) - { - case 0x00: { - CANDIDATE_TYPE rvtype = 0; - fp->Read (&rvtype, sizeof (rvtype), nullptr); - CANDIDATE0_DATA cdata; - cdata.bResValueType = (BYTE)vecResTypes.at (rvtype); - auto &length = cdata.wEmbeddedLength; - auto &stringOffset = cdata.dwEmbeddedOffset; - fp >> length >> stringOffset; - vecCandidateInfo.emplace_back (CANDIDATE_INFO (cdata)); - } break; - case 0x01: { - CANDIDATE_TYPE rvtype = 0; - fp->Read (&rvtype, sizeof (rvtype), nullptr); - CANDIDATE1_DATA cdata; - auto &resourceValueType = cdata.bResValueType; - auto &sourceFileIndex = cdata.wSrcFile; - auto &valueLocation = cdata.wDataIndex; - auto &dataItemSection = cdata.wSectIndex; - resourceValueType = (BYTE)vecResTypes.at (rvtype); - fp >> sourceFileIndex >> valueLocation >> dataItemSection; - vecCandidateInfo.emplace_back (CANDIDATE_INFO (cdata)); - } break; - default: { - throw std::domain_error ("Error: invalid data read in ResourceMap or ResourceMap2 section."); - } break; - } - } - ulint strbegpos = 0; - fp->Seek (lint (0), STREAM_SEEK_CUR, strbegpos.ptr_union ()); - for (size_t i = 0; i < vecItemToItemInfoGroup.size (); i ++) - { - auto &itemToItemGroup = vecItemToItemInfoGroup [i]; - ITEMINFO_GROUP_TABLE_ENTRY itemInfoGroup; - if (itemToItemGroup.wItemInfoGroupIndex < vecItemInfoGroups.size ()) - itemInfoGroup = (vecItemInfoGroups [itemToItemGroup.wItemInfoGroupIndex]); - else itemInfoGroup = {1, (WORD)(itemToItemGroup.wItemInfoGroupIndex - vecItemInfoGroups.size ())}; - for (size_t j = itemInfoGroup.wFirstItemIndex; j < itemInfoGroup.wFirstItemIndex + itemInfoGroup.wItemInfoCount; j ++) - { - auto &itemInfo = vecItemInfo [j]; - auto decIndex = itemInfo.wDecisionIndex; - auto &decSect = sect.pri_file.get_section_by_ref (ref_sect (content.wDecInfSectIndex)); - decSect.parse (); - auto dec = decSect.vec_dec [decIndex]; - CANDIDATE_SET candidateSet; - std::vector &candidates = candidateSet.vecCandidates; - for (size_t k = 0; k < dec.verQualSets.size (); k ++) - { - auto can_info = vecCandidateInfo [itemInfo.wFirstCandiIndex + k]; - switch (can_info.bCandidateType) - { - case 0x01: { - REF_FILE_REF sourceFile; - if (!can_info.objCandidate._1.wSrcFile) sourceFile.setnull (); - else sourceFile.set (can_info.objCandidate._1.wSrcFile - 1); - candidates.push_back ( - CANDIDATE ( - dec.verQualSets [k].wIndex, - (RES_VALUE_TYPE)can_info.objCandidate._1.bResValueType, - sourceFile, - DATA_ITEM_REF (can_info.objCandidate._1.wDataIndex, can_info.objCandidate._1.wSectIndex - ) - ) - ); - } break; - case 0x00: { - BYTE_SPAN bspan ( - sectpos + strbegpos + ulint (can_info.objCandidate._0.dwEmbeddedOffset), - can_info.objCandidate._0.wEmbeddedLength - ); - candidates.push_back ( - CANDIDATE ( - dec.verQualSets [k].wIndex, - (RES_VALUE_TYPE)can_info.objCandidate._1.bResValueType, - bspan - ) - ); - } break; - } - } - WORD resourceMapItemIndex = itemToItemGroup.wFirstIndexProperty + (j - itemInfoGroup.wFirstItemIndex); - candidateSet.refResMapItem = RES_MAP_ITEM_REF (content.wHSSectIndex, resourceMapItemIndex); - candidateSet.wDecisionIndex = decIndex; - mapCandidateSet [resourceMapItemIndex] = candidateSet; - } - } - return valid (); -} -#ifdef UNALIGN_MEMORY -#pragma pack(pop) -#endif \ No newline at end of file diff --git a/priread/priread.cpp b/priread/priread.cpp deleted file mode 100644 index d89cbc9..0000000 --- a/priread/priread.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// priread.cpp : DLL Ӧóĵ -// - -#include "stdafx.h" -#include "priread.h" - - -// ǵһʾ -PRIREAD_API int npriread=0; - -// ǵһʾ -PRIREAD_API int fnpriread(void) -{ - return 42; -} - -// ѵĹ캯 -// йඨϢ priread.h -Cpriread::Cpriread() -{ - return; -} diff --git a/priread/priread.h b/priread/priread.h deleted file mode 100644 index dc15979..0000000 --- a/priread/priread.h +++ /dev/null @@ -1,22 +0,0 @@ -// ifdef Ǵʹ DLL 򵥵 -// ı׼ DLL еļ϶ PRIREAD_EXPORTS -// űġʹô DLL -// κĿϲӦ˷šԴļаļκĿὫ -// PRIREAD_API ΪǴ DLL ģ DLL ô˺궨 -// ΪDZġ -#ifdef PRIREAD_EXPORTS -#define PRIREAD_API __declspec(dllexport) -#else -#define PRIREAD_API __declspec(dllimport) -#endif - -// Ǵ priread.dll -class PRIREAD_API Cpriread { -public: - Cpriread(void); - // TODO: ڴķ -}; - -extern PRIREAD_API int npriread; - -PRIREAD_API int fnpriread(void); diff --git a/priread/priread.vcxproj b/priread/priread.vcxproj deleted file mode 100644 index 268ba63..0000000 --- a/priread/priread.vcxproj +++ /dev/null @@ -1,182 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {99D714D9-F40D-425B-BAFA-8B41C17971A5} - Win32Proj - priread - 8.1 - - - - DynamicLibrary - true - v140 - Unicode - - - DynamicLibrary - false - v140 - true - Unicode - - - DynamicLibrary - true - v140 - Unicode - - - DynamicLibrary - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - - - true - - - false - - - false - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;PRIREAD_EXPORTS;%(PreprocessorDefinitions) - true - - - Windows - true - - - - - Use - Level3 - Disabled - _DEBUG;_WINDOWS;_USRDLL;PRIREAD_EXPORTS;%(PreprocessorDefinitions) - true - - - Windows - true - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;PRIREAD_EXPORTS;%(PreprocessorDefinitions) - true - - - Windows - true - true - true - - - - - Level3 - Use - MaxSpeed - true - true - NDEBUG;_WINDOWS;_USRDLL;PRIREAD_EXPORTS;%(PreprocessorDefinitions) - true - - - Windows - true - true - true - - - - - - - - - - - - - - - - - false - - - false - - - false - - - false - - - - - - Create - Create - Create - Create - - - - - - \ No newline at end of file diff --git a/priread/priread.vcxproj.filters b/priread/priread.vcxproj.filters deleted file mode 100644 index 7efecd9..0000000 --- a/priread/priread.vcxproj.filters +++ /dev/null @@ -1,54 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - - - - 头文件 - - - 头文件 - - - 头文件 - - - 头文件 - - - 头文件 - - - 头文件 - - - 头文件 - - - - - 源文件 - - - 源文件 - - - 源文件 - - - \ No newline at end of file diff --git a/priread/stdafx.cpp b/priread/stdafx.cpp deleted file mode 100644 index 85e805e..0000000 --- a/priread/stdafx.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// stdafx.cpp : ֻ׼ļԴļ -// priread.pch ΪԤͷ -// stdafx.obj ԤϢ - -#include "stdafx.h" - -// TODO: STDAFX.H κĸͷļ -//ڴļ diff --git a/priread/stdafx.h b/priread/stdafx.h deleted file mode 100644 index 4f79067..0000000 --- a/priread/stdafx.h +++ /dev/null @@ -1,20 +0,0 @@ -// stdafx.h : ׼ϵͳļİļ -// Ǿʹõĵ -// ضĿİļ -// - -#pragma once - -#include "targetver.h" - -#define WIN32_LEAN_AND_MEAN // Windows ͷųʹõ -// Windows ͷļ: -#include - - -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // ijЩ CString 캯ʽ - -#include -#include - -// TODO: ڴ˴óҪͷļ diff --git a/priread/targetver.h b/priread/targetver.h deleted file mode 100644 index 416cebf..0000000 --- a/priread/targetver.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -// SDKDDKVer.h õ߰汾 Windows ƽ̨ - -// ҪΪǰ Windows ƽ̨Ӧó WinSDKVer.h -// _WIN32_WINNT ΪҪֵ֧ƽ̨Ȼٰ SDKDDKVer.h - -#include diff --git a/priread/themeinfo.h b/priread/themeinfo.h deleted file mode 100644 index 8d3c712..0000000 --- a/priread/themeinfo.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#include - -bool IsHighContrastEnabled () -{ - HIGHCONTRAST hc = {sizeof (HIGHCONTRAST)}; - if (SystemParametersInfo (SPI_GETHIGHCONTRAST, sizeof (hc), &hc, 0)) return (hc.dwFlags & HCF_HIGHCONTRASTON) != 0; - return false; -} -enum class HighContrastTheme -{ - None, - Black, - White, - Other -}; -HighContrastTheme GetHighContrastTheme () -{ - HIGHCONTRAST hc = {sizeof (HIGHCONTRAST)}; - if (!SystemParametersInfo (SPI_GETHIGHCONTRAST, sizeof (hc), &hc, 0)) return HighContrastTheme::None; - if (!(hc.dwFlags & HCF_HIGHCONTRASTON)) return HighContrastTheme::None; - COLORREF bgColor = GetSysColor (COLOR_WINDOW); - COLORREF textColor = GetSysColor (COLOR_WINDOWTEXT); - int brightnessBg = (GetRValue (bgColor) + GetGValue (bgColor) + GetBValue (bgColor)) / 3; - int brightnessText = (GetRValue (textColor) + GetGValue (textColor) + GetBValue (textColor)) / 3; - if (brightnessBg < brightnessText) return HighContrastTheme::Black; - else if (brightnessBg > brightnessText) return HighContrastTheme::White; - else return HighContrastTheme::Other; -} -int GetDPI () -{ - HDC hDC = GetDC (NULL); - int DPI_A = (int)(((double)GetDeviceCaps (hDC, 118) / (double)GetDeviceCaps (hDC, 8)) * 100); - int DPI_B = (int)(((double)GetDeviceCaps (hDC, 88) / 96) * 100); - ReleaseDC (NULL, hDC); - if (DPI_A == 100) return DPI_B; - else if (DPI_B == 100) return DPI_A; - else if (DPI_A == DPI_B) return DPI_A; - else return 0; -} diff --git a/shared/VisualElementsManifest.xml b/shared/VisualElementsManifest.xml index 61a4577..e6bf895 100644 --- a/shared/VisualElementsManifest.xml +++ b/shared/VisualElementsManifest.xml @@ -12,6 +12,18 @@ DarkModeBackgroundColor='#001629' /> + + + + + + len) { + return this.add(member); + } + this._members.splice(index, 0, member); + try { + if (_container) { + var refNode = _container.childNodes[index] || null; + _container.insertBefore(member.element, refNode); + } + } catch (e) {} + this._updateSelectionVisibility(); + return index; + }; + + // remove 接受成员对象或索引 + this.remove = function(memberOrIndex) { + var idx = -1; + if (typeof memberOrIndex === "number") { + idx = memberOrIndex; + } else { + idx = this._members.indexOf(memberOrIndex); + } + if (idx < 0 || idx >= this._members.length) return false; + var removed = this._members.splice(idx, 1)[0]; + try { + if (removed && removed.element && removed.element.parentNode) { + removed.element.parentNode.removeChild(removed.element); + } + } catch (e) {} + this._updateSelectionVisibility(); + return true; + }; + + // 替换指定索引的成员,返回 true/false + this.replaceAt = function(index, member) { + if (!member || !member.element) return false; + if (typeof index !== "number" || index < 0 || index >= this._members.length) return false; + var old = this._members[index]; + this._members[index] = member; + try { + if (_container && old && old.element) { + // 如果 old.element 在容器中,直接 replaceChild + if (old.element.parentNode === _container) { + _container.replaceChild(member.element, old.element); + } else { + // 备用:在位置 index 插入 + var ref = _container.childNodes[index] || null; + _container.insertBefore(member.element, ref); + } + } else if (_container) { + // 没有 old 元素,直接 append + _container.appendChild(member.element); + } + } catch (e) {} + this._updateSelectionVisibility(); + return true; + }; + + this.getMember = function(index) { + return this._members[index]; + }; + + this.indexOf = function(member) { + return this._members.indexOf(member); + }; + + this.clear = function() { + while (this._members.length) { + var m = this._members.shift(); + try { + if (m && m.element && m.element.parentNode) { + m.element.parentNode.removeChild(m.element); + } + } catch (e) {} + } + }; + + var timer = null; + var isupdating = false; + + function waitTimer(ms) { + clearTimeout(timer); + isupdating = true; + timer = setTimeout(function(t) { + isupdating = false; + t = null; + }, ms, timer); + } + Object.defineProperty(this, "isupdating", { + get: function() { return isupdating; } + }); + var touchHide = document.createElement("div"); + touchHide.classList.add("appbar-touchhide"); + touchHide.style.display = "none"; + Windows.UI.Event.Util.addEvent(touchHide, "click", function(event) { + touchHide.style.display = "none"; + this.hide(); + }.bind(this)); + document.body.appendChild(touchHide); + + function showTouchHide() { + if (touchHide == null || touchHide == void 0) { + touchHide = document.createElement("div"); + touchHide.classList.add("appbar-touchhide"); + } + touchHide.style.display = ""; + } + + function hideTouchHide() { + touchHide.style.display = "none"; + } + this.show = function() { + try { + if (!_enable) return; + if (!this.element.classList.contains("show")) + this.element.classList.add("show"); + waitTimer(500); + showTouchHide(); + } catch (e) {} + }; + this.hide = function() { + try { + if (this.element.classList.contains("show")) + this.element.classList.remove("show"); + waitTimer(500); + hideTouchHide(); + } catch (e) {} + }; + this.setSelectionActive = function(active) { + this._hasSelection = !!active; + this._updateSelectionVisibility(); + }; + this._updateSelectionVisibility = function() { + for (var i = 0; i < this._members.length; i++) { + var el = this._members[i].element; + if (el && el.classList && el.classList.contains("win-selection")) { + el.style.display = this._hasSelection ? "" : "none"; + } + } + }; + Object.defineProperty(this, "enabled", { + get: function() { return _enable; }, + set: function(value) { + _enable = value; + if (!value) { + this.hide(); + } + } + }); + Object.defineProperty(this, "isshowing", { + get: function() { return this.element.classList.contains("show"); }, + set: function(value) { + if (value) { + this.show(); + } else { + this.hide(); + } + } + }); + this._eventShowHandler = function(event) { + if (!this.isshowing) this.show(); + else this.hide(); + }; + this._eventHideHandler = function(event) { + this.hide(); + }; + var EventUtil = Windows.UI.Event.Util; + var self = this; + EventUtil.addEvent(document, "contextmenu", function(event) { + self._eventShowHandler(event); + event.preventDefault(); + }); + var pressTimer = null; + + EventUtil.addEvent(document, "mousedown", function(event) { + if (!self._enable) return; + pressTimer = setTimeout(function(e) { + self._eventShowHandler(e); + event.preventDefault(); + }, 600, event); + }); + + EventUtil.addEvent(document, "mouseup", function() { + clearTimeout(pressTimer); + }); + } + global.AppBar = { + AppBar: PMAppBar, + Command: PMAppBarCommand, + Separator: PMAppBarSeparator, + BaseMember: PMAppBarBaseMember + }; +})(this); \ No newline at end of file diff --git a/shared/html/js/datasrc.js b/shared/html/js/datasrc.js new file mode 100644 index 0000000..7b242a6 --- /dev/null +++ b/shared/html/js/datasrc.js @@ -0,0 +1,479 @@ +(function(global) { + "use strict"; + global.DataView = { + ChangeType: { + add: "add", + remove: "remove", + change: "change", + clear: "clear", + move: "move", + sort: "sort", + }, + }; + var childAnimeDuration = 120; + var parentAnimeDuration = 400; + + function showItemAmine(node) { + return Windows.UI.Animation.runAsync(node, [ + Windows.UI.Animation.Keyframes.Scale.up, + Windows.UI.Animation.Keyframes.Opacity.visible, + ], childAnimeDuration); + } + + function hideItemAmine(node) { + return Windows.UI.Animation.runAsync(node, [ + Windows.UI.Animation.Keyframes.Scale.down, + Windows.UI.Animation.Keyframes.Opacity.hidden, + ], childAnimeDuration); + } + + function updateItemAmine(node, updateCallback) { + return Windows.UI.Animation.runAsync(node, [ + Windows.UI.Animation.Keyframes.Opacity.hidden, + Windows.UI.Animation.Keyframes.Scale.down + ], 120).then(function() { + if (updateCallback && typeof updateCallback === 'function') { + updateCallback(node); + } + return Windows.UI.Animation.runAsync(node, [ + Windows.UI.Animation.Keyframes.Opacity.visible, + Windows.UI.Animation.Keyframes.Scale.up + ], 120); + }).then(function() { + return node; + }); + } + + function PMChangeEvent(type, datas, detailOperation) { + this.type = type; // ChangeType + this.datas = datas || []; // 受影响的数据 + this.detail = detailOperation || null; + } + + function PMDataSource() { + var _list = []; + var _listeners = []; + this.subscribe = function(fn) { + if (typeof fn === "function") { + _listeners.push(fn); + } + }; + + function emit(evt) { + for (var i = 0; i < _listeners.length; i++) { + _listeners[i](evt); + } + } + this.add = function(item) { + _list.push(item); + emit(new PMChangeEvent( + DataView.ChangeType.add, [item], { index: _list.length - 1 } + )); + }; + this.removeAt = function(index) { + if (index < 0 || index >= _list.length) return; + var item = _list.splice(index, 1)[0]; + emit(new PMChangeEvent( + DataView.ChangeType.remove, [item], { index: index } + )); + }; + this.changeAt = function(index, newItem) { + if (index < 0 || index >= _list.length) return; + _list[index] = newItem; + emit(new PMChangeEvent( + DataView.ChangeType.change, [newItem], { index: index } + )); + }; + this.clear = function() { + _list.length = 0; + emit(new PMChangeEvent( + DataView.ChangeType.clear + )); + }; + this.move = function(from, to) { + if (from === to || + from < 0 || to < 0 || + from >= _list.length || to >= _list.length) { + return; + } + var item = _list.splice(from, 1)[0]; + _list.splice(to, 0, item); + emit(new PMChangeEvent( + DataView.ChangeType.move, [item], { from: from, to: to } + )); + }; + this.sort = function(compareFn) { + _list.sort(compareFn); + emit(new PMChangeEvent( + DataView.ChangeType.sort, + _list.slice(0), { compare: compareFn } + )); + }; + this.get = function() { + return _list.slice(0); + }; + this.addList = function(list, keySelector) { + if (!list || !list.length) return; + + var added = []; + var changed = []; + + var useKey = keySelector !== void 0; + var getKey; + + if (keySelector === null) { + getKey = function(item) { + return item && item.id; + }; + } else if (typeof keySelector === "function") { + getKey = keySelector; + } + + for (var i = 0; i < list.length; i++) { + var item = list[i]; + + if (!useKey) { + _list.push(item); + added.push({ item: item, index: _list.length - 1 }); + continue; + } + + var key = getKey(item); + if (key === void 0) { + _list.push(item); + added.push({ item: item, index: _list.length - 1, key: key }); + continue; + } + + var found = -1; + for (var j = 0; j < _list.length; j++) { + if (getKey(_list[j]) === key) { + found = j; + break; + } + } + + if (found >= 0) { + _list[found] = item; + changed.push({ item: item, index: found, key: key }); + } else { + _list.push(item); + added.push({ item: item, index: _list.length - 1, key: key }); + } + } + + // 统一发出一个事件 + if (added.length > 0) { + emit(new PMChangeEvent(DataView.ChangeType.add, added)); + } + if (changed.length > 0) { + emit(new PMChangeEvent(DataView.ChangeType.change, changed)); + } + }; + this.updateList = function(list, fnGetKey) { + if (!list) list = []; + + var getKey; + + if (fnGetKey === null) { + getKey = function(item) { + return item && item.id; + }; + } else if (typeof fnGetKey === "function") { + getKey = fnGetKey; + } else { + // 不提供 key:直接整体替换 + _list = list.slice(0); + emit(new PMChangeEvent( + DataView.ChangeType.clear + )); + emit(new PMChangeEvent( + DataView.ChangeType.add, + list.map(function(item, index) { + return { item: item, index: index }; + }) + )); + return; + } + + var oldList = _list; + var newList = list; + + var oldKeyIndex = {}; + var newKeyIndex = {}; + + var i; + + // 建立旧列表 key → index + for (i = 0; i < oldList.length; i++) { + var ok = getKey(oldList[i]); + if (ok !== void 0) { + oldKeyIndex[ok] = i; + } + } + + // 建立新列表 key → index + for (i = 0; i < newList.length; i++) { + var nk = getKey(newList[i]); + if (nk !== void 0) { + newKeyIndex[nk] = i; + } + } + + var added = []; + var changed = []; + var removed = []; + + // 1️⃣ 找 remove + for (i = oldList.length - 1; i >= 0; i--) { + var oldItem = oldList[i]; + var oldKey = getKey(oldItem); + + if (oldKey === void 0 || newKeyIndex[oldKey] === void 0) { + removed.push({ + item: oldItem, + index: i, + key: oldKey + }); + } + } + + // 2️⃣ 找 add / change + for (i = 0; i < newList.length; i++) { + var newItem = newList[i]; + var newKey = getKey(newItem); + + if (newKey === void 0 || oldKeyIndex[newKey] === void 0) { + added.push({ + item: newItem, + index: i, + key: newKey + }); + } else { + var oldIndex = oldKeyIndex[newKey]; + var oldItem2 = oldList[oldIndex]; + + if (oldItem2 !== newItem) { + changed.push({ + item: newItem, + index: oldIndex, + key: newKey + }); + } + } + } + + // 3️⃣ 执行 remove(从后往前) + if (removed.length > 0) { + for (i = 0; i < removed.length; i++) { + _list.splice(removed[i].index, 1); + } + emit(new PMChangeEvent( + DataView.ChangeType.remove, + removed + )); + } + + // 4️⃣ 执行 add / change(重建顺序) + _list = newList.slice(0); + + if (added.length > 0) { + emit(new PMChangeEvent( + DataView.ChangeType.add, + added + )); + } + + if (changed.length > 0) { + emit(new PMChangeEvent( + DataView.ChangeType.change, + changed + )); + } + }; + + } + + function PMDataListView(container, templateFn) { + this.container = container; + this.templateFn = templateFn; + this.listViewControl = this; + } + PMDataListView.prototype.bind = function(ds) { + var self = this; + var items = ds.get(); + self.container.innerHTML = ""; + + // 动画队列,保证异步操作不会乱序 + var queue = Promise.resolve(); + + function renderItem(data, index) { + var el = self.templateFn(data, index); + + el.addEventListener("click", function() { + self._toggleSelect(el); + }); + + return el; + } + + // 初始化渲染 + for (var i = 0; i < items.length; i++) { + self.container.appendChild(renderItem(items[i], i)); + } + + ds.subscribe(function(evt) { + + // 把每次事件放进队列,保证顺序执行 + queue = queue.then(function() { + switch (evt.type) { + + case DataView.ChangeType.add: + { + // evt.datas = [{item, index}, ...] + var datas = evt.datas; + + // 先批量 append 到 DOM(顺序必须保持) + var nodes = []; + for (var i = 0; i < datas.length; i++) { + var n = renderItem(datas[i].item, datas[i].index); + nodes.push(n); + self.container.appendChild(n); + } + + // 如果数量>=20,动画并行,否则串行 + if (datas.length >= 20) { + var promises = []; + for (var j = 0; j < nodes.length; j++) { + promises.push(showItemAmine(nodes[j])); + } + return Promise.all(promises); + } else { + // 串行 + var p = Promise.resolve(); + for (var k = 0; k < nodes.length; k++) { + (function(node) { + p = p.then(function() { + return showItemAmine(node); + }); + })(nodes[k]); + } + return p; + } + } + + case DataView.ChangeType.remove: + { + var node = self.container.children[evt.detail.index]; + if (!node) return; + + // 隐藏动画完成后再移除 + return hideItemAmine(node).then(function() { + self.container.removeChild(node); + }); + } + + case DataView.ChangeType.change: + { + var oldNode = self.container.children[evt.detail.index]; + if (!oldNode) return; + + // 先淡出旧节点 + return hideItemAmine(oldNode).then(function() { + // 替换节点 + var newNode = renderItem(evt.datas[0], evt.detail.index); + self.container.replaceChild(newNode, oldNode); + + // 再淡入新节点 + return showItemAmine(newNode); + }); + } + + case DataView.ChangeType.clear: + self.container.innerHTML = ""; + return Promise.resolve(); + + case DataView.ChangeType.move: + { + var node = self.container.children[evt.detail.from]; + var ref = self.container.children[evt.detail.to] || null; + if (node) self.container.insertBefore(node, ref); + return Promise.resolve(); + } + + case DataView.ChangeType.sort: + { + self.container.innerHTML = ""; + for (var i = 0; i < evt.datas.length; i++) { + self.container.appendChild(renderItem(evt.datas[i], i)); + } + return Promise.resolve(); + } + } + }); + }); + }; + + PMDataListView.prototype._toggleSelect = function(ele) { + // 如果选择模式为 none,则不处理 + if (this.selectionMode === "none") return; + + var isSelected = ele.classList.contains("selected"); + + if (this.selectionMode === "single") { + // 单选:先取消所有选中 + this._clearSelected(); + if (!isSelected) { + ele.classList.add("selected"); + } + } else if (this.selectionMode === "multiple") { + // 多选:点一次切换状态 + if (isSelected) { + ele.classList.remove("selected"); + } else { + ele.classList.add("selected"); + } + } + }; + PMDataListView.prototype._clearSelected = function() { + var selected = this.container.querySelectorAll(".selected"); + for (var i = 0; i < selected.length; i++) { + selected[i].classList.remove("selected"); + } + }; + Object.defineProperty(PMDataListView.prototype, "selectionMode", { + get: function() { + return this._selectionMode || "none"; + }, + set: function(value) { + var mode = String(value).toLowerCase(); + if (mode !== "none" && mode !== "single" && mode !== "multiple") { + mode = "none"; + } + this._selectionMode = mode; + + // 切换模式时,清空选中状态(可选) + if (mode === "none") { + this._clearSelected(); + } + if (mode === "single") { + // 单选模式:如果多选了多个,保留第一个 + var selected = this.container.querySelectorAll(".selected"); + if (selected.length > 1) { + for (var i = 1; i < selected.length; i++) { + selected[i].classList.remove("selected"); + } + } + } + } + }); + Object.defineProperty(PMDataListView.prototype, "selectedItems", { + get: function() { + return Array.prototype.slice.call(this.container.querySelectorAll(".selected")); + } + }); + + global.DataView.ChangeEvent = PMChangeEvent; + global.DataView.DataSource = PMDataSource; + global.DataView.ListView = PMDataListView; +})(this); \ No newline at end of file diff --git a/shared/html/js/manager/pages.js b/shared/html/js/manager/pages.js new file mode 100644 index 0000000..6c52587 --- /dev/null +++ b/shared/html/js/manager/pages.js @@ -0,0 +1,50 @@ +(function(global) { + "use strict"; + var pkg_ns = external.Package; + + function archsToStr(archs) { + var arr = []; + for (var i = 0; i < archs.length; i++) { + switch (archs[i]) { + case 0: + arr.push("x86"); + break; + case 5: + arr.push("ARM"); + break; + case 9: + arr.push("x64"); + break; + case 11: + arr.push("Neutral"); + break; + case 12: + arr.push("ARM64"); + break; + case 65535: + arr.push("Unknown"); + break; + } + } + return arr.join(", "); + } + + function setAppInfoPageContent(info) { + var page = document.getElementById("page-appinfo"); + page.querySelector(".display-name").textContent = info.Properties.DisplayName; + page.querySelector(".publisher-display-name").textContent = info.Properties.Publisher; + page.querySelector(".version").textContent = info.Identity.Version.Expression; + page.querySelector(".description").textContent = info.Properties.Description; + page.querySelector(".identity .name").textContent = info.Identity.Name; + page.querySelector(".identity .publisher").textContent = info.Identity.Publisher; + page.querySelector(".identity .publisher-id").textContent = info.Identity.PublisherId; + page.querySelector(".identity .family-name").textContent = info.Identity.FamilyName; + page.querySelector(".identity .full-name").textContent = info.Identity.FullName; + page.querySelector(".identity .architecture").textContent = archsToStr(info.Identity.ProcessArchitecture); + var il = info.InstallLocation; + var pkg = pkg_ns.fromInstallLocation(il); + var json = pkg.jsonText; + console.log(JSON.parse(json)); + } + global.setAppInfoPageContent = setAppInfoPageContent; +})(this); \ No newline at end of file diff --git a/shared/html/js/mgrinit.js b/shared/html/js/mgrinit.js new file mode 100644 index 0000000..adb0ab4 --- /dev/null +++ b/shared/html/js/mgrinit.js @@ -0,0 +1,524 @@ +(function(global) { + function _createImage(src, onload, onerror) { + var img = new Image(); + + img.onload = function() { + onload(img); + }; + + img.onerror = function() { + onerror && onerror(); + }; + + img.src = src; + } + + function getSolidOpaqueBackgroundColor(source, callback) { + + function processImage(img) { + if (!img || !img.complete) { + callback(null); + return; + } + + var canvas = document.createElement("canvas"); + var ctx = canvas.getContext("2d"); + + canvas.width = img.naturalWidth || img.width; + canvas.height = img.naturalHeight || img.height; + + ctx.drawImage(img, 0, 0); + + try { + var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); + } catch (e) { + // 跨域导致的安全异常 + callback(null); + return; + } + + var data = imageData.data; + var w = canvas.width; + var h = canvas.height; + + var colors = {}; + var total = 0; + + function pushColor(r, g, b, a) { + if (a !== 255) return; + var key = r + "," + g + "," + b; + colors[key] = (colors[key] || 0) + 1; + total++; + } + + // top + bottom + for (var x = 0; x < w; x++) { + var topIndex = (0 * w + x) * 4; + var botIndex = ((h - 1) * w + x) * 4; + pushColor(data[topIndex], data[topIndex + 1], data[topIndex + 2], data[topIndex + 3]); + pushColor(data[botIndex], data[botIndex + 1], data[botIndex + 2], data[botIndex + 3]); + } + + // left + right + for (var y = 1; y < h - 1; y++) { + var leftIndex = (y * w + 0) * 4; + var rightIndex = (y * w + (w - 1)) * 4; + pushColor(data[leftIndex], data[leftIndex + 1], data[leftIndex + 2], data[leftIndex + 3]); + pushColor(data[rightIndex], data[rightIndex + 1], data[rightIndex + 2], data[rightIndex + 3]); + } + + if (total === 0) { + callback(null); + return; + } + + var bestKey = null; + var bestCount = 0; + + for (var key in colors) { + if (colors.hasOwnProperty(key)) { + if (colors[key] > bestCount) { + bestCount = colors[key]; + bestKey = key; + } + } + } + + // 95% 纯色阈值 + if (bestCount / total < 0.95) { + callback(null); + return; + } + + callback(bestKey); + } + + // 如果传入的是 img 元素 + if (source && source.tagName && source.tagName.toLowerCase() === "img") { + processImage(source); + return; + } + + // 如果传入的是 data url 或普通 url + if (typeof source === "string") { + _createImage(source, processImage, function() { + callback(null); + }); + return; + } + + callback(null); + } + + function getHamonyColor(source, callback) { + + function _createImage(src, onload, onerror) { + var img = new Image(); + img.onload = function() { onload(img); }; + img.onerror = function() { onerror && onerror(); }; + img.src = src; + } + + function _toKey(r, g, b) { + return r + "," + g + "," + b; + } + + function _rgbToHsl(r, g, b) { + r /= 255; + g /= 255; + b /= 255; + var max = Math.max(r, g, b); + var min = Math.min(r, g, b); + var h, s, l = (max + min) / 2; + + if (max === min) { + h = s = 0; + } else { + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch (max) { + case r: + h = (g - b) / d + (g < b ? 6 : 0); + break; + case g: + h = (b - r) / d + 2; + break; + case b: + h = (r - g) / d + 4; + break; + } + h /= 6; + } + return { h: h, s: s, l: l }; + } + + function _hslToRgb(h, s, l) { + var r, g, b; + + function hue2rgb(p, q, t) { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; + return p; + } + + if (s === 0) { + r = g = b = l; + } else { + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hue2rgb(p, q, h + 1 / 3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1 / 3); + } + + return { + r: Math.round(r * 255), + g: Math.round(g * 255), + b: Math.round(b * 255) + }; + } + + function _lum(r, g, b) { + function f(x) { + x = x / 255; + return x <= 0.03928 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4); + } + return 0.2126 * f(r) + 0.7152 * f(g) + 0.0722 * f(b); + } + + function _contrast(a, b) { + var L1 = _lum(a.r, a.g, a.b); + var L2 = _lum(b.r, b.g, b.b); + var lighter = Math.max(L1, L2); + var darker = Math.min(L1, L2); + return (lighter + 0.05) / (darker + 0.05); + } + + function _tryPureBackground(data, w, h) { + var edgeColors = {}; + var edgeTotal = 0; + + function push(r, g, b, a) { + if (a !== 255) return; + var k = _toKey(r, g, b); + edgeColors[k] = (edgeColors[k] || 0) + 1; + edgeTotal++; + } + + for (var x = 0; x < w; x++) { + var top = (0 * w + x) * 4; + var bot = ((h - 1) * w + x) * 4; + push(data[top], data[top + 1], data[top + 2], data[top + 3]); + push(data[bot], data[bot + 1], data[bot + 2], data[bot + 3]); + } + for (var y = 1; y < h - 1; y++) { + var left = (y * w + 0) * 4; + var right = (y * w + (w - 1)) * 4; + push(data[left], data[left + 1], data[left + 2], data[left + 3]); + push(data[right], data[right + 1], data[right + 2], data[right + 3]); + } + + if (edgeTotal === 0) return null; + + var best = null, + bestCount = 0; + for (var k in edgeColors) { + if (edgeColors.hasOwnProperty(k) && edgeColors[k] > bestCount) { + bestCount = edgeColors[k]; + best = k; + } + } + if (best && bestCount / edgeTotal >= 0.95) return best; + return null; + } + + function _process(img) { + if (!img || !img.complete) { callback(null); return; } + + var canvas = document.createElement("canvas"); + var ctx = canvas.getContext("2d"); + canvas.width = img.naturalWidth || img.width; + canvas.height = img.naturalHeight || img.height; + ctx.drawImage(img, 0, 0); + + var imageData; + try { + imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); + } catch (e) { + callback(null); + return; + } + + var data = imageData.data; + var w = canvas.width, + h = canvas.height; + + // 1) 尝试纯色背景 + var pure = _tryPureBackground(data, w, h); + if (pure) { callback(pure); return; } + + // 2) 统计不透明像素(抽样) + var sumR = 0, + sumG = 0, + sumB = 0, + count = 0; + var samples = 0; + var step = 4; // 4x抽样,减少性能消耗 + for (var y = 0; y < h; y += step) { + for (var x = 0; x < w; x += step) { + var i = (y * w + x) * 4; + var a = data[i + 3]; + if (a === 255) { + sumR += data[i]; + sumG += data[i + 1]; + sumB += data[i + 2]; + count++; + } + samples++; + } + } + if (count === 0) { callback(null); return; } + + var avgR = sumR / count, + avgG = sumG / count, + avgB = sumB / count; + + // 3) 生成候选色(借鉴流行配色) + var base = _rgbToHsl(avgR, avgG, avgB); + + function clamp(v, min, max) { return Math.max(min, Math.min(max, v)); } + + var candidates = []; + + // 中性色(低饱和) + candidates.push(_hslToRgb(base.h, 0.05, 0.5)); + candidates.push(_hslToRgb(base.h, 0.1, 0.6)); + candidates.push(_hslToRgb(base.h, 0.1, 0.4)); + + // 平均色去饱和 + candidates.push(_hslToRgb(base.h, clamp(base.s * 0.4, 0.05, 0.2), clamp(base.l, 0.2, 0.8))); + + // 互补色(活泼) + candidates.push(_hslToRgb((base.h + 0.5) % 1, clamp(base.s * 0.6, 0.1, 0.8), clamp(base.l, 0.35, 0.7))); + + // 类似色 + candidates.push(_hslToRgb((base.h + 0.083) % 1, clamp(base.s * 0.5, 0.1, 0.8), clamp(base.l, 0.35, 0.7))); + candidates.push(_hslToRgb((base.h - 0.083 + 1) % 1, clamp(base.s * 0.5, 0.1, 0.8), clamp(base.l, 0.35, 0.7))); + + // 三分色 + candidates.push(_hslToRgb((base.h + 0.333) % 1, clamp(base.s * 0.6, 0.1, 0.8), clamp(base.l, 0.35, 0.7))); + candidates.push(_hslToRgb((base.h - 0.333 + 1) % 1, clamp(base.s * 0.6, 0.1, 0.8), clamp(base.l, 0.35, 0.7))); + + // 4) 计算最小对比度(与所有不透明像素) + function minContrastWithImage(bg) { + var bgObj = { r: bg.r, g: bg.g, b: bg.b }; + var minC = Infinity; + + for (var y = 0; y < h; y += step) { + for (var x = 0; x < w; x += step) { + var i = (y * w + x) * 4; + if (data[i + 3] !== 255) continue; + var px = { r: data[i], g: data[i + 1], b: data[i + 2] }; + var c = _contrast(bgObj, px); + if (c < minC) minC = c; + } + } + return minC; + } + + var best = null; + for (var i = 0; i < candidates.length; i++) { + var c = candidates[i]; + var minC = minContrastWithImage(c); + if (minC >= 4.5) { + best = c; + break; + } + } + + if (best) { + callback(_toKey(best.r, best.g, best.b)); + } else { + callback(null); + } + } + + if (source && source.tagName && source.tagName.toLowerCase() === "img") { + _process(source); + } else if (typeof source === "string") { + _createImage(source, _process, function() { callback(null); }); + } else { + callback(null); + } + } + + function getSuitableBackgroundColor(source, callback) { + getSolidOpaqueBackgroundColor(source, function(color) { + if (color) { + callback(color); + } else { + getHamonyColor(source, callback); + } + }); + } + + function createLocalizedCompare(locale) { + return function(a, b) { + a = a || ""; + b = b || ""; + + return a.localeCompare(b, locale, { + numeric: true, // 2 < 10 + sensitivity: "base" // 不区分大小写 / 重音 + }); + }; + } + var pagemgr = new PageManager(); + OnLoad.add(function() { + var listContainer = document.getElementById("applist"); + var appItemTemplate = document.getElementById("appitem-template"); + var mgr = Package.manager; + var nstr = Bridge.NString; + var datasrc = new DataView.DataSource(); + var themeColor = Bridge.UI.themeColor; + var loadingDisplay = document.getElementById("applist-loading"); + var loadingStatus = loadingDisplay.querySelector(".title"); + var listView = new DataView.ListView(listContainer, function(item) { + var appItem = appItemTemplate.cloneNode(true); + appItem.id = ""; + appItem.style.display = ""; + var logoimg = appItem.querySelector("img"); + logoimg.src = item.Properties.LogoBase64 || logoimg.src; + logoimg.parentElement.style.backgroundColor = themeColor; + var appName = appItem.querySelector(".displayName"); + appName.textContent = item.Properties.DisplayName || item.Identity.Name; + var appPub = appItem.querySelector(".publisher"); + appPub.textContent = item.Properties.Publisher; + appItem.data = item; + appItem.setAttribute("data-install-location", item.InstallLocation); + appItem.setAttribute("data-development-mode", item.DevelopmentMode); + appItem.setAttribute("data-is-bundle", item.IsBundle); + appItem.setAttribute("data-is-framework", item.Properties.Framework); + appItem.setAttribute("data-family-name", item.Identity.FamilyName); + appItem.setAttribute("data-full-name", item.Identity.FullName); + appItem.setAttribute("data-version", item.Identity.Version.Expression); + appItem.setAttribute("data-users", item.Users); + appItem.setAttribute("data-publisher-id", item.Identity.PublisherId); + setTimeout(function(a, b) { + getSolidOpaqueBackgroundColor(a, function(color) { + try { + var pipes = color.split(","); + var colorobj = new Color(parseInt(pipes[0]), parseInt(pipes[1]), parseInt(pipes[2])); + if (colorobj.hex == "#ffffff" || colorobj.hex == "#000000") throw "too white or black"; + var rgbstr = colorobj.RGB.toString(); + b.style.backgroundColor = rgbstr; + } catch (e) {} + }); + }, 0, item.Properties.LogoBase64, logoimg.parentElement); + Windows.UI.Event.Util.addEvent(appItem.querySelector("div[role=advance] a"), "click", function(e) { + e.stopPropagation(); + try { + pagemgr.go("appinfo", this.parentNode.parentNode.parentNode.data); + } catch (ex) {} + }); + return appItem; + }); + listView.selectionMode = "single"; + listView.bind(datasrc); + var timer = null; + + function refreshAppList() { + function update(datas) { + var newDatas = []; + for (var i = 0; i < datas.length; i++) { + var data = datas[i]; + if (data.Properties.Framework) continue; // 过滤依赖项 + var isfind = false; // 过滤系统应用 + for (var j = 0; data && data.Users && j < data.Users.length; j++) { + if (Bridge.NString.equals(data.Users[j], "NT AUTHORITY\\SYSTEM")) { + isfind = true; + break; + } + } + if (isfind) continue; + newDatas.push(data); + } + datasrc.updateList(newDatas, function(item) { + return item.Identity.FullName || ""; + }); + var compare = function(a, b) { return a - b; }; + try { + compare = createLocalizedCompare(external.System.Locale.currentLocale); + } catch (e) { + try { + compare = createLocalizedCompare(navigator.language); + } catch (e) { + compare = function(a, b) { + if (a < b) return -1; + if (a > b) return 1; + return 0; + }; + } + } + datasrc.sort(function(a, b) { + return compare(a.Properties.DisplayName, b.Properties.DisplayName); + }); + } + if (timer) clearTimeout(timer); + timer = null; + loadingDisplay.style.display = ""; + loadingDisplay.classList.remove("noloading"); + + function waitAndHide() { + if (timer) clearTimeout(timer); + timer = null; + timer = setTimeout(function() { + loadingDisplay.style.display = "none"; + }, 10000); + } + loadingStatus.textContent = "正在加载数据..."; + return mgr.get().then(function(result) { + loadingDisplay.classList.add("noloading"); + loadingStatus.textContent = "已经加载了所有数据"; + update(result.list); + waitAndHide(); + }, function(error) { + loadingDisplay.classList.add("noloading"); + loadingStatus.textContent = "更新时出错: " + (error.result ? (error.result.message || error.result.ErrorCode || "获取失败") : (error.message || error.error || error)); + try { update(error.list); } catch (e) {} + waitAndHide(); + }) + } + var appbar = document.getElementById("appBar"); + var appbarControl = new AppBar.AppBar(appbar); + var refreshButton = new AppBar.Command(); + refreshButton.icon = ""; + refreshButton.label = "刷新"; + global.refreshAppList2 = function refreshAppList2() { + appbarControl.hide(); + refreshButton.disabled = true; + refreshAppList().done(function() { + refreshButton.disabled = false; + }, function(error) { + refreshButton.disabled = false; + }); + } + refreshButton.addEventListener("click", refreshAppList2); + appbarControl.add(refreshButton); + refreshAppList2(); + pagemgr.register("manager", document.getElementById("tag-manager"), document.getElementById("page-manager")); + pagemgr.register("appinfo", document.getElementById("tag-appinfo"), document.getElementById("page-appinfo"), setAppInfoPageContent); + var appinfoBackPage = document.getElementById("page-appinfo").querySelector(".win-backbutton"); + Windows.UI.Event.Util.addEvent(appinfoBackPage, "click", function(e) { + pagemgr.back(); + }); + pagemgr.addEventListener("load", function(e) { + appbarControl.enabled = e == "manager"; + refreshButton.style.display = e == "manager" ? "" : "none"; + }); + pagemgr.go("manager"); + }); +})(this); \ No newline at end of file diff --git a/shared/html/js/pagemgr.js b/shared/html/js/pagemgr.js new file mode 100644 index 0000000..770e6d6 --- /dev/null +++ b/shared/html/js/pagemgr.js @@ -0,0 +1,359 @@ +(function(global) { + "use strict"; + var eu = Windows.UI.Event.Util; + var anime = Windows.UI.Animation; + + function PagePair(guideNode, pageNode, respHandler) { + var _guide = guideNode; + var _page = pageNode; + var _handler = respHandler || null; + Object.defineProperty(this, "guide", { + get: function() { return _guide; }, + set: function(value) { _guide = value; } + }); + Object.defineProperty(this, "page", { + get: function() { return _page; }, + set: function(value) { _page = value; } + }); + Object.defineProperty(this, "handler", { + get: function() { return _handler; }, + set: function(value) { _handler = value; } + }); + } + + function PageManager() { + var dict = {}; + var stack = []; + var current = -1; + var record = {}; // 记录哪些界面已经第一次加载过 + var paramStack = []; + // scrollStack 与 stack 对齐:scrollStack[i] 对应 stack[i] + var scrollStack = []; + var nowScroll = 0; + var events = { + firstload: [], + beforeload: [], + load: [], + afterload: [], + willunload: [], + unload: [] + }; + + function addHandler(type, fn) { + if (typeof fn !== "function") return; + events[type].push(fn); + } + + function removeHandler(type, fn) { + var list = events[type]; + for (var i = list.length - 1; i >= 0; i--) { + if (list[i] === fn) { + list.splice(i, 1); + } + } + } + + function emit(type, arg) { + var list = events[type]; + for (var i = 0; i < list.length; i++) { + try { + list[i](arg); + } catch (e) {} + } + } + + function emitCancelable(type, arg) { + var list = events[type]; + for (var i = 0; i < list.length; i++) { + try { + var r = list[i](arg); + if (r === false) return false; + } catch (e) {} + } + return true; + } + /** + * 添加载入事件 + * @param {string} type 支持:"firstload" + "beforeload" + "load" + "afterload" + "willunload" + "unload" + + * @param {function} fn + */ + this.addEventListener = function(type, fn) { + addHandler(type, fn); + }; + /** + * 移除载入事件 + * @param {string} type 支持:"firstload" + "beforeload" + "load" + "afterload" + "willunload" + "unload" + + * @param {function} fn + */ + this.removeEventListener = function(type, fn) { + removeHandler(type, fn); + }; + + + function guideClickHandler(e) { + var tag = this.__pageTag; + if (!tag) return; + if (this.classList.contains("selected")) return; + self.go(tag); + return; + var keys = Object.keys(dict); + var promises = []; + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + var pair = dict[key]; + if (pair.guide.classList.contains("selected")) { + promises.push(anime.runAsync( + pair.page, [ + anime.Keyframes.Opacity.hidden, + anime.Keyframes.Scale.down + ] + ).then(function(el) { + el.style.display = "none"; + })); + } + } + this.classList.add("selected"); + var after = Promise.join(promises); + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + var pair = dict[key]; + if (pair.guide.classList.contains("selected")) { + pair.page.style.display = ""; + after.then(function() { + anime.runAsync( + pair.page, [ + anime.Keyframes.Opacity.visible, + anime.Keyframes.Flyout.toLeft + ] + ); + }); + } + } + } + var self = this; + + function _activate(tag, args, fromHistory) { + var pair = dict[tag]; + if (!pair) throw "Page not found: " + tag; + if (!emitCancelable("beforeload", tag)) { + return; + } + var keys = Object.keys(dict); + var promises = []; + var oldTags = []; + for (var i = 0; i < keys.length; i++) { + var k = keys[i]; + var p = dict[k]; + if (p.guide.classList.contains("selected") && k !== tag) { + if (!emitCancelable("willunload", k)) { + return; + } + oldTags.push(k); + promises.push( + anime.runAsync(p.page, [ + anime.Keyframes.Opacity.hidden + ]).then((function(page, key) { + return function() { + page.style.display = "none"; + page.style.opacity = 0; + emit("unload", key); + }; + })(p.page, k)) + ); + p.guide.classList.remove("selected"); + } + } + pair.guide.classList.add("selected"); + pair.page.style.display = ""; + emit("load", tag); + var after = Promise.join(promises); + after.then(function() { + if (!record[tag]) { + record[tag] = true; + emit("firstload", tag); + } + pair.page.style.opacity = 1; + if (pair.handler) { + // fix: use pair.handler + pair.handler(args); + } + try { + setTimeout(function(tnode) { + try { + tnode.scrollTop = nowScroll || 0; + } catch (ex) {} + }, 10, pair.page.parentNode); + } catch (ex) {} + return anime.runAsync(pair.page, [ + anime.Keyframes.Opacity.visible, + anime.Keyframes.Flyout.toLeft + ]).then(function() { + + }); + }).then(function() { + emit("afterload", tag); + }); + } + this.register = function(tag, guideNode, pageNode, respHandler) { + dict[tag] = new PagePair(guideNode, pageNode, respHandler); + guideNode.__pageTag = tag; + try { + eu.removeEvent(guideNode, "click", guideClickHandler); + eu.addEvent(guideNode, "click", guideClickHandler); + } catch (e) {} + }; + this.edit = function(tag, pagePair) { + try { + if (dict[tag] && dict[tag].guide) { + dict[tag].guide.__pageTag = null; + } + } catch (e) {} + dict[tag] = pagePair; + try { + pagePair.guide.__pageTag = tag; + eu.removeEvent(pagePair.guide, "click", guideClickHandler); + eu.addEvent(pagePair.guide, "click", guideClickHandler); + } catch (e) {} + }; + this.get = function(tag) { + return dict[tag]; + }; + this.getGuide = function(tag) { + return dict[tag].guide; + }; + this.getPage = function(tag) { + return dict[tag].page; + }; + this.getHandler = function(tag) { + return dict[tag].handler; + }; + this.setGuide = function(tag, guideNode) { + try { + if (dict[tag] && dict[tag].guide) { + eu.removeEvent(dict[tag].guide, "click", guideClickHandler); + dict[tag].guide.__pageTag = null; + } + } catch (e) {} + dict[tag].guide = guideNode; + try { + guideNode.__pageTag = tag; + eu.removeEvent(guideNode, "click", guideClickHandler); + eu.addEvent(guideNode, "click", guideClickHandler); + } catch (e) {} + }; + this.setPage = function(tag, pageNode) { + dict[tag].page = pageNode; + }; + this.setHandler = function(tag, handler) { + dict[tag].handler = handler; + }; + this.remove = function(tag) { + try { + try { + if (dict[tag] && dict[tag].guide) { + eu.removeEvent(dict[tag].guide, "click", guideClickHandler); + } + } catch (e) {} + delete dict[tag]; + } catch (e) {} + }; + this.clear = function() { + try { + var keys = Object.keys(dict); + for (var i = 0; i < keys.length; i++) { + this.remove(keys[i]); + } + } catch (e) {} + }; + this.jump = function(tag, args) { + _activate(tag, args, true); + }; + this.go = function(tag, params) { + // limit history + if (stack.length > 300) { + stack.length = 0; + paramStack.length = 0; + scrollStack.length = 0; + current = -1; + } + // if we are in the middle, truncate forward history + if (current < stack.length - 1) { + stack.splice(current + 1); + paramStack.splice(current + 1); + scrollStack.splice(current + 1); + } + // save current page scrollTop + try { + if (current >= 0 && stack[current] && dict[stack[current]] && dict[stack[current]].page && dict[stack[current]].page.parentNode) { + scrollStack[current] = dict[stack[current]].page.parentNode.scrollTop; + } + } catch (e) {} + // push new entry + stack.push(tag); + paramStack.push(params); + // initialize scroll value for the new page (will be used if user goes back to it later) + scrollStack.push(0); + current++; + _activate(tag, params, false); + }; + this.back = function() { + if (current <= 0) return false; + // save scroll of current page + try { + if (stack[current] && dict[stack[current]] && dict[stack[current]].page && dict[stack[current]].page.parentNode) { + scrollStack[current] = dict[stack[current]].page.parentNode.scrollTop; + } + } catch (e) {} + // move back + current--; + // restore scroll for new current + nowScroll = scrollStack[current] || 0; + _activate(stack[current], paramStack[current], true); + return true; + }; + this.next = function() { + if (current >= stack.length - 1) return false; + // save scroll of current page + try { + if (stack[current] && dict[stack[current]] && dict[stack[current]].page && dict[stack[current]].page.parentNode) { + scrollStack[current] = dict[stack[current]].page.parentNode.scrollTop; + } + } catch (e) {} + // move forward + current++; + // restore scroll for new current + nowScroll = scrollStack[current] || 0; + _activate(stack[current], paramStack[current], true); + return true; + }; + Object.defineProperty(this, "current", { + get: function() { return stack[current]; }, + set: function(value) { + if (value < 0 || value >= stack.length) return; + current = value; + // restore scroll for assigned current + nowScroll = scrollStack[current] || 0; + _activate(stack[current], paramStack[current], true); + } + }); + Object.defineProperty(this, "canback", { + get: function() { return current > 0; } + }); + Object.defineProperty(this, "cannext", { + get: function() { return current < stack.length - 1; } + }); + } + global.PageManager = PageManager; +})(this); \ No newline at end of file diff --git a/shared/html/js/pkginfo.js b/shared/html/js/pkginfo.js new file mode 100644 index 0000000..d3c4e45 --- /dev/null +++ b/shared/html/js/pkginfo.js @@ -0,0 +1,128 @@ +(function(global) { + "use strict"; + var mgr = external.Package.manager; + + function parseJsonCallback(swJson, callback) { + var ret = swJson; + try { + if (swJson) ret = JSON.parse(swJson); + } catch (e) {} + if (callback) callback(ret); + } + global.Package = { + reader: function(pkgPath) { external.Package.reader(pkgPath); }, + manager: { + add: function(swPkgPath, uOptions) { + return new Promise(function(resolve, reject, progress) { + mgr.addPackage(swPkgPath, uOptions, function(result) { + parseJsonCallback(result, resolve); + }, function(result) { + parseJsonCallback(result, reject); + }, progress); + }) + }, + get: function() { + return new Promise(function(resolve, reject) { + mgr.getPackages(function(result) { + parseJsonCallback(result, resolve); + }, function(result) { + parseJsonCallback(result, reject); + }); + }); + }, + remove: function(swPkgFullName) { + return new Promise(function(resolve, reject, progress) { + mgr.removePackage(swPkgFullName, function(result) { + parseJsonCallback(result, resolve); + }, function(result) { + parseJsonCallback(result, reject); + }, progress); + }); + }, + clearup: function(swPkgName, swUserSID) { + return new Promise(function(resolve, reject, progress) { + mgr.clearupPackage(swPkgName, swUserSID, function(result) { + parseJsonCallback(result, resolve); + }, function(result) { + parseJsonCallback(result, reject); + }, progress); + }); + }, + register: function(swPkgPath, uOptions) { + return new Promise(function(resolve, reject, progress) { + mgr.registerPackage(swPkgPath, uOptions, function(result) { + parseJsonCallback(result, resolve); + }, function(result) { + parseJsonCallback(result, reject); + }, progress); + }); + }, + registerByFullName: function(swPkgFullName, uOptions) { + return new Promise(function(resolve, reject, progress) { + mgr.registerPackageByFullName(swPkgFullName, uOptions, function(result) { + parseJsonCallback(result, resolve); + }, function(result) { + parseJsonCallback(result, reject); + }, progress); + }); + }, + setStatus: function(swPkgFullName, uStatus) { + mgr.setPackageStatus(swPkgFullName, uStatus); + }, + stage: function(swPkgPath, uOptions) { + return new Promise(function(resolve, reject, progress) { + mgr.stagePackage(swPkgPath, uOptions, function(result) { + parseJsonCallback(result, resolve); + }, function(result) { + parseJsonCallback(result, reject); + }, progress); + }); + }, + stageUserData: function(swPkgFullName) { + return new Promise(function(resolve, reject, progress) { + mgr.stagePackageUserData(swPkgFullName, function(result) { + parseJsonCallback(result, resolve); + }, function(result) { + parseJsonCallback(result, reject); + }, progress); + }); + }, + update: function(swPkgPath, uOptions) { + return new Promise(function(resolve, reject, progress) { + mgr.updatePackage(swPkgPath, uOptions, function(result) { + parseJsonCallback(result, resolve); + }, function(result) { + parseJsonCallback(result, reject); + }, progress); + }); + }, + findByIdentity: function(swIdName, swIdPublisher) { + return new Promise(function(resolve, reject) { + mgr.findPackageByIdentity(swIdName, swIdPublisher, function(result) { + parseJsonCallback(result, resolve); + }, function(result) { + parseJsonCallback(result, reject); + }); + }); + }, + findByFamilyName: function(swFamilyName) { + return new Promise(function(resolve, reject) { + mgr.findPackageByFamilyName(swFamilyName, function(result) { + parseJsonCallback(result, resolve); + }, function(result) { + parseJsonCallback(result, reject); + }); + }); + }, + findByFullName: function(swPkgFullName) { + return new Promise(function(resolve, reject) { + mgr.findPackageByFullName(swPkgFullName, function(result) { + parseJsonCallback(result, resolve); + }, function(result) { + parseJsonCallback(result, reject); + }); + }); + }, + }, + }; +})(this); \ No newline at end of file diff --git a/shared/html/libs/msgbox/msgbox.js b/shared/html/libs/msgbox/msgbox.js index af0cd45..d85781c 100644 --- a/shared/html/libs/msgbox/msgbox.js +++ b/shared/html/libs/msgbox/msgbox.js @@ -380,4 +380,153 @@ function messageBoxAsync(swText, swTitle, uType, swColor, pfCallback) { 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/manager.html b/shared/html/manager.html index c3a81f2..657f656 100644 --- a/shared/html/manager.html +++ b/shared/html/manager.html @@ -8,6 +8,7 @@ + @@ -21,38 +22,77 @@ + + + + + + + -
+
-
+
+ \ No newline at end of file diff --git a/shared/html/manager/appbar.css b/shared/html/manager/appbar.css new file mode 100644 index 0000000..32f6e79 --- /dev/null +++ b/shared/html/manager/appbar.css @@ -0,0 +1,49 @@ +.win-bottom { + position: absolute; + bottom: 0; + top: auto; + left: 0; + right: 0; +} + +.appbar { + -ms-transform: translateY(100%); + transform: translateY(100%); + transition: all 0.5s cubic-bezier(0.1, 0.9, 0.2, 1); +} + +.appbar.show { + -ms-transform: translateY(0); + transform: translateY(0); +} + +.appbar.win-ui-dark .win-label { + color: white; +} + +.appbar-touchhide { + background-color: transparent; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 88px; +} + +.appbar button.win-command, +.win-appbar .win-commandlayout button.win-command { + box-sizing: border-box; + /* 含 padding/border 计算宽度 */ + min-width: 100px; + /* 强制最小宽度 100px */ +} + + +/* 同时覆盖在窄屏 media query 中的行为(确保在 @media (max-width:1023px) 之后或在文件末尾定义) */ + +@media (max-width: 1023px) { + .appbar button.win-command, + .win-appbar .win-commandlayout button.win-command { + min-width: 100px; + } +} \ No newline at end of file diff --git a/shared/html/manager/appitem.css b/shared/html/manager/appitem.css index 229eff4..23ff28d 100644 --- a/shared/html/manager/appitem.css +++ b/shared/html/manager/appitem.css @@ -2,7 +2,7 @@ padding: 10px; box-sizing: border-box; height: 60px; - width: 450px; + width: 460px; max-width: 100%; display: -ms-flexbox; /* IE10 */ @@ -53,6 +53,14 @@ -ms-flex-line-pack: center; /* IE10 -> align-content */ align-content: center; + overflow-x: hidden; + overflow-y: hidden; + transition: all 0.3s cubic-bezier(0.1, 0.9, 0.2, 1); +} + +.appitem div[role=img] img { + width: 30px; + height: 30px; } .appitem div[role=divide] { @@ -65,6 +73,23 @@ font-weight: normal; flex: 1; -ms-flex: 1; + width: 100%; + overflow-x: hidden; + overflow-y: hidden; + text-overflow: ellipsis; +} + +.appitem div[role=excepticon] div[role=advance] { + display: none; + opacity: 0; + height: 0; + transition: all 0.3s cubic-bezier(0.1, 0.9, 0.2, 1); +} + +.appitem.selected div[role=excepticon] div[role=advance] { + display: block; + opacity: 1; + height: auto; } .appitem div[role=excepticon] { @@ -85,12 +110,12 @@ -ms-flex-pack: start; /* IE10 -> justify-content */ justify-content: flex-start; + width: calc(100% - 40px - 10px); } .appitem div[role=excepticon] div[role=control] { display: none; /* IE10 */ - display: flex; -ms-flex-direction: row-reverse; /* IE10 */ flex-direction: row-reverse; @@ -106,13 +131,95 @@ -ms-flex-align: center; /* IE10 -> align-items */ align-items: center; + transition: all 0.3s cubic-bezier(0.1, 0.9, 0.2, 1); + opacity: 0; + height: 0; } .appitem.selected { height: 119px; + background-color: rgba(232, 232, 232, 1); } .appitem.selected div[role=excepticon] div[role=control] { display: flex; display: -ms-flexbox; + opacity: 1; + height: auto; +} + +ul.appitem-list, +ul.appitem-list li { + margin: 0; + padding: 0; + list-style: none; +} + +.appitem .displayName, +.appitem .publisher { + text-overflow: ellipsis; + overflow-x: hidden; + overflow-y: hidden; + white-space: nowrap; + max-width: 100%; +} + +.appitem .publisher { + color: rgb(102, 102, 102); +} + +.app-loading { + display: flex; + flex-direction: row; + flex-wrap: wrap; + align-content: center; + justify-content: flex-start; + align-items: center; + width: 100%; + height: auto; +} + +.app-loading.noloading progress { + display: none; +} + +.app-loading .title { + margin-left: 10px; +} + +.app-loading.noloading .title { + margin-left: 0; +} + +.app-detailpage header { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + align-content: flex-start; + justify-content: flex-start; + overflow-x: hidden; + overflow-y: hidden; + text-overflow: ellipsis; + width: 100%; + height: 67px; + box-sizing: border-box; + max-width: 100%; +} + +.app-detailpage header .win-backbutton { + width: 35px; + height: 35px; + font-size: 11.9pt; + line-height: 32px; + min-width: 35px; + min-height: 35px; +} + +.app-detailpage header .display-name { + padding-left: 10px; + box-sizing: border-box; + width: calc(100% - 35px - 10px); + overflow-y: hidden; + overflow-x: hidden; + text-overflow: ellipsis; } \ No newline at end of file diff --git a/shared/html/manager/page.css b/shared/html/manager/page.css index adf4c16..48d6268 100644 --- a/shared/html/manager/page.css +++ b/shared/html/manager/page.css @@ -168,6 +168,7 @@ aside>nav ul li { .page.fold>aside>nav ul li { padding: 0; + cursor: pointer; } aside>nav ul li div[role=img] { @@ -189,6 +190,33 @@ aside>nav ul li div[role=img] { text-align: center; } +.page>aside>nav ul li.selected { + background-color: #159d9d; +} + +.page>aside>nav ul li.selected:hover { + background-color: rgb(23, 187, 187); +} + +.page>aside>nav ul li.selected:active { + background-color: rgb(29, 224, 224); +} + +.page>aside>nav ul li.subitem { + opacity: 0; + height: 0; + min-height: 0; +} + +.page>aside>nav ul li.subitem.selected { + opacity: 1; + height: 50px; +} + +.page.fold>aside>nav ul li * { + pointer-events: none; +} + .page.fold>aside>nav ul li div[role=img] { min-width: 90px; width: 90px; @@ -213,7 +241,8 @@ aside>nav ul li div[role=img] { .page>aside>nav ul li div[role=img] { font-size: 15pt; - margin-right: 5px; + margin-right: 10px; + width: 1em; } .page>aside>nav ul li.title div[role=img] { @@ -256,7 +285,7 @@ aside>nav ul li div[role=img] { .page.fold>aside>nav ul li:hover div[role=img] { min-width: 0; - width: auto; + width: 1em; } .page.fold>aside>nav ul li:hover span { @@ -292,6 +321,10 @@ aside>nav ul li div[role=img] { overflow-y: visible; } +.main { + transition: all 0.3s cubic-bezier(0.1, 0.9, 0.2, 1); +} + .main.padding { padding: 44px 60px; } @@ -307,12 +340,18 @@ aside>nav ul li div[role=img] { top: 0px; left: 0px; background-color: white; + transition: all 0.3s cubic-bezier(0.1, 0.9, 0.2, 1); } .section.padding { padding: 44px 60px; } -.section.padding .bottom-compensate { +.bottom-compensate { padding-bottom: 44px; +} + +.ispage { + opacity: 1; + transition: all 0.4s cubic-bezier(0.1, 0.9, 0.2, 1); } \ No newline at end of file