|
|
@ -49,23 +49,30 @@ internal class Win32Icon : IDisposable |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
~Win32Icon() |
|
|
|
|
|
{ |
|
|
|
|
|
UnmanagedMethods.DestroyIcon(Handle); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
public IntPtr Handle { get; private set; } |
|
|
public IntPtr Handle { get; private set; } |
|
|
public PixelSize Size { get; } |
|
|
public PixelSize Size { get; } |
|
|
|
|
|
|
|
|
private readonly byte[]? _bytes; |
|
|
private readonly byte[]? _bytes; |
|
|
|
|
|
|
|
|
|
|
|
private const string GdiError = "A GDI+ error occurred."; |
|
|
|
|
|
|
|
|
IntPtr CreateIcon(Bitmap bitmap, PixelPoint hotSpot = default) |
|
|
IntPtr CreateIcon(Bitmap bitmap, PixelPoint hotSpot = default) |
|
|
{ |
|
|
{ |
|
|
|
|
|
|
|
|
var mainBitmap = CreateHBitmap(bitmap); |
|
|
var mainBitmap = CreateHBitmap(bitmap); |
|
|
if (mainBitmap == IntPtr.Zero) |
|
|
if (mainBitmap == IntPtr.Zero) |
|
|
throw new Win32Exception(); |
|
|
throw new Win32Exception(GdiError); |
|
|
var alphaBitmap = AlphaToMask(bitmap); |
|
|
var alphaBitmap = AlphaToMask(bitmap); |
|
|
|
|
|
|
|
|
try |
|
|
try |
|
|
{ |
|
|
{ |
|
|
if (alphaBitmap == IntPtr.Zero) |
|
|
if (alphaBitmap == IntPtr.Zero) |
|
|
throw new Win32Exception(); |
|
|
throw new Win32Exception(GdiError); |
|
|
var info = new UnmanagedMethods.ICONINFO |
|
|
var info = new UnmanagedMethods.ICONINFO |
|
|
{ |
|
|
{ |
|
|
IsIcon = false, |
|
|
IsIcon = false, |
|
|
@ -77,7 +84,7 @@ internal class Win32Icon : IDisposable |
|
|
|
|
|
|
|
|
var hIcon = UnmanagedMethods.CreateIconIndirect(ref info); |
|
|
var hIcon = UnmanagedMethods.CreateIconIndirect(ref info); |
|
|
if (hIcon == IntPtr.Zero) |
|
|
if (hIcon == IntPtr.Zero) |
|
|
throw new Win32Exception(); |
|
|
throw new Win32Exception(Marshal.GetLastWin32Error()); |
|
|
return hIcon; |
|
|
return hIcon; |
|
|
} |
|
|
} |
|
|
finally |
|
|
finally |
|
|
@ -303,6 +310,7 @@ internal class Win32Icon : IDisposable |
|
|
|
|
|
|
|
|
var bestSize = new PixelSize(bestWidth, bestHeight); |
|
|
var bestSize = new PixelSize(bestWidth, bestHeight); |
|
|
|
|
|
|
|
|
|
|
|
IntPtr handle; |
|
|
// Copy the bytes into an aligned buffer if needed.
|
|
|
// Copy the bytes into an aligned buffer if needed.
|
|
|
if ((_bestImageOffset % IntPtr.Size) != 0) |
|
|
if ((_bestImageOffset % IntPtr.Size) != 0) |
|
|
{ |
|
|
{ |
|
|
@ -314,8 +322,8 @@ internal class Win32Icon : IDisposable |
|
|
{ |
|
|
{ |
|
|
fixed (byte* pbAlignedBuffer = alignedBuffer) |
|
|
fixed (byte* pbAlignedBuffer = alignedBuffer) |
|
|
{ |
|
|
{ |
|
|
return (UnmanagedMethods.CreateIconFromResourceEx(pbAlignedBuffer, _bestBytesInRes, 1, |
|
|
handle = UnmanagedMethods.CreateIconFromResourceEx(pbAlignedBuffer, _bestBytesInRes, 1, |
|
|
0x00030000, 0, 0, 0), bestSize); |
|
|
0x00030000, 0, 0, 0); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
finally |
|
|
finally |
|
|
@ -328,14 +336,26 @@ internal class Win32Icon : IDisposable |
|
|
{ |
|
|
{ |
|
|
try |
|
|
try |
|
|
{ |
|
|
{ |
|
|
return (UnmanagedMethods.CreateIconFromResourceEx(checked(b + _bestImageOffset), _bestBytesInRes, |
|
|
handle = UnmanagedMethods.CreateIconFromResourceEx(checked(b + _bestImageOffset), _bestBytesInRes, |
|
|
1, 0x00030000, 0, 0, 0), bestSize); |
|
|
1, 0x00030000, 0, 0, 0); |
|
|
} |
|
|
} |
|
|
catch (OverflowException) |
|
|
catch (OverflowException) |
|
|
{ |
|
|
{ |
|
|
return default; |
|
|
return default; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (handle == default) |
|
|
|
|
|
{ |
|
|
|
|
|
var error = Marshal.GetLastWin32Error(); |
|
|
|
|
|
// If there we are out of GDI handles then our fallback won't work either, so throw now.
|
|
|
|
|
|
if (error == (int)Windows.Win32.Foundation.WIN32_ERROR.ERROR_NOT_ENOUGH_MEMORY) |
|
|
|
|
|
{ |
|
|
|
|
|
throw new Win32Exception(error); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return (handle, bestSize); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -348,5 +368,6 @@ internal class Win32Icon : IDisposable |
|
|
{ |
|
|
{ |
|
|
UnmanagedMethods.DestroyIcon(Handle); |
|
|
UnmanagedMethods.DestroyIcon(Handle); |
|
|
Handle = IntPtr.Zero; |
|
|
Handle = IntPtr.Zero; |
|
|
|
|
|
GC.SuppressFinalize(this); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|