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 the icon handle.
/// The icon handle.
public HICON IconHandle => 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;
}
}
}
}