| File: System\Windows\Ole\WpfOleServices.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\PresentationCore\PresentationCore.csproj (PresentationCore) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Private.Windows.Ole; using System.Windows.Interop; using System.Windows.Media.Imaging; using MS.Internal; using Windows.Win32; using Windows.Win32.Graphics.Gdi; using Windows.Win32.System.Com; using Windows.Win32.System.Ole; using Com = Windows.Win32.System.Com; using HRESULT = Windows.Win32.Foundation.HRESULT; namespace System.Windows.Ole; internal sealed unsafe class WpfOleServices : IOleServices { // Prevent instantiation private WpfOleServices() { } public static void EnsureThreadState() => OleServicesContext.EnsureThreadState(); public static HRESULT GetDataHere(string format, object data, FORMATETC* pformatetc, STGMEDIUM* pmedium) { TYMED mediumType = (TYMED)pformatetc->tymed; // Handle bitmaps. if (mediumType.HasFlag(TYMED.TYMED_GDI) && format.Equals(DataFormatNames.Bitmap) && (SystemDrawingHelper.IsBitmap(data) || data is BitmapSource)) { pmedium->u.hBitmap = GetCompatibleBitmap(data); return HRESULT.S_OK; } // Handle enhanced metafiles. if (mediumType.HasFlag(TYMED.TYMED_ENHMF) && format.Equals(DataFormatNames.Emf)) { if (SystemDrawingHelper.IsMetafile(data)) { pmedium->u.hEnhMetaFile = SystemDrawingHelper.GetHandleFromMetafile(data); } else if (data is MemoryStream memoryStream && memoryStream.GetBuffer() is { } buffer && buffer.Length != 0) { HENHMETAFILE hemf = PInvoke.SetEnhMetaFileBits(buffer); if (hemf.IsNull) { throw new Win32Exception(); } } return HRESULT.S_OK; } return HRESULT.DV_E_TYMED; static HBITMAP GetCompatibleBitmap(object data) { HBITMAP hbitmap = SystemDrawingHelper.GetHBitmap(data, out int width, out int height); return hbitmap.IsNull ? HBITMAP.Null : hbitmap.CreateCompatibleBitmap(width, height); } } public static bool TryGetObjectFromDataObject<T>( Com.IDataObject* dataObject, string format, [NotNullWhen(true)] out T data) { data = default!; TYMED mediumType; ushort formatId; if (format == DataFormatNames.Bitmap) { mediumType = TYMED.TYMED_GDI; formatId = (ushort)CLIPBOARD_FORMAT.CF_BITMAP; } else if (format == DataFormatNames.Emf) { mediumType = TYMED.TYMED_ENHMF; formatId = (ushort)CLIPBOARD_FORMAT.CF_ENHMETAFILE; } else { return false; } FORMATETC formatEtc = new() { cfFormat = formatId, dwAspect = (uint)DVASPECT.DVASPECT_CONTENT, lindex = -1, tymed = (uint)mediumType }; HRESULT result = dataObject->QueryGetData(formatEtc); if (result.Failed) { return false; } result = dataObject->GetData(formatEtc, out STGMEDIUM medium); try { if (result.Failed) { return false; } if (mediumType == TYMED.TYMED_GDI) { // Get the bitmap from the handle of bitmap. object bitmap = Imaging.CreateBitmapSourceFromHBitmap( (HBITMAP)(nint)medium.hGlobal, 0, Int32Rect.Empty, sizeOptions: null); if (bitmap is T t) { data = t; return true; } } else { // Get the metafile object form the enhanced metafile handle. object metafile = SystemDrawingHelper.GetMetafileFromHemf((HENHMETAFILE)(nint)medium.hGlobal); if (metafile is T t) { data = t; return true; } } } finally { PInvokeCore.ReleaseStgMedium(ref medium); } return false; } public static bool AllowTypeWithoutResolver<T>() { // Image is a special case because we are reading bitmaps directly from the SerializationRecord. return typeof(T).FullName.Equals("System.Drawing.Image"); } public static bool IsValidTypeForFormat(Type type, string format) => format switch { DataFormatNames.Bitmap or DataFormatNames.BinaryFormatBitmap => type == typeof(BitmapSource) || type.FullName is "System.Drawing.Bitmap" or "System.Drawing.Image", DataFormatNames.Emf or DataFormatNames.BinaryFormatMetafile => type.FullName is "System.Drawing.Imaging.Metafile" or "System.Drawing.Image", // All else should fall through as valid. _ => true }; public static void ValidateDataStoreData(ref string format, bool autoConvert, object data) { // We do not have proper support for Dibs, so if the user explicitly asked // for Dib and provided a Bitmap object we can't convert. Instead, publish as an HBITMAP // and let the system provide the conversion for us. if (format == DataFormats.Dib && autoConvert && (SystemDrawingHelper.IsBitmap(data) || data is BitmapSource)) { format = DataFormats.Bitmap; } } public static IComVisibleDataObject CreateDataObject() => new DataObject(); static HRESULT IOleServices.OleGetClipboard(Com.IDataObject** dataObject) => PInvokeCore.OleGetClipboard(dataObject); static HRESULT IOleServices.OleSetClipboard(Com.IDataObject* dataObject) => PInvokeCore.OleSetClipboard(dataObject); static HRESULT IOleServices.OleFlushClipboard() => PInvokeCore.OleFlushClipboard(); }