From 44f0afe7325c09f6f55805b02a8dcbe3ebe6b428 Mon Sep 17 00:00:00 2001 From: dahall Date: Wed, 28 Oct 2020 22:41:35 -0600 Subject: [PATCH] Added Vanara.Windows.Shell.StockIcon class --- Windows.Shell/StockIcon.cs | 122 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 Windows.Shell/StockIcon.cs diff --git a/Windows.Shell/StockIcon.cs b/Windows.Shell/StockIcon.cs new file mode 100644 index 00000000..ad350ff3 --- /dev/null +++ b/Windows.Shell/StockIcon.cs @@ -0,0 +1,122 @@ +using System; +using System.Drawing; +using Vanara.PInvoke; +using static Vanara.PInvoke.Shell32; +using static Vanara.PInvoke.User32; + +namespace Vanara.Windows.Shell +{ + /// Represents a standard system icon. + public class StockIcon : IDisposable + { + private SHGSI curFlags; + private SHSTOCKICONID curId; + private HICON hIcon; + private IconLocation location; + private int systemImageIndex; + + static StockIcon() => FileIconInit(false); + + /// Creates a new StockIcon instance with the specified identifer and options. + /// A value that identifies the icon represented by this instance. + /// A value that indicates the size of the stock icon. + /// A bool value that indicates whether the icon has a link overlay. + /// A bool value that indicates whether the icon is in a selected state. + public StockIcon(SHSTOCKICONID id, ShellIconType size = ShellIconType.Large, bool isLinkOverlay = false, bool isSelected = false) + { + Identifier = id; + LinkOverlay = isLinkOverlay; + Selected = isSelected; + Size = size; + } + + /// Finalizes an instance of the class. + ~StockIcon() + { + Dispose(false); + } + + /// Gets the icon image in format. + public Bitmap Bitmap { get { Refresh(); return hIcon.IsNull ? null : Bitmap.FromHicon((IntPtr)hIcon); } } + + /// Gets the icon image in format. + public Icon Icon { get { Refresh(); return hIcon.IsNull ? null : Icon.FromHandle((IntPtr)hIcon); } } + + /// Gets or sets the Stock Icon identifier associated with this icon. + public SHSTOCKICONID Identifier { get; set; } + + /// Gets or sets a value that cotrols whether to put a link overlay on the icon. + /// A value. + public bool LinkOverlay { get; set; } + + /// Gets the icon location, composed of a resource path and the icon's index. + /// The icon location. + public IconLocation Location { get { Refresh(); return location; } } + + /// Gets or sets a value indicating whether the icon appears selected. + /// A value. + public bool Selected { get; set; } + + /// Gets or sets a value that controls the size of the Stock Icon. + /// A value. + public ShellIconType Size { get; set; } + + /// Gets the index of the image in the system icon cache. + /// The index of the system image. + public int SystemImageIndex { get { Refresh(); return systemImageIndex; } } + + /// Release the native objects + public void Dispose() + { + Dispose(true); + System.GC.SuppressFinalize(this); + } + + /// Release the native and managed objects + /// Indicates that this is being called from Dispose(), rather than the finalizer. + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + // dispose managed resources here + } + + // Unmanaged resources + if (hIcon != IntPtr.Zero) + DestroyIcon(hIcon); + } + + private SHGSI GetFlags() => SHGSI.SHGSI_ICON | SHGSI.SHGSI_ICONLOCATION | SHGSI.SHGSI_SYSICONINDEX | (SHGSI)Size | (Selected ? SHGSI.SHGSI_SELECTED : 0) | (LinkOverlay ? SHGSI.SHGSI_LINKOVERLAY : 0); + + private void Refresh() + { + var flags = GetFlags(); + if (curFlags == flags && curId == Identifier) + return; + + if (hIcon != IntPtr.Zero) + { + DestroyIcon(hIcon); + hIcon = default; + } + + var info = SHSTOCKICONINFO.Default; + var hr = SHGetStockIconInfo(curId = Identifier, curFlags = flags, ref info); + + // If we get an error, return null as the icon requested might not be supported on the current system + if (hr == HRESULT.E_INVALIDARG) + throw new InvalidOperationException("Invalid identifier."); + else if (hr.Succeeded) + { + hIcon = info.hIcon; + location = new IconLocation(info.szPath, info.iIcon); + systemImageIndex = info.iSysImageIndex; + } + else + { + location = null; + systemImageIndex = 0; + } + } + } +} \ No newline at end of file