| File: System\Private\Windows\Ole\DragDropFormat.cs | Web Access |
| Project: src\winforms\src\System.Private.Windows.Core\src\Microsoft.Private.Windows.Core.csproj (Microsoft.Private.Windows.Core) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Windows.Win32.System.Com; using Windows.Win32.System.Memory; using Windows.Win32.System.Ole; namespace System.Private.Windows.Ole; /// <summary> /// Represents a private format used for data transfer by the drag-and-drop helpers. /// </summary> internal class DragDropFormat : IDisposable { private ushort _format; private STGMEDIUM _medium; public STGMEDIUM Medium => _medium; /// <summary> /// Initializes a new instance of the <see cref="DragDropFormat"/> class using the specified format, storage medium, and owner. /// </summary> public DragDropFormat(ushort format, STGMEDIUM medium, bool copyData) { _format = format; // Handle whether the data object or the caller owns the storage medium. _medium = copyData ? CopyData(format, medium) : medium; } /// <summary> /// Returns a copy of the storage medium in this instance. /// </summary> public STGMEDIUM GetData() => CopyData(_format, _medium); /// <summary> /// Refreshes the storage medium in this instance. /// </summary> public void RefreshData(ushort format, STGMEDIUM medium, bool copyData) { ReleaseData(); _format = format; // Handle whether the data object or the caller owns the storage medium. _medium = copyData ? CopyData(format, medium) : medium; } /// <summary> /// Copies a given storage medium. /// </summary> /// <returns> /// A copy of <paramref name="mediumSource"/>. /// </returns> private static unsafe STGMEDIUM CopyData(ushort format, STGMEDIUM mediumSource) { STGMEDIUM mediumDestination = default; try { switch (mediumSource.tymed) { case TYMED.TYMED_HGLOBAL: case TYMED.TYMED_FILE: case TYMED.TYMED_ENHMF: case TYMED.TYMED_GDI: case TYMED.TYMED_MFPICT: mediumDestination.hGlobal = (HGLOBAL)(nint)PInvokeCore.OleDuplicateData( (HANDLE)(nint)mediumSource.hGlobal, (CLIPBOARD_FORMAT)format, // Note that GMEM_DDESHARE is ignored GLOBAL_ALLOC_FLAGS.GMEM_MOVEABLE | GLOBAL_ALLOC_FLAGS.GMEM_ZEROINIT); if (mediumDestination.hGlobal.IsNull) { return default; } break; case TYMED.TYMED_ISTORAGE: case TYMED.TYMED_ISTREAM: mediumDestination.hGlobal = mediumSource.hGlobal; Marshal.AddRef(mediumSource.hGlobal); break; case TYMED.TYMED_NULL: default: mediumDestination.hGlobal = HGLOBAL.Null; break; } mediumDestination.tymed = mediumSource.tymed; mediumDestination.pUnkForRelease = mediumSource.pUnkForRelease; if (mediumSource.pUnkForRelease is not null) { mediumSource.pUnkForRelease->AddRef(); } return mediumDestination; } catch { PInvokeCore.ReleaseStgMedium(ref mediumDestination); return default; } } /// <summary> /// Frees the storage medium in this instance. /// </summary> private unsafe void ReleaseData() { PInvokeCore.ReleaseStgMedium(ref _medium); _medium.pUnkForRelease = null; _medium.tymed = TYMED.TYMED_NULL; _medium.hGlobal = HGLOBAL.Null; } public void Dispose() { ReleaseData(); GC.SuppressFinalize(this); } ~DragDropFormat() { Dispose(); } }