using System.ComponentModel; using System.ComponentModel.Design.Serialization; using System.Globalization; using static Vanara.PInvoke.Kernel32; using static Vanara.PInvoke.User32; namespace Vanara.Windows.Shell; /// Wraps the icon location string used by some Shell classes. [TypeConverter(typeof(IconLocationTypeConverter))] public class IconLocation : IndirectResource { /// Initializes a new instance of the class. public IconLocation() { } /// 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 icon in the module file. public IconLocation(string module, int resourceIdOrIndex) : base(module, resourceIdOrIndex) { } /// Gets the icon referred to by this instance. /// The icon. [Browsable(false)] public SafeHICON? Icon { get { if (!IsValid) return null; using var lib = LoadLibraryEx(ModuleFileName!, LoadLibraryExFlags.LOAD_LIBRARY_AS_IMAGE_RESOURCE); return new SafeHICON(LoadImage(lib, ResourceId, LoadImageType.IMAGE_ICON, 0, 0, 0)); //var hIconEx = new[] { IntPtr.Zero }; //if (large) // ExtractIconEx(loc.ModuleFileName, loc.ResourceId, hIconEx, null, 1); //else // ExtractIconEx(loc.ModuleFileName, loc.ResourceId, null, hIconEx, 1); } } /// 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 IconLocation loc) { var parts = value?.Split(','); if (parts != null && parts.Length == 2 && int.TryParse(parts[1], out var i)) { loc = new IconLocation(parts[0], i); return true; } loc = new IconLocation(); return false; } /// Returns a that represents this instance. /// A that represents this instance. public override string ToString() => IsValid ? $"{ModuleFileName},{ResourceId}" : string.Empty; } internal class IconLocationTypeConverter : ExpandableObjectConverter { public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) => sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destType) => destType == typeof(InstanceDescriptor) || destType == typeof(string) || base.CanConvertTo(context, destType); public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) => value is string s ? IconLocation.TryParse(s, out var loc) ? loc : null : base.ConvertFrom(context, culture, value); public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? info, object? value, Type destType) { if (destType == typeof(InstanceDescriptor)) return new InstanceDescriptor(typeof(IconLocation).GetConstructor([]), null, false); if (destType == typeof(string) && value is IconLocation s) return s.ToString(); return base.ConvertTo(context, info, value, destType); } }