using System; using System.ComponentModel; using System.ComponentModel.Design.Serialization; using System.Globalization; using Vanara.PInvoke; using static Vanara.PInvoke.Kernel32; using static Vanara.PInvoke.User32_Gdi; namespace Vanara.Windows.Shell { /// Wraps a string resource reference used by some Shell classes. [TypeConverter(typeof(IndirectStringTypeConverter))] public class IndirectString : IndirectResource { /// Initializes a new instance of the class. public IndirectString() { } /// Initializes a new instance of the class. public IndirectString(string value) : base(value, 0) { } /// 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 string in the module file. /// public IndirectString(string module, int resourceIdOrIndex) : base(module, resourceIdOrIndex) { } /// Gets the raw value of the string. /// Returns a value. [Browsable(false)] public string RawValue => IsValid ? $"@{ModuleFileName},{ResourceId}" : ModuleFileName; /// Gets the localized string referred to by this instance. /// The referenced localized string. [Browsable(false)] public string Value { get { if (ResourceId == 0) return ModuleFileName; using (var lib = LoadLibraryEx(ModuleFileName, Kernel32.LoadLibraryExFlags.LOAD_LIBRARY_AS_IMAGE_RESOURCE)) { if (ResourceId >= 0) throw new NotSupportedException(); const int sz = 2048; var sb = new System.Text.StringBuilder(sz, sz); LoadString(lib, -ResourceId, sb, sz); return sb.ToString(); } } } /// Performs an implicit conversion from to . /// The ind. /// The result of the conversion. public static implicit operator string(IndirectString ind) => ind.RawValue; /// Performs an implicit conversion from to . /// The s. /// The result of the conversion. public static implicit operator IndirectString(string s) => TryParse(s, out var loc) ? loc : null; /// Tries to parse the specified string to create a instance. /// The string representation in the format of either "ModuleFileName,ResourceIndex" or "ModuleFileName,-ResourceID". /// The resulting instance on success. /// true if successfully parsed. public static bool TryParse(string value, out IndirectString loc) { var parts = value?.Split(','); if (parts != null && parts.Length == 2 && int.TryParse(parts[1], out var i) && parts[0].StartsWith("@")) { loc = new IndirectString(parts[0].TrimStart('@'), i); return true; } loc = new IndirectString(value); return !string.IsNullOrEmpty(value); } /// Returns a that represents this instance. /// A that represents this instance. public override string ToString() => RawValue ?? ""; } internal class IndirectStringTypeConverter : ExpandableObjectConverter { public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { if (sourceType == typeof(string)) return true; return base.CanConvertFrom(context, sourceType); } public override bool CanConvertTo(ITypeDescriptorContext context, Type destType) { if (destType == typeof(InstanceDescriptor) || destType == typeof(string)) return true; return base.CanConvertTo(context, destType); } public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { if (value is string s) return IndirectString.TryParse(s, out var loc) ? loc : null; return base.ConvertFrom(context, culture, value); } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo info, object value, Type destType) { if (destType == typeof(string) && value is IndirectString s) return s.RawValue; if (destType == typeof(InstanceDescriptor)) return new InstanceDescriptor(typeof(IndirectString).GetConstructor(new Type[0]), null, false); return base.ConvertTo(context, info, value, destType); } } }