File: System\Windows\Forms\OLE\WinFormsOleServices.cs
Web Access
Project: src\src\System.Windows.Forms\src\System.Windows.Forms.csproj (System.Windows.Forms)
// 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;
        }
    }
}