DragDataObject.cs
1 // Copyright (c) Microsoft Corporation 2 // The Microsoft Corporation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Drawing; 7 using System.Runtime.InteropServices; 8 using System.Runtime.InteropServices.ComTypes; 9 10 using DrawingImaging = System.Drawing.Imaging; 11 using MediaImaging = System.Windows.Media.Imaging; 12 13 namespace PowerLauncher.Helper 14 { 15 // based on: https://stackoverflow.com/questions/61041282/showing-image-thumbnail-with-mouse-cursor-while-dragging/61148788#61148788 16 public static class DragDataObject 17 { 18 private static readonly Guid DataObject = new Guid("b8c0bd9f-ed24-455c-83e6-d5390c4fe8c4"); 19 20 public static IDataObject FromFile(string filePath) 21 { 22 Marshal.ThrowExceptionForHR(SHCreateItemFromParsingName(filePath, null, typeof(IShellItem).GUID, out IShellItem item)); 23 Marshal.ThrowExceptionForHR(item.BindToHandler(null, DataObject, typeof(IDataObject).GUID, out object dataObject)); 24 return (IDataObject)dataObject; 25 } 26 27 public static void SetDragImage(this IDataObject dataObject, IntPtr hBitmap, int width, int height) 28 { 29 ArgumentNullException.ThrowIfNull(dataObject); 30 31 IDragSourceHelper dragDropHelper = (IDragSourceHelper)new DragDropHelper(); 32 ShDragImage dragImage = new ShDragImage 33 { 34 HBmpDragImage = hBitmap, 35 SizeDragImage = new Size(width, height), 36 }; 37 Marshal.ThrowExceptionForHR(dragDropHelper.InitializeFromBitmap(ref dragImage, dataObject)); 38 } 39 40 [DllImport("shell32", CharSet = CharSet.Unicode)] 41 private static extern int SHCreateItemFromParsingName(string path, IBindCtx pbc, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IShellItem ppv); 42 43 [Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")] 44 [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 45 private interface IShellItem 46 { 47 [PreserveSig] 48 int BindToHandler(IBindCtx pbc, [MarshalAs(UnmanagedType.LPStruct)] Guid bhid, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppv); 49 50 // more methods available, but we don't need them 51 } 52 53 [ComImport] 54 [Guid("4657278a-411b-11d2-839a-00c04fd918d0")] // CLSID_DragDropHelper 55 private class DragDropHelper 56 { 57 } 58 59 // https://learn.microsoft.com/windows/win32/api/shobjidl_core/ns-shobjidl_core-shdragimage 60 [StructLayout(LayoutKind.Sequential)] 61 private struct ShDragImage 62 { 63 public Size SizeDragImage; 64 public Point PtOffset; 65 public IntPtr HBmpDragImage; 66 public int CrColorKey; 67 } 68 69 // https://learn.microsoft.com/windows/win32/api/shobjidl_core/nn-shobjidl_core-idragsourcehelper 70 [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 71 [Guid("DE5BF786-477A-11D2-839D-00C04FD918D0")] 72 private interface IDragSourceHelper 73 { 74 [PreserveSig] 75 int InitializeFromBitmap(ref ShDragImage pShDrawImage, IDataObject pDataObject); 76 77 // more methods available, but we don't need them 78 } 79 80 // https://stackoverflow.com/a/2897325 81 public static Bitmap BitmapSourceToBitmap(MediaImaging.BitmapSource source) 82 { 83 if (source == null) 84 { 85 return null; 86 } 87 88 Bitmap bitmap = new Bitmap(source.PixelWidth, source.PixelHeight, DrawingImaging.PixelFormat.Format32bppArgb); 89 DrawingImaging.BitmapData bitmapData = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size), DrawingImaging.ImageLockMode.WriteOnly, DrawingImaging.PixelFormat.Format32bppArgb); 90 91 source.CopyPixels(System.Windows.Int32Rect.Empty, bitmapData.Scan0, bitmapData.Height * bitmapData.Stride, bitmapData.Stride); 92 bitmap.UnlockBits(bitmapData); 93 94 return bitmap; 95 } 96 } 97 }