|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Drawing;
using System.Private.Windows.Ole;
using Windows.Win32.System.Com;
namespace System.Windows.Forms.Ole;
/// <summary>
/// Provides Windows Forms specific OLE services.
/// </summary>
internal sealed class WinFormsOleServices : IOleServices
{
private WinFormsOleServices() { }
static void IOleServices.EnsureThreadState()
{
if (Control.CheckForIllegalCrossThreadCalls && Application.OleRequired() != ApartmentState.STA)
{
throw new ThreadStateException(SR.ThreadMustBeSTA);
}
}
static unsafe HRESULT IOleServices.GetDataHere(string format, object data, FORMATETC* pformatetc, STGMEDIUM* pmedium)
{
if (format == DataFormatNames.Dib && data is Image)
{
// GDI+ does not properly handle saving to DIB images. Since the clipboard will take
// an HBITMAP and publish a Dib, we don't need to support this.
return HRESULT.DV_E_TYMED;
}
if (((TYMED)pformatetc->tymed).HasFlag(TYMED.TYMED_GDI))
{
if (format.Equals(DataFormatNames.Bitmap) && data is Bitmap bitmap)
{
// Save bitmap
pmedium->u.hBitmap = GetCompatibleBitmap(bitmap);
}
return HRESULT.S_OK;
}
return HRESULT.DV_E_TYMED;
static HBITMAP GetCompatibleBitmap(Bitmap bitmap)
{
using var screenDC = GetDcScope.ScreenDC;
// GDI+ returns a DIBSECTION based HBITMAP. The clipboard only deals well with bitmaps created using
// CreateCompatibleBitmap(). So, we convert the DIBSECTION into a compatible bitmap.
HBITMAP hbitmap = bitmap.GetHBITMAP();
// Create a compatible DC to render the source bitmap.
using CreateDcScope sourceDC = new(screenDC);
using SelectObjectScope sourceBitmapSelection = new(sourceDC, hbitmap);
// Create a compatible DC and a new compatible bitmap.
using CreateDcScope destinationDC = new(screenDC);
HBITMAP compatibleBitmap = PInvokeCore.CreateCompatibleBitmap(screenDC, bitmap.Size.Width, bitmap.Size.Height);
// Select the new bitmap into a compatible DC and render the blt the original bitmap.
using SelectObjectScope destinationBitmapSelection = new(destinationDC, compatibleBitmap);
PInvokeCore.BitBlt(
destinationDC,
0,
0,
bitmap.Size.Width,
bitmap.Size.Height,
sourceDC,
0,
0,
ROP_CODE.SRCCOPY);
return compatibleBitmap;
}
}
}
|