using System; using System.ComponentModel; using System.Linq; namespace Vanara.Windows.Shell { /// Wraps a resource reference used by some Shell classes. public abstract class IndirectResource { /// Initializes a new instance of the class. /// The value of the string. public IndirectResource(string value = null) => RawValue = value; /// Initializes a new instance of the class. /// The module file name. /// /// If this number is positive, this is the index of the resource in the module file. If negative, the absolute value of the number /// is the resource ID of the resource in the module file. /// /// The version modifier. This value can be, and usually is, . public IndirectResource(string module, int resourceIdOrIndex, string versionModifier = null) { if (module is null) throw new ArgumentNullException(nameof(module)); RawValue = $"@{module},{resourceIdOrIndex}" + (versionModifier is null ? "" : ';' + versionModifier); } /// Initializes a new instance of the class. /// The package name or package resource index file name. /// The package locator. /// packageNameOrPriFile or packageLocator /// Package locator must start with 'ms-resource://' - packageLocator public IndirectResource(string packageNameOrPriFile, string packageLocator) { if (packageNameOrPriFile is null) throw new ArgumentNullException(nameof(packageNameOrPriFile)); if (packageLocator is null) throw new ArgumentNullException(nameof(packageLocator)); if (!packageLocator.StartsWith("ms-resource://")) throw new ArgumentException("Package locator must start with 'ms-resource://'", nameof(packageLocator)); RawValue = $"@{{{packageNameOrPriFile}? {packageLocator}}}"; } /// Returns true if this location is valid. /// true if this location is valid; otherwise, false. [Browsable(false)] public virtual bool IsValid => (ModuleFileName != null && ResourceId != 0) || ((PackageName != null || PackageResourceIndexFile != null) && PackageLocator != null); /// Gets the module file name. /// The module file name. [Browsable(false)] public string ModuleFileName { get { if (string.IsNullOrEmpty(RawValue) || RawValue[0] != '@' || (RawValue.Length > 1 && RawValue[1] == '{')) return null; return RawValue.TrimStart('@').Split(',')[0]; } } /// Gets the resource name used to lookup the resource within a package. /// The resource lookup name. public string PackageLocator { get { #pragma warning disable IDE0056 // Use index operator if (string.IsNullOrEmpty(RawValue) || RawValue[0] != '@' || (RawValue.Length > 1 && !(RawValue[1] == '{' && RawValue[RawValue.Length - 1] == '}'))) return null; #pragma warning restore IDE0056 // Use index operator var parts = RawValue.Substring(2).TrimEnd('}').Split('?'); return parts.Length > 1 && parts[1].Trim().StartsWith("ms-resource://") ? parts[1].Trim() : null; } } /// /// Gets the name of the package. The string is extracted from the Resources.pri file stored in the app's root directory of the /// package identified by PackageFullName, using the resource as a locator. The retrieved string is copied to the output buffer and /// the function returns S_OK. The string is extracted based on the app's environment or ResourceContext. Note: This string must /// refer to a package installed for the current user.If it does not, the call will fail. /// /// The name of the package. Something like "Microsoft.Camera_6.2.8376.0_x64__8wekyb3d8bbwe". [Browsable(false)] public string PackageName { get { #pragma warning disable IDE0056 // Use index operator if (string.IsNullOrEmpty(RawValue) || RawValue[0] != '@' || (RawValue.Length > 1 && !(RawValue[1] == '{' && RawValue[RawValue.Length - 1] == '}'))) return null; #pragma warning restore IDE0056 // Use index operator var parts = RawValue.Substring(2).TrimEnd('}').Split('?'); return parts[0].Contains('\\') ? null : parts[0]; } } /// /// Gets the package resource index file name. The Package Resource Index (PRI) is a binary format introduced in Windows 8 that /// contains indexed resources or references to resources. The .pri file is bundled as part of an app's package. For more /// information on .pri files, see Creating and retrieving resources in Windows Store apps. The string is extracted from the.pri /// file named, using the resource as a locator.The retrieved string is copied to the output buffer and the function returns S_OK. /// The string is extracted based on the current Shell environment or ResourceContext. /// /// The package resource index file name. Something like "C:\Program Files\WindowsApps\Microsoft.Camera_6.2.8376.0_x64__8wekyb3d8bbwe\resources.pri". [Browsable(false)] public string PackageResourceIndexFile { get { #pragma warning disable IDE0056 // Use index operator if (string.IsNullOrEmpty(RawValue) || RawValue[0] != '@' || (RawValue.Length > 1 && !(RawValue[1] == '{' && RawValue[RawValue.Length - 1] == '}'))) return null; #pragma warning restore IDE0056 // Use index operator var parts = RawValue.Substring(2).TrimEnd('}').Split('?'); return parts[0].Contains('\\') && System.IO.Path.GetExtension(parts[0]) != null && System.IO.Path.GetExtension(RawValue).Equals(".pri", StringComparison.InvariantCultureIgnoreCase) ? parts[0] : null; } } /// Gets the raw value of the string. /// Returns a value. public string RawValue { get; private set; } /// Gets or sets the resource index or resource ID. /// /// If this number is positive, this is the index of the resource in the module file. If negative, the absolute value of the number /// is the resource ID of the icon in the module file. /// [Browsable(false)] public int ResourceId { get { if (string.IsNullOrEmpty(RawValue) || RawValue[0] != '@' || (RawValue.Length > 1 && RawValue[1] == '{')) return 0; var parts = RawValue.Split(',', ';'); return parts.Length > 1 && int.TryParse(parts[1], out var i) ? i : 0; } } /// Gets the version modifier. This value is rarely used. /// The version modifier (e.g. "v2"). [Browsable(false)] public string VersionModifier { get { if (string.IsNullOrEmpty(RawValue) || RawValue[0] != '@' || (RawValue.Length > 1 && RawValue[1] == '{')) return null; var parts = RawValue.Split(',', ';'); return parts.Length > 2 ? parts[2] : null; } } /// Returns a that represents this instance. /// A that represents this instance. public override string ToString() => RawValue; } }