Browse Source

Win32 - export bitmap in more clipboard formats (#20209)

* win32 - export bitmap in more clipboard formats

* addressed review

* use compatible bitmap for ole gdi copy

* change bitmap intent to colormetric

---------

Co-authored-by: Julien Lebosquain <julien@lebosquain.net>
release/11.3.10
Emmanuel Hansen 2 months ago
committed by Julien Lebosquain
parent
commit
9c7258a8f2
No known key found for this signature in database GPG Key ID: 1833CAD10ACC46FD
  1. 26
      src/Windows/Avalonia.Win32/ClipboardFormatRegistry.cs
  2. 38
      src/Windows/Avalonia.Win32/DataTransferToOleDataObjectWrapper.cs
  3. 100
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  4. 230
      src/Windows/Avalonia.Win32/OleDataObjectHelper.cs
  5. 10
      src/Windows/Avalonia.Win32/OleDataObjectToDataTransferWrapper.cs

26
src/Windows/Avalonia.Win32/ClipboardFormatRegistry.cs

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.ComponentModel;
using Avalonia.Input;
using Avalonia.Media.Imaging;
using Avalonia.Utilities;
using Avalonia.Win32.Interop;
@ -12,17 +13,28 @@ namespace Avalonia.Win32
private const int MaxFormatNameLength = 260;
private const string AppPrefix = "avn-app-fmt:";
public const string PngFormatMimeType = "image/png";
public const string JpegFormatMimeType = "image/jpeg";
public const string PngFormatSystemType = "PNG";
public const string BitmapFormat = "CF_BITMAP";
public const string DibFormat = "CF_DIB";
public const string DibV5Format = "CF_DIBV5";
private static readonly List<(DataFormat Format, ushort Id)> s_formats = [];
public static DataFormat PngSystemDataFormat = DataFormat.FromSystemName<Bitmap>(PngFormatSystemType, AppPrefix);
public static DataFormat PngMimeDataFormat = DataFormat.FromSystemName<Bitmap>(PngFormatMimeType, AppPrefix);
public static DataFormat HBitmapDataFormat = DataFormat.FromSystemName<Bitmap>(BitmapFormat, AppPrefix);
public static DataFormat DibDataFormat = DataFormat.FromSystemName<Bitmap>(DibFormat, AppPrefix);
public static DataFormat DibV5DataFormat = DataFormat.FromSystemName<Bitmap>(DibV5Format, AppPrefix);
public static DataFormat[] ImageFormats = [PngMimeDataFormat, PngSystemDataFormat, DibDataFormat, DibV5DataFormat, HBitmapDataFormat];
static ClipboardFormatRegistry()
{
AddDataFormat(DataFormat.Text, (ushort)UnmanagedMethods.ClipboardFormat.CF_UNICODETEXT);
AddDataFormat(DataFormat.Text, (ushort)UnmanagedMethods.ClipboardFormat.CF_TEXT);
AddDataFormat(DataFormat.File, (ushort)UnmanagedMethods.ClipboardFormat.CF_HDROP);
AddDataFormat(DataFormat.Bitmap, (ushort)UnmanagedMethods.ClipboardFormat.CF_DIB);
AddDataFormat(DibDataFormat, (ushort)UnmanagedMethods.ClipboardFormat.CF_DIB);
AddDataFormat(DibV5DataFormat, (ushort)UnmanagedMethods.ClipboardFormat.CF_DIBV5);
AddDataFormat(HBitmapDataFormat, (ushort)UnmanagedMethods.ClipboardFormat.CF_BITMAP);
}
private static void AddDataFormat(DataFormat format, ushort id)
@ -62,24 +74,18 @@ namespace Avalonia.Win32
if (DataFormat.Bitmap.Equals(format))
{
(DataFormat, ushort)? pngFormat = null;
(DataFormat, ushort)? jpgFormat = null;
(DataFormat, ushort)? dibFormat = null;
(DataFormat, ushort)? bitFormat = null;
foreach (var currentFormat in s_formats)
{
if (currentFormat.Id == (ushort)UnmanagedMethods.ClipboardFormat.CF_DIB)
dibFormat = currentFormat;
else if (currentFormat.Id == (ushort)UnmanagedMethods.ClipboardFormat.CF_BITMAP)
bitFormat = currentFormat;
else if (currentFormat.Format.Identifier == PngFormatMimeType)
pngFormat = currentFormat;
else if (currentFormat.Format.Identifier == JpegFormatMimeType)
jpgFormat = currentFormat;
}
var imageFormatId = dibFormat?.Item2 ?? bitFormat?.Item2 ?? pngFormat?.Item2 ?? jpgFormat?.Item2 ?? 0;
var imageFormatId = pngFormat?.Item2 ?? dibFormat?.Item2 ?? 0;
if(imageFormatId != 0)
if (imageFormatId != 0)
{
return imageFormatId;
}

38
src/Windows/Avalonia.Win32/DataTransferToOleDataObjectWrapper.cs

@ -6,7 +6,6 @@ using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using Avalonia.Input;
using Avalonia.MicroCom;
using Avalonia.Platform.Storage;
using static Avalonia.Win32.Interop.UnmanagedMethods;
using FORMATETC = Avalonia.Win32.Interop.UnmanagedMethods.FORMATETC;
using STGMEDIUM = Avalonia.Win32.Interop.UnmanagedMethods.STGMEDIUM;
@ -33,7 +32,23 @@ internal class DataTransferToOleDataObjectWrapper(IDataTransfer dataTransfer)
public FormatEnumerator(IReadOnlyList<DataFormat> dataFormats)
{
_formats = dataFormats.Select(OleDataObjectHelper.ToFormatEtc).ToArray();
List<FORMATETC> formats = new List<FORMATETC>();
if (dataFormats.Contains(DataFormat.Bitmap))
{
// We add extra formats for bitmaps
formats.Add(OleDataObjectHelper.ToFormatEtc(ClipboardFormatRegistry.PngMimeDataFormat));
formats.Add(OleDataObjectHelper.ToFormatEtc(ClipboardFormatRegistry.PngSystemDataFormat));
formats.Add(OleDataObjectHelper.ToFormatEtc(ClipboardFormatRegistry.DibDataFormat));
formats.Add(OleDataObjectHelper.ToFormatEtc(ClipboardFormatRegistry.DibV5DataFormat));
formats.Add(OleDataObjectHelper.ToFormatEtc(ClipboardFormatRegistry.HBitmapDataFormat, true));
}
else
{
formats.AddRange(dataFormats.Select(x => OleDataObjectHelper.ToFormatEtc(x)));
}
_formats = formats.ToArray();
_current = 0;
}
@ -113,9 +128,18 @@ internal class DataTransferToOleDataObjectWrapper(IDataTransfer dataTransfer)
if (!ValidateFormat(format, out var result, out var dataFormat))
return result;
*medium = default;
medium->tymed = TYMED.TYMED_HGLOBAL;
return OleDataObjectHelper.WriteDataToHGlobal(DataTransfer, dataFormat, ref medium->unionmember);
if (format->tymed == TYMED.TYMED_GDI)
{
*medium = default;
medium->tymed = TYMED.TYMED_GDI;
return OleDataObjectHelper.WriteDataToGdi(DataTransfer, dataFormat, ref medium->unionmember);
}
else
{
*medium = default;
medium->tymed = TYMED.TYMED_HGLOBAL;
return OleDataObjectHelper.WriteDataToHGlobal(DataTransfer, dataFormat, ref medium->unionmember);
}
}
unsafe uint Win32Com.IDataObject.GetDataHere(FORMATETC* format, STGMEDIUM* medium)
@ -142,7 +166,7 @@ internal class DataTransferToOleDataObjectWrapper(IDataTransfer dataTransfer)
{
dataFormat = null;
if (!format->tymed.HasAllFlags(TYMED.TYMED_HGLOBAL))
if (!(format->tymed.HasAllFlags(TYMED.TYMED_HGLOBAL) || format->cfFormat == (ushort)ClipboardFormat.CF_BITMAP && format->tymed == TYMED.TYMED_GDI))
{
result = DV_E_TYMED;
dataFormat = null;
@ -162,7 +186,7 @@ internal class DataTransferToOleDataObjectWrapper(IDataTransfer dataTransfer)
}
dataFormat = ClipboardFormatRegistry.GetFormatById(format->cfFormat);
if (!DataTransfer.Contains(dataFormat))
if (!DataTransfer.Contains(dataFormat) && !ClipboardFormatRegistry.ImageFormats.Contains(dataFormat))
{
result = DV_E_FORMATETC;
return false;

100
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@ -887,6 +887,23 @@ namespace Avalonia.Win32.Interop
BI_PNG = 5
}
public enum BitmapColorSpace : uint
{
LCS_CALIBRATED_RGB = 0,
LCS_sRGB = 0x73524742,
LCS_WINDOWS_COLOR_SPACE = 0x57696E20,
PROFILE_LINKED = 0x4C494E4B,
PROFILE_EMBEDDED = 0x4D424544
}
public enum BitmapIntent : uint
{
LCS_GM_ABS_COLORIMETRIC = 1,
LCS_GM_BUSINESS = 2,
LCS_GM_GRAPHICS = 4,
LCS_GM_IMAGES = 8,
}
public enum DIBColorTable
{
DIB_RGB_COLORS = 0, /* color table in RGBs */
@ -1093,7 +1110,7 @@ namespace Avalonia.Win32.Interop
public int biHeight;
public ushort biPlanes;
public ushort biBitCount;
public uint biCompression;
public BitmapCompressionMode biCompression;
public uint biSizeImage;
public int biXPelsPerMeter;
public int biYPelsPerMeter;
@ -1106,6 +1123,56 @@ namespace Avalonia.Win32.Interop
}
}
[StructLayout(LayoutKind.Sequential)]
public struct BITMAPV5HEADER
{
public uint bV5Size;
public int bV5Width;
public int bV5Height;
public ushort bV5Planes;
public ushort bV5BitCount;
public BitmapCompressionMode bV5Compression;
public uint bV5SizeImage;
public int bV5XPelsPerMeter;
public int bV5YPelsPerMeter;
public uint bV5ClrUsed;
public uint bV5ClrImportant;
public uint bV5RedMask;
public uint bV5GreenMask;
public uint bV5BlueMask;
public uint bV5AlphaMask;
public BitmapColorSpace bV5CSType;
public CIEXYZTRIPLE bV5Endpoints;
public uint bV5GammaRed;
public uint bV5GammaGreen;
public uint bV5GammaBlue;
public BitmapIntent bV5Intent;
public uint bV5ProfileData;
public uint bV5ProfileSize;
public uint bV5Reserved;
public void Init()
{
bV5Size = (uint)sizeof(BITMAPV5HEADER);
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct CIEXYZTRIPLE
{
public CIEXYZ ciexyzRed;
public CIEXYZ ciexyzGreen;
public CIEXYZ ciexyzBlue;
}
[StructLayout(LayoutKind.Sequential)]
internal struct CIEXYZ
{
public int ciexyzX;
public int ciexyzY;
public int ciexyzZ;
}
[StructLayout(LayoutKind.Sequential)]
public struct BITMAPINFO
{
@ -1126,9 +1193,10 @@ namespace Avalonia.Win32.Interop
public uint biClrUsed;
public uint biClrImportant;
//}
public uint biRedMask;
public uint biGreenMask;
public uint biBlueMask;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public uint[] cols;
}
[StructLayout(LayoutKind.Sequential)]
@ -1200,6 +1268,15 @@ namespace Avalonia.Win32.Interop
uint uStartScan, uint cScanLines,
IntPtr lpvBits, [In] ref BITMAPINFO lpbmi, uint fuColorUse);
[DllImport("gdi32.dll")]
public static extern int SetDIBits(IntPtr hdc, IntPtr hbm, uint start, uint cLines, IntPtr lpBits, in BITMAPINFO lpbmi, uint fuColorUse);
[DllImport("gdi32.dll")]
public static extern int SetDIBits(IntPtr hdc, IntPtr hbm, uint start, uint cLines, IntPtr lpBits, in BITMAPINFOHEADER lpbmi, uint fuColorUse);
[DllImport("gdi32.dll")]
public static extern int SetDIBits(IntPtr hdc, IntPtr hbm, uint start, uint cLines, IntPtr lpBits, in BITMAPV5HEADER lpbmi, uint fuColorUse);
[DllImport("gdi32.dll", SetLastError = false, ExactSpelling = true)]
public static extern IntPtr CreateRectRgn(int x1, int y1, int x2, int y2);
@ -1689,13 +1766,25 @@ namespace Avalonia.Win32.Interop
[DllImport("gdi32.dll")]
public static extern int SetDIBitsToDevice(IntPtr hdc, int XDest, int YDest, uint
dwWidth, uint dwHeight, int XSrc, int YSrc, uint uStartScan, uint cScanLines,
IntPtr lpvBits, [In] ref BITMAPINFOHEADER lpbmi, uint fuColorUse);
IntPtr lpvBits, [In] ref BITMAPINFOHEADER lpbmi, DIBColorTable fuColorUse);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateDIBSection(IntPtr hDC, ref BITMAPINFOHEADER pBitmapInfo, int un, out IntPtr lplpVoid, IntPtr handle, int dw);
public static extern IntPtr CreateDIBSection(IntPtr hDC, ref BITMAPINFOHEADER pBitmapInfo, DIBColorTable usage, out IntPtr lplpVoid, IntPtr handle, int dw);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateDIBSection(IntPtr hDC, in BITMAPV5HEADER pBitmapInfo, DIBColorTable usage, out IntPtr lplpVoid, IntPtr handle, int dw);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateDIBitmap(IntPtr hDC, in BITMAPV5HEADER pBitmapInfo, int flInit, IntPtr lplpVoid, in BITMAPINFO pbmi, DIBColorTable iUsage);
[DllImport("gdi32.dll")]
public static extern bool GdiFlush();
[DllImport("gdi32.dll")]
public static extern bool BitBlt(IntPtr hDC, int x, int y, int cx, int cy, IntPtr hdcSrc, int x1, int y1, uint rop);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int cx, int cy);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateBitmap(int width, int height, int planes, int bitCount, IntPtr data);
[DllImport("gdi32.dll")]
@ -2222,6 +2311,7 @@ namespace Avalonia.Win32.Interop
/// A handle to type HDROP that identifies a list of files.
/// </summary>
CF_HDROP = 15,
CF_DIBV5 = 17,
}
public struct MSG

230
src/Windows/Avalonia.Win32/OleDataObjectHelper.cs

@ -7,10 +7,10 @@ using System.Runtime.InteropServices.ComTypes;
using Avalonia.Input;
using Avalonia.Logging;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Avalonia.Platform.Storage;
using Avalonia.Platform.Storage.FileIO;
using Avalonia.Utilities;
using Avalonia.Win32.Interop;
using static Avalonia.Win32.Interop.UnmanagedMethods;
using FORMATETC = Avalonia.Win32.Interop.UnmanagedMethods.FORMATETC;
using STGMEDIUM = Avalonia.Win32.Interop.UnmanagedMethods.STGMEDIUM;
@ -24,14 +24,14 @@ internal static class OleDataObjectHelper
{
private const int SRCCOPY = 0x00CC0020;
public static FORMATETC ToFormatEtc(this DataFormat format)
public static FORMATETC ToFormatEtc(this DataFormat format, bool isGdi = false)
=> new()
{
cfFormat = ClipboardFormatRegistry.GetFormatId(format),
dwAspect = DVASPECT.DVASPECT_CONTENT,
ptd = IntPtr.Zero,
lindex = -1,
tymed = TYMED.TYMED_HGLOBAL
tymed = isGdi ? TYMED.TYMED_GDI : TYMED.TYMED_HGLOBAL
};
public static unsafe object? TryGet(this Win32Com.IDataObject oleDataObject, DataFormat format)
@ -327,42 +327,91 @@ internal static class OleDataObjectHelper
return WriteFileNamesToHGlobal(ref hGlobal, fileNames);
}
if (DataFormat.Bitmap.Equals(format))
if (ClipboardFormatRegistry.DibDataFormat.Equals(format)
|| ClipboardFormatRegistry.DibV5DataFormat.Equals(format))
{
var bitmap = dataTransfer.TryGetValue(DataFormat.Bitmap);
if (bitmap != null)
{
bool isV5 = ClipboardFormatRegistry.DibV5DataFormat.Equals(format);
var pixelSize = bitmap.PixelSize;
var bpp = bitmap.Format?.BitsPerPixel ?? 0;
var stride = ((bitmap.Format?.BitsPerPixel ?? 0) / 8) * pixelSize.Width;
var buffer = new byte[stride * pixelSize.Height];
fixed (byte* bytes = buffer)
{
bitmap.CopyPixels(new PixelRect(pixelSize), (IntPtr)bytes, buffer.Length, stride);
var infoHeader = new BITMAPINFOHEADER()
if (!isV5)
{
biSizeImage = (uint)buffer.Length,
biWidth = pixelSize.Width,
biHeight = -pixelSize.Height,
biBitCount = (ushort)(bitmap.Format?.BitsPerPixel ?? 0),
biPlanes = 1,
biCompression = (uint)BitmapCompressionMode.BI_RGB
};
infoHeader.Init();
var imageData = new byte[infoHeader.biSize + infoHeader.biSizeImage];
fixed (byte* image = imageData)
var infoHeader = new BITMAPINFOHEADER()
{
biSizeImage = (uint)buffer.Length,
biWidth = pixelSize.Width,
biHeight = -pixelSize.Height,
biBitCount = (ushort)bpp,
biPlanes = 1,
biCompression = BitmapCompressionMode.BI_RGB,
};
infoHeader.Init();
var imageData = new byte[infoHeader.biSize + infoHeader.biSizeImage];
fixed (byte* image = imageData)
{
Marshal.StructureToPtr(infoHeader, (IntPtr)image, false);
new Span<byte>(bytes, buffer.Length).CopyTo(new Span<byte>((image + infoHeader.biSize), buffer.Length));
return WriteBytesToHGlobal(ref hGlobal, imageData);
}
}
else
{
Marshal.StructureToPtr(infoHeader, (IntPtr)image, false);
new Span<byte>(bytes, buffer.Length).CopyTo(new Span<byte>((image + infoHeader.biSize), buffer.Length));
return WriteBytesToHGlobal(ref hGlobal, imageData);
var infoHeader = new BITMAPV5HEADER()
{
bV5Width = pixelSize.Width,
bV5Height = -pixelSize.Height,
bV5Planes = 1,
bV5BitCount = (ushort)bpp,
bV5Compression = bpp > 16 ? BitmapCompressionMode.BI_BITFIELDS : BitmapCompressionMode.BI_RGB,
bV5SizeImage = (uint)buffer.Length,
bV5RedMask = GetRedMask(bitmap),
bV5BlueMask = GetBlueMask(bitmap),
bV5GreenMask = GetGreenMask(bitmap),
bV5AlphaMask = GetAlphaMask(bitmap),
bV5CSType = BitmapColorSpace.LCS_sRGB,
bV5Intent = BitmapIntent.LCS_GM_ABS_COLORIMETRIC
};
infoHeader.Init();
var imageData = new byte[infoHeader.bV5Size + infoHeader.bV5SizeImage];
fixed (byte* image = imageData)
{
Marshal.StructureToPtr(infoHeader, (IntPtr)image, false);
new Span<byte>(bytes, buffer.Length).CopyTo(new Span<byte>((image + infoHeader.bV5Size), buffer.Length));
return WriteBytesToHGlobal(ref hGlobal, imageData);
}
}
}
}
}
if (ClipboardFormatRegistry.PngSystemDataFormat.Equals(format)
|| ClipboardFormatRegistry.PngMimeDataFormat.Equals(format))
{
var bitmap = dataTransfer.TryGetValue(DataFormat.Bitmap);
if (bitmap != null)
{
using var stream = new MemoryStream();
bitmap.Save(stream);
return WriteBytesToHGlobal(ref hGlobal, stream.ToArray().AsSpan());
}
return DV_E_FORMATETC;
}
if (format is DataFormat<string> stringFormat)
{
return dataTransfer.TryGetValue(stringFormat) is { } stringValue ?
@ -383,6 +432,145 @@ internal static class OleDataObjectHelper
return DV_E_FORMATETC;
}
private static uint GetAlphaMask(Bitmap? bitmap)
{
return bitmap?.Format?.FormatEnum switch
{
PixelFormatEnum.Rgba8888 => 0xff000000,
PixelFormatEnum.Bgra8888 => 0xff000000,
PixelFormatEnum.Rgb565 => 0,
_ => throw new NotSupportedException()
};
}
private static uint GetGreenMask(Bitmap? bitmap)
{
return bitmap?.Format?.FormatEnum switch
{
PixelFormatEnum.Rgba8888 => 0x0000ff00,
PixelFormatEnum.Bgra8888 => 0x0000ff00,
PixelFormatEnum.Rgb565 => 0b0000011111100000,
_ => throw new NotSupportedException()
};
}
private static uint GetBlueMask(Bitmap? bitmap)
{
return bitmap?.Format?.FormatEnum switch
{
PixelFormatEnum.Rgba8888 => 0x00ff0000,
PixelFormatEnum.Bgra8888 => 0x000000ff,
PixelFormatEnum.Rgb565 => 0b1111100000000000,
_ => throw new NotSupportedException()
};
}
private static uint GetRedMask(Bitmap? bitmap)
{
return bitmap?.Format?.FormatEnum switch
{
PixelFormatEnum.Rgba8888 => 0x000000ff,
PixelFormatEnum.Bgra8888 => 0x00ff0000,
PixelFormatEnum.Rgb565 => 0b0000000000011111,
_ => throw new NotSupportedException()
};
}
public unsafe static uint WriteDataToGdi(IDataTransfer dataTransfer, DataFormat format, ref IntPtr hGlobalBitmap)
{
if (ClipboardFormatRegistry.HBitmapDataFormat.Equals(format))
{
var bitmap = dataTransfer.TryGetValue(DataFormat.Bitmap);
if (bitmap != null)
{
var pixelSize = bitmap.PixelSize;
var bpp = bitmap.Format?.BitsPerPixel ?? 0;
var stride = (bpp / 8) * pixelSize.Width;
var buffer = new byte[stride * pixelSize.Height];
fixed (byte* bytes = buffer)
{
bitmap.CopyPixels(new PixelRect(pixelSize), (IntPtr)bytes, buffer.Length, stride);
IntPtr hdc = IntPtr.Zero, compatDc = IntPtr.Zero, desDc = IntPtr.Zero, hbitmap = IntPtr.Zero, section = IntPtr.Zero;
try
{
hdc = GetDC(IntPtr.Zero);
if (hdc == IntPtr.Zero)
return DV_E_FORMATETC;
compatDc = CreateCompatibleDC(hdc);
if (compatDc == IntPtr.Zero)
return DV_E_FORMATETC;
desDc = CreateCompatibleDC(hdc);
if (desDc == IntPtr.Zero)
return DV_E_FORMATETC;
var bitmapInfoHeader = new BITMAPV5HEADER()
{
bV5Width = pixelSize.Width,
bV5Height = -pixelSize.Height,
bV5Planes = 1,
bV5BitCount = (ushort)bpp,
bV5Compression = BitmapCompressionMode.BI_BITFIELDS,
bV5SizeImage = (uint)buffer.Length,
bV5RedMask = GetRedMask(bitmap),
bV5BlueMask = GetBlueMask(bitmap),
bV5GreenMask = GetGreenMask(bitmap),
bV5AlphaMask = GetAlphaMask(bitmap),
bV5CSType = BitmapColorSpace.LCS_sRGB,
bV5Intent = BitmapIntent.LCS_GM_ABS_COLORIMETRIC,
};
bitmapInfoHeader.Init();
section = CreateDIBSection(compatDc, bitmapInfoHeader, 0, out var lbBits, IntPtr.Zero, 0);
if (section == IntPtr.Zero)
return DV_E_FORMATETC;
SelectObject(compatDc, section);
Marshal.Copy(buffer, 0, lbBits, buffer.Length);
hbitmap = CreateCompatibleBitmap(desDc, pixelSize.Width, pixelSize.Height);
SelectObject(desDc, hbitmap);
if (!BitBlt(desDc, 0, 0, pixelSize.Width, pixelSize.Height, compatDc, 0, 0, SRCCOPY))
{
return DV_E_FORMATETC;
}
hGlobalBitmap = hbitmap;
GdiFlush();
return (uint)HRESULT.S_OK;
}
finally
{
SelectObject(compatDc, IntPtr.Zero);
SelectObject(desDc, IntPtr.Zero);
if (desDc != IntPtr.Zero)
ReleaseDC(IntPtr.Zero, desDc);
if (compatDc != IntPtr.Zero)
ReleaseDC(IntPtr.Zero, compatDc);
if (hdc != IntPtr.Zero)
ReleaseDC(IntPtr.Zero, hdc);
}
}
}
}
Logger.TryGet(LogEventLevel.Warning, LogArea.Win32Platform)
?.Log(null, "Unsupported gdi data format {Format}", format);
return DV_E_FORMATETC;
}
private static unsafe uint WriteStringToHGlobal(ref IntPtr hGlobal, string data)
{
var requiredSize = (data.Length + 1) * sizeof(char);

10
src/Windows/Avalonia.Win32/OleDataObjectToDataTransferWrapper.cs

@ -32,21 +32,21 @@ internal sealed class OleDataObjectToDataTransferWrapper(Win32Com.IDataObject ol
while (Next(enumFormat) is { } format)
formats.Add(format);
bool hasSupportedFormat = false;
bool hasSupportedImageFormat = false;
foreach (var format in formats)
{
if (format.Identifier is ClipboardFormatRegistry.DibFormat
or ClipboardFormatRegistry.BitmapFormat
or ClipboardFormatRegistry.PngFormatMimeType
or ClipboardFormatRegistry.JpegFormatMimeType)
or ClipboardFormatRegistry.PngFormatMimeType
or ClipboardFormatRegistry.PngFormatSystemType)
{
hasSupportedFormat = true;
hasSupportedImageFormat = true;
break;
}
}
if (hasSupportedFormat)
if (hasSupportedImageFormat)
{
formats.Add(DataFormat.Bitmap);
}

Loading…
Cancel
Save