/ src / modules / launcher / PowerLauncher / Helper / DragDataObject.cs
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  }