#nullable enable using System; using System.ComponentModel; 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 (RawValue is null || RawValue.Length == 0 || 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 { if (RawValue is null || RawValue.Length == 0 || RawValue[0] != '@' || RawValue.Length > 1 && !(RawValue[1] == '{' && RawValue[RawValue.Length - 1] == '}')) return null; 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 { if (RawValue is null || RawValue.Length == 0 || RawValue[0] != '@' || RawValue.Length > 1 && !(RawValue[1] == '{' && RawValue[RawValue.Length - 1] == '}')) return null; var parts = RawValue.Substring(2).TrimEnd('}').Split('?'); return parts[0].IndexOf('\\') >= 0 ? 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 { if (RawValue is null || RawValue.Length == 0 || RawValue[0] != '@' || RawValue.Length > 1 && !(RawValue[1] == '{' && RawValue[RawValue.Length - 1] == '}')) return null; var parts = RawValue.Substring(2).TrimEnd('}').Split('?'); return parts[0].IndexOf('\\') >= 0 && 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 (RawValue is null || RawValue.Length == 0 || 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 (RawValue is null || RawValue.Length == 0 || 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 ?? ""; } }