using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.IO; using System.Runtime.InteropServices; using Vanara.PInvoke; using static Vanara.PInvoke.Gdi32; using static Vanara.PInvoke.Kernel32; using static Vanara.PInvoke.Shell32; using static Vanara.PInvoke.User32; namespace Vanara.Resources { /// Represents a file that contains resources. /// public class ResourceFile : IDisposable { private SafeHINSTANCE hLib; /// Initializes a new instance of the class. /// The filename. /// filename public ResourceFile(string filename) : this() { if (filename == null) throw new ArgumentNullException(nameof(filename)); using (var hm = LoadLibraryEx(filename)) FileName = GetModuleFileName(hm); hLib = LoadLibraryEx(filename, IntPtr.Zero, LoadLibraryExFlags.LOAD_LIBRARY_AS_DATAFILE | LoadLibraryExFlags.LOAD_LIBRARY_AS_IMAGE_RESOURCE); } private ResourceFile() { Bitmaps = new ImageResIndexer(GetBitmap); GroupIcons = new GroupIconResIndexer(GetGroupIcon); Icons = new ImageResIndexer(GetIcon); Strings = new StringResIndexer(GetString); } /// Gets the bitmaps. /// The bitmaps. public ImageResIndexer Bitmaps { get; } /// Gets the name of the file. /// The name of the file. public string FileName { get; } /// Gets the group icons. /// The group icons. public GroupIconResIndexer GroupIcons { get; } /// Gets the icons. /// The icons. public ImageResIndexer Icons { get; } /// Gets the strings. /// The strings. public StringResIndexer Strings { get; } /// Gets the resource grouo icon. /// The resource reference. /// public static Icon GetResourceGrouoIcon(string resourceReference) { var parts = GetResourceRefParts(resourceReference); using (var nr = new ResourceFile(parts.Item1)) return nr.GetGroupIcon(parts.Item2); } /// Gets the resource icon. /// The resource reference. /// public static Icon GetResourceIcon(string resourceReference) { var parts = GetResourceRefParts(resourceReference); SHDefExtractIcon(parts.Item1, parts.Item2, 0, out var hIcon, out var _, 0).ThrowIfFailed(); return hIcon.ToIcon(); } /// Gets the resource string. /// The resource reference. /// public static string GetResourceString(string resourceReference) { var parts = GetResourceRefParts(resourceReference); using (var nr = new ResourceFile(parts.Item1)) return nr.GetString(parts.Item2); } /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. public void Dispose() { hLib = null; } /// Get binary image of the specified resource. /// The resource name. /// Type of the resource. /// Binary image of the resource. public byte[] GetResourceData(SafeResourceId name, ResourceType resourceType) { // Get binary image of the specified resource. var hResInfo = FindResource(hLib, name, resourceType); if (hResInfo.IsNull) throw new Win32Exception(); var hResData = LoadResource(hLib, hResInfo); if (hResData.IsNull) throw new Win32Exception(); var hGlobal = LockResource(hResData); if (hGlobal == IntPtr.Zero) throw new Win32Exception(); var resSize = SizeofResource(hLib, hResInfo); if (resSize == 0) throw new Win32Exception(); var buf = new byte[resSize]; Marshal.Copy(hGlobal, buf, 0, buf.Length); return buf; } /// Gets the resource names. /// The type. /// public IList GetResourceNames(SafeResourceId type) => EnumResourceNamesEx(hLib, type); /// Gets the bitmap. /// The name. /// The size. /// /// protected virtual Bitmap GetBitmap(SafeResourceId name, Size size) { var hBmp = new SafeHBITMAP(LoadImage(hLib, name, LoadImageType.IMAGE_BITMAP, size.Width, size.Height, LoadImageOptions.LR_DEFAULTCOLOR)); return !hBmp.IsNull ? hBmp.ToBitmap() : throw new Win32Exception(); } /// Gets the group icon. /// The name. /// protected virtual Icon GetGroupIcon(SafeResourceId name) { const int szGrpIconDirEntry = 14; // sizeof(GRPICONDIRENTRY) const int sIconDir = 6; // sizeof(ICONDIR) const int sIconDirEntry = 16; // sizeof(ICONDIRENTRY) var srcBuf = GetResourceData(name, ResourceType.RT_GROUP_ICON); // Convert the resource into an .ico file image. using (var destStream = new MemoryStream()) using (var writer = new BinaryWriter(destStream)) { int count = BitConverter.ToUInt16(srcBuf, 4); // ICONDIR.idCount var imgOffset = sIconDir + sIconDirEntry * count; // Copy ICONDIR. writer.Write(srcBuf, 0, sIconDir); for (var i = 0; i < count; i++) { // Copy GRPICONDIRENTRY converting into ICONDIRENTRY. writer.BaseStream.Seek(sIconDir + sIconDirEntry * i, SeekOrigin.Begin); writer.Write(srcBuf, sIconDir + szGrpIconDirEntry * i, sIconDirEntry - 4); // Common fields of structures writer.Write(imgOffset); // ICONDIRENTRY.dwImageOffset // Get picture and mask data, then copy them. var nId = BitConverter.ToUInt16(srcBuf, sIconDir + szGrpIconDirEntry * i + 12); // GRPICONDIRENTRY.nID var imgBuf = GetResourceData(nId, ResourceType.RT_ICON); writer.BaseStream.Seek(imgOffset, SeekOrigin.Begin); writer.Write(imgBuf, 0, imgBuf.Length); imgOffset += imgBuf.Length; } destStream.Seek(0, SeekOrigin.Begin); return new Icon(destStream); } } /// Gets the icon. /// The name. /// The size. /// /// protected virtual Icon GetIcon(SafeResourceId name, Size size) { var hIcon = new SafeHICON(LoadImage(hLib, name, LoadImageType.IMAGE_ICON, size.Width, size.Height, LoadImageOptions.LR_LOADTRANSPARENT)); return !hIcon.IsNull ? hIcon.ToIcon() : throw new Win32Exception(); } /// Gets the string. /// The identifier. /// protected virtual string GetString(int id) { var sb = new System.Text.StringBuilder(260); var len = LoadString(hLib, id, sb, 260); return len == 0 ? null : sb.ToString(); } private static Tuple GetResourceRefParts(string resourceReference) { var parts = resourceReference.Split(','); if (parts.Length != 2) throw new ArgumentException(@"Invalid string format.", nameof(resourceReference)); int id; if (!int.TryParse(parts[1], out id)) throw new ArgumentException(@"Invalid resource identifier.", nameof(resourceReference)); var fn = parts[0]; try { fn = Environment.ExpandEnvironmentVariables(fn); } catch (Exception ex) { throw new ArgumentException(@"Invalid file name part.", nameof(resourceReference), ex); } return new Tuple(fn, id); } /// An indexer for group icons. public class GroupIconResIndexer { private readonly IndexerGetter getter; internal GroupIconResIndexer(IndexerGetter getFn) { getter = getFn; } internal delegate Icon IndexerGetter(SafeResourceId name); /// Gets the at the specified index. /// The . /// The index. /// public Icon this[int index] => getter(index); /// Gets the at the specified index. /// The . /// The index. /// public Icon this[string index] => getter(index); } /// An indexer for images. /// public class ImageResIndexer { private readonly IndexerGetter getter; internal ImageResIndexer(IndexerGetter getFn) { getter = getFn; } internal delegate T IndexerGetter(SafeResourceId name, Size size); /// Gets the at the specified index. /// The . /// The index. /// public T this[int index] => getter(index, default); /// Gets the at the specified index. /// The . /// The index. /// The size. /// public T this[int index, Size size] => getter(index, size); /// Gets the at the specified index. /// The . /// The index. /// public T this[string index] => getter(index, default); /// Gets the at the specified index. /// The . /// The index. /// The size. /// public T this[string index, Size size] => getter(index, size); } /// An indexer for strings. public class StringResIndexer { private readonly IndexerGetter getter; internal StringResIndexer(IndexerGetter getFn) { getter = getFn; } internal delegate string IndexerGetter(int name); /// Gets the at the specified index. /// The . /// The index. /// public string this[int index] => getter(index); } } }