<PackageReference Include="System.Drawing.Common" Version="10.0.0-preview.6.25358.103" />

Icon

Represents a Windows icon, which is a small bitmap image that is used to represent an object. Icons can be thought of as transparent bitmaps, although their size is determined by the system.
using System.Buffers; using System.ComponentModel; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using Windows.Win32; using Windows.Win32.Foundation; using Windows.Win32.Graphics.Gdi; using Windows.Win32.System.Com; using Windows.Win32.System.Ole; using Windows.Win32.UI.WindowsAndMessaging; namespace System.Drawing { [Serializable] [NullableContext(1)] [Nullable(0)] [Editor("System.Drawing.Design.IconEditor, System.Drawing.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Drawing.Design.UITypeEditor, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")] [TypeConverter(typeof(IconConverter))] [TypeForwardedFrom("System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")] public sealed class Icon : MarshalByRefObject, ICloneable, IDisposable, ISerializable, IIcon, IHandle<HICON> { private static int s_bitDepth; private const int PNGSignature1 = 1196314761; private const int PNGSignature2 = 169478669; [Nullable(2)] private readonly byte[] _iconData; private uint _bestImageOffset; private uint _bestBitDepth; private uint _bestBytesInRes; private bool? _isBestImagePng; private Size _iconSize = Size.Empty; [NonSerialized] private HICON _handle; private readonly bool _ownHandle = true; [Browsable(false)] public IntPtr Handle { get { if (!_handle.IsNull) return _handle; throw new ObjectDisposedException(GetType().Name); } } HICON IHandle<HICON>.Handle { get { return (HICON)Handle; } } [Browsable(false)] public int Height { get { return Size.Height; } } public unsafe Size Size { get { if (!_iconSize.IsEmpty) return _iconSize; ICONINFO iconInfo = PInvokeCore.GetIconInfo(this); BITMAP bITMAP = default(BITMAP); if (!iconInfo.hbmColor.IsNull) { PInvokeCore.GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bITMAP); PInvokeCore.DeleteObject(iconInfo.hbmColor); _iconSize = new Size(bITMAP.bmWidth, bITMAP.bmHeight); } else if (!iconInfo.hbmMask.IsNull) { PInvokeCore.GetObject(iconInfo.hbmMask, sizeof(BITMAP), &bITMAP); _iconSize = new Size(bITMAP.bmWidth, bITMAP.bmHeight / 2); } if (!iconInfo.hbmMask.IsNull) PInvokeCore.DeleteObject(iconInfo.hbmMask); return _iconSize; } } [Browsable(false)] public int Width { get { return Size.Width; } } private Icon() { } internal Icon(HICON handle) : this(handle, false) { } internal Icon(HICON handle, bool takeOwnership) { if (handle.IsNull) throw new ArgumentException(System.SR.Format(System.SR.InvalidGDIHandle, "Icon")); _handle = handle; _ownHandle = takeOwnership; } public Icon(string fileName) : this(fileName, 0, 0) { } public Icon(string fileName, Size size) : this(fileName, size.Width, size.Height) { } public Icon(string fileName, int width, int height) : this() { using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { _iconData = new byte[(int)fileStream.Length]; fileStream.ReadExactly(_iconData); } Initialize(width, height); } public Icon(Icon original, Size size) : this(original, size.Width, size.Height) { } public Icon(Icon original, int width, int height) : this() { ArgumentNullException.ThrowIfNull(original, "original"); _iconData = original._iconData; if (_iconData == null) { _iconSize = original.Size; _handle = PInvokeCore.CopyIcon(original, _iconSize.Width, _iconSize.Height, IMAGE_FLAGS.LR_DEFAULTCOLOR); } else Initialize(width, height); } public Icon(Type type, string resource) : this() { ArgumentNullException.ThrowIfNull(resource, "resource"); Stream manifestResourceStream = type.Module.Assembly.GetManifestResourceStream(type, resource); if (manifestResourceStream == null) throw new ArgumentException(System.SR.Format(System.SR.ResourceNotFound, type, resource)); Stream stream = manifestResourceStream; _iconData = new byte[(int)stream.Length]; stream.ReadExactly(_iconData); Initialize(0, 0); } public Icon(Stream stream) : this(stream, 0, 0) { } public Icon(Stream stream, Size size) : this(stream, size.Width, size.Height) { } public Icon(Stream stream, int width, int height) : this() { ArgumentNullException.ThrowIfNull(stream, "stream"); _iconData = new byte[(int)stream.Length]; stream.ReadExactly(_iconData); Initialize(width, height); } private Icon(SerializationInfo info, StreamingContext context) { _iconData = (byte[])info.GetValue("IconData", typeof(byte[])); _iconSize = (Size)info.GetValue("IconSize", typeof(Size)); Initialize(_iconSize.Width, _iconSize.Height); } void ISerializable.GetObjectData(SerializationInfo si, StreamingContext context) { if (_iconData != null) si.AddValue("IconData", _iconData, typeof(byte[])); else { MemoryStream memoryStream = new MemoryStream(); Save(memoryStream); si.AddValue("IconData", memoryStream.ToArray(), typeof(byte[])); } si.AddValue("IconSize", _iconSize, typeof(Size)); } [return: Nullable(2)] public static Icon ExtractAssociatedIcon(string filePath) { return ExtractAssociatedIcon(filePath, 0); } [return: Nullable(2)] private unsafe static Icon ExtractAssociatedIcon(string filePath, int index) { ArgumentNullException.ThrowIfNull(filePath, "filePath"); if (string.IsNullOrEmpty(filePath)) throw new ArgumentException(System.SR.NullOrEmptyPath, "filePath"); filePath = Path.GetFullPath(filePath); if (!File.Exists(filePath)) throw new FileNotFoundException(null, filePath); char[] array = ArrayPool<char>.Shared.Rent(Math.Max(260, filePath.Length)); filePath.CopyTo(0, array, 0, filePath.Length); array[filePath.Length] = ''; HICON handle; fixed (char* value = array) { ushort num = (ushort)index; handle = PInvoke.ExtractAssociatedIcon(HINSTANCE.Null, value, &num); } ArrayPool<char>.Shared.Return(array, false); if (handle.IsNull) return null; return new Icon(handle, true); } public object Clone() { Size size = Size; int width = size.Width; size = Size; return new Icon(this, width, size.Height); } internal void DestroyHandle() { if (_ownHandle) { PInvokeCore.DestroyIcon(_handle); _handle = HICON.Null; GC.KeepAlive(this); } } public void Dispose() { if (!_handle.IsNull) DestroyHandle(); GC.SuppressFinalize(this); } private void DrawIcon(HDC hdc, Rectangle imageRect, Rectangle targetRect, bool stretch) { int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; Size size = Size; int width; int height; if (!imageRect.IsEmpty) { num = imageRect.X; num2 = imageRect.Y; width = imageRect.Width; height = imageRect.Height; } else { width = size.Width; height = size.Height; } int width2; int height2; if (!targetRect.IsEmpty) { num3 = targetRect.X; num4 = targetRect.Y; width2 = targetRect.Width; height2 = targetRect.Height; } else { width2 = size.Width; height2 = size.Height; } int cxWidth; int cyWidth; int num5; int num6; if (stretch) { cxWidth = size.Width * width2 / width; cyWidth = size.Height * height2 / height; num5 = width2; num6 = height2; } else { cxWidth = size.Width; cyWidth = size.Height; num5 = ((width2 < width) ? width2 : width); num6 = ((height2 < height) ? height2 : height); } RegionScope regionScope = new RegionScope(hdc); try { try { PInvokeCore.IntersectClipRect(hdc, num3, num4, num3 + num5, num4 + num6); PInvokeCore.DrawIconEx(hdc, num3 - num, num4 - num2, this, cxWidth, cyWidth, DI_FLAGS.DI_NORMAL); } finally { PInvokeCore.SelectClipRgn(hdc, regionScope); } } finally { regionScope.Dispose(); } } internal void Draw(Graphics graphics, int x, int y) { Size size = Size; Draw(graphics, new Rectangle(x, y, size.Width, size.Height)); } internal void Draw(Graphics graphics, Rectangle targetRect) { Rectangle targetRect2 = targetRect; using (Matrix matrix = graphics.Transform) { PointF offset = matrix.Offset; targetRect2.X += (int)offset.X; targetRect2.Y += (int)offset.Y; DeviceContextHdcScope scope = new DeviceContextHdcScope(graphics, ApplyGraphicsProperties.Clipping, false); try { DrawIcon((HDC)ref scope, Rectangle.Empty, targetRect2, true); } finally { scope.Dispose(); } } } internal void DrawUnstretched(Graphics graphics, Rectangle targetRect) { Rectangle targetRect2 = targetRect; using (Matrix matrix = graphics.Transform) { PointF offset = matrix.Offset; targetRect2.X += (int)offset.X; targetRect2.Y += (int)offset.Y; DeviceContextHdcScope scope = new DeviceContextHdcScope(graphics, ApplyGraphicsProperties.Clipping, false); try { DrawIcon((HDC)ref scope, Rectangle.Empty, targetRect2, false); } finally { scope.Dispose(); } } } ~Icon() { Dispose(); } public static Icon FromHandle(IntPtr handle) { if (handle == IntPtr.Zero) throw new ArgumentException(null, "handle"); return new Icon((HICON)handle); } private unsafe void Initialize(int width, int height) { if (_iconData == null || !_handle.IsNull) throw new InvalidOperationException(System.SR.Format(System.SR.IllegalState, GetType().Name)); SpanReader<byte> spanReader = new SpanReader<byte>(_iconData); ICONDIR value; if (!spanReader.TryRead(out value) || value.idReserved != 0 || value.idType != 1 || value.idCount == 0) throw new ArgumentException(System.SR.Format(System.SR.InvalidPictureType, "picture", "Icon")); if (width == 0) width = PInvokeCore.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CXICON); if (height == 0) height = PInvokeCore.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CYICON); if (s_bitDepth == 0) { GetDcScope scope = GetDcScope.ScreenDC; try { s_bitDepth = PInvokeCore.GetDeviceCaps((HDC)ref scope, GET_DEVICE_CAPS_INDEX.BITSPIXEL); s_bitDepth *= PInvokeCore.GetDeviceCaps((HDC)ref scope, GET_DEVICE_CAPS_INDEX.PLANES); if (s_bitDepth == 8) s_bitDepth = 4; } finally { scope.Dispose(); } } byte b = 0; byte b2 = 0; if (!spanReader.TryRead(value.idCount, out ReadOnlySpan<ICONDIRENTRY> value2)) throw new ArgumentException(System.SR.Format(System.SR.InvalidPictureType, "picture", "Icon")); ReadOnlySpan<ICONDIRENTRY> readOnlySpan = value2; foreach (ICONDIRENTRY iCONDIRENTRY in readOnlySpan) { bool flag = false; uint num; if (iCONDIRENTRY.bColorCount != 0) { num = 4; if (iCONDIRENTRY.bColorCount < 16) num = 1; } else num = iCONDIRENTRY.wBitCount; if (num == 0) num = 8; if (_bestBytesInRes == 0) flag = true; else { int num2 = Math.Abs(b - width) + Math.Abs(b2 - height); int num3 = Math.Abs(iCONDIRENTRY.bWidth - width) + Math.Abs(iCONDIRENTRY.bHeight - height); if (num3 < num2 || (num3 == num2 && ((num <= s_bitDepth && num > _bestBitDepth) || (_bestBitDepth > s_bitDepth && num < _bestBitDepth)))) flag = true; } if (flag) { b = iCONDIRENTRY.bWidth; b2 = iCONDIRENTRY.bHeight; _bestImageOffset = iCONDIRENTRY.dwImageOffset; _bestBytesInRes = iCONDIRENTRY.dwBytesInRes; _bestBitDepth = num; } } if (_bestImageOffset > 2147483647) throw new ArgumentException(System.SR.Format(System.SR.InvalidPictureType, "picture", "Icon")); if (_bestBytesInRes > 2147483647) throw new Win32Exception(87); uint num4; try { num4 = checked(_bestImageOffset + _bestBytesInRes); } catch (OverflowException) { throw new Win32Exception(87); } if (num4 > _iconData.Length) throw new ArgumentException(System.SR.Format(System.SR.InvalidPictureType, "picture", "Icon")); ReadOnlySpan<byte> readOnlySpan2 = spanReader.Span.Slice((int)_bestImageOffset, (int)_bestBytesInRes); if ((long)_bestImageOffset % (long)sizeof(IntPtr) == 0) { fixed (byte* presbits = &readOnlySpan2.GetPinnableReference()) { _handle = PInvoke.CreateIconFromResourceEx(presbits, (uint)readOnlySpan2.Length, true, 196608, 0, 0, IMAGE_FLAGS.LR_DEFAULTCOLOR); } } else { BufferScope<byte> bufferScope = new BufferScope<byte>((int)_bestBytesInRes); try { readOnlySpan2.CopyTo(bufferScope.AsSpan()); fixed (byte* presbits2 = &bufferScope.GetPinnableReference()) { _handle = PInvoke.CreateIconFromResourceEx(presbits2, (uint)readOnlySpan2.Length, true, 196608, 0, 0, IMAGE_FLAGS.LR_DEFAULTCOLOR); } } finally { bufferScope.Dispose(); } } if (_handle.IsNull) throw new Win32Exception(); } private unsafe void CopyBitmapData(BitmapData sourceData, BitmapData targetData) { byte* ptr = (byte*)(long)sourceData.Scan0; byte* ptr2 = (byte*)(long)targetData.Scan0; int num = Math.Min(sourceData.Height, targetData.Height); long num2 = Math.Abs(targetData.Stride); for (int i = 0; i < num; i++) { Buffer.MemoryCopy(ptr, ptr2, num2, num2); ptr += sourceData.Stride; ptr2 += targetData.Stride; } GC.KeepAlive(this); } private unsafe static bool BitmapHasAlpha(BitmapData bmpData) { for (int i = 0; i < bmpData.Height; i++) { for (int j = 3; j < Math.Abs(bmpData.Stride); j += 4) { if (((byte*)bmpData.Scan0.ToPointer() + i * bmpData.Stride)[j] != 0) return true; } } return false; } public Bitmap ToBitmap() { if (HasPngSignature() && !System.LocalAppContextSwitches.DontSupportPngFramesInIcons) { using (MemoryStream memoryStream = new MemoryStream()) { memoryStream.Write(_iconData, (int)_bestImageOffset, (int)_bestBytesInRes); return new Bitmap(memoryStream); } } return BmpFrame(); } private unsafe Bitmap BmpFrame() { Bitmap bitmap = null; if (_iconData != null && _bestBitDepth == 32) { Size size = Size; int width = size.Width; size = Size; bitmap = new Bitmap(width, size.Height, PixelFormat.Format32bppArgb); Bitmap bitmap2 = bitmap; size = Size; int width2 = size.Width; size = Size; BitmapData bitmapData = bitmap2.LockBits(new Rectangle(0, 0, width2, size.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); try { uint* ptr = (uint*)bitmapData.Scan0.ToPointer(); int num = (int)(_bestImageOffset + sizeof(BITMAPINFOHEADER)); size = Size; int length = size.Width * 4; size = Size; int width3 = size.Width; size = Size; for (int num2 = (size.Height - 1) * 4; num2 >= 0; num2 -= 4) { Marshal.Copy(_iconData, num + num2 * width3, (IntPtr)ptr, length); ptr += width3; } } finally { bitmap.UnlockBits(bitmapData); } } else { uint bestBitDepth = _bestBitDepth; if ((bestBitDepth == 0 || bestBitDepth == 32) ? true : false) { ICONINFO iconInfo = PInvokeCore.GetIconInfo(this); BITMAP bITMAP = default(BITMAP); try { if (!iconInfo.hbmColor.IsNull) { PInvokeCore.GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bITMAP); if (bITMAP.bmBitsPixel == 32) { Bitmap bitmap3 = null; BitmapData bitmapData2 = null; BitmapData bitmapData3 = null; try { bitmap3 = Image.FromHbitmap(iconInfo.hbmColor); bitmapData2 = bitmap3.LockBits(new Rectangle(0, 0, bitmap3.Width, bitmap3.Height), ImageLockMode.ReadOnly, bitmap3.PixelFormat); if (BitmapHasAlpha(bitmapData2)) { bitmap = new Bitmap(bitmapData2.Width, bitmapData2.Height, PixelFormat.Format32bppArgb); bitmapData3 = bitmap.LockBits(new Rectangle(0, 0, bitmapData2.Width, bitmapData2.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); CopyBitmapData(bitmapData2, bitmapData3); } } finally { if (bitmap3 != null && bitmapData2 != null) bitmap3.UnlockBits(bitmapData2); if (bitmap != null && bitmapData3 != null) bitmap.UnlockBits(bitmapData3); } bitmap3.Dispose(); } } } finally { if (!iconInfo.hbmColor.IsNull) PInvokeCore.DeleteObject(iconInfo.hbmColor); if (!iconInfo.hbmMask.IsNull) PInvokeCore.DeleteObject(iconInfo.hbmMask); } } } if (bitmap == null) { Size size2 = Size; bitmap = new Bitmap(size2.Width, size2.Height); Graphics graphics; using (graphics = Graphics.FromImage(bitmap)) try { using (Bitmap image = Bitmap.FromHicon(Handle)) graphics.DrawImage(image, new Rectangle(0, 0, size2.Width, size2.Height)); } catch (ArgumentException) { Draw(graphics, new Rectangle(0, 0, size2.Width, size2.Height)); } Color transparentColor = Color.FromArgb(13, 11, 12); bitmap.MakeTransparent(transparentColor); } return bitmap; } private bool HasPngSignature() { if (!_isBestImagePng.HasValue) { if (_iconData != null && _iconData.Length >= _bestImageOffset + 8) { int num = BitConverter.ToInt32(_iconData, (int)_bestImageOffset); int num2 = BitConverter.ToInt32(_iconData, (int)(_bestImageOffset + 4)); _isBestImagePng = (num == 1196314761 && num2 == 169478669); } else _isBestImagePng = false; } return _isBestImagePng.Value; } public override string ToString() { return System.SR.toStringIcon; } public unsafe void Save(Stream outputStream) { ArgumentNullException.ThrowIfNull(outputStream, "outputStream"); if (_iconData != null) outputStream.Write(_iconData, 0, _iconData.Length); else { ComScope<IPicture> comScope = this.CreateIPicture(false); try { ComScope<IStream> scope = outputStream.ToIStream(true); try { comScope.Value->SaveAsFile((IStream*)ref scope, (BOOL)(-1), null).ThrowOnFailure((IntPtr)0); } finally { scope.Dispose(); } } finally { comScope.Dispose(); } } } [return: Nullable(2)] public static Icon ExtractIcon(string filePath, int id, int size) { if ((size > 0 && size <= 65535) || 1 == 0) return ExtractIcon(filePath, id, size, false); throw new ArgumentOutOfRangeException("size"); } [return: Nullable(2)] public static Icon ExtractIcon(string filePath, int id, bool smallIcon = false) { return ExtractIcon(filePath, id, 0, smallIcon); } [return: Nullable(2)] private unsafe static Icon ExtractIcon(string filePath, int id, int size, bool smallIcon = false) { ArgumentNullException.ThrowIfNull(filePath, "filePath"); HICON null = HICON.Null; IntPtr value; if (filePath == null) value = (IntPtr)(void*)null; else { ref reference = ref filePath.GetPinnableReference(); value = (IntPtr)(&reference); } HRESULT hRESULT = PInvoke.SHDefExtractIcon((char*)(long)value, id, 0, (HICON*)(long)(smallIcon ? ((IntPtr)(void*)null) : ((IntPtr)(&null))), (HICON*)(long)(smallIcon ? ((IntPtr)(&null)) : ((IntPtr)(void*)null)), (uint)(((ushort)size << 16) | (ushort)size)); ref reference = ref *(char*)null; if (hRESULT == HRESULT.S_FALSE) return null; try { Marshal.ThrowExceptionForHR(hRESULT); } catch (COMException innerException) { throw new IOException(System.SR.IconCouldNotBeExtracted, innerException); } return new Icon(null, true); } } }