Retrieve filenames from drop event

This commit is contained in:
Simon Lübeß
2025-06-17 18:08:19 +02:00
parent 60482059a4
commit 68745f0515
2 changed files with 175 additions and 5 deletions
+2 -1
View File
@@ -1206,9 +1206,10 @@ namespace GlitchyEditor
if (_isDraggingFromOutside) if (_isDraggingFromOutside)
{ {
// Reset drop effect, so the drop targets have to set it themselves (and don't "leak" it).
SetDropEffect(.None); SetDropEffect(.None);
if (ImGui.BeginDragDropSource(.SourceExtern | .SourceAutoExpirePayload)) if (ImGui.BeginDragDropSource(.SourceExtern | .SourceAutoExpirePayload | .SourceNoPreviewTooltip))
{ {
ImGui.SetDragDropPayload(.ExternFiles, null, 0); ImGui.SetDragDropPayload(.ExternFiles, null, 0);
ImGui.EndDragDropSource(); ImGui.EndDragDropSource();
@@ -5,6 +5,8 @@ using GlitchyEngine;
using GlitchyEngine.Events; using GlitchyEngine.Events;
using static System.Windows; using static System.Windows;
using GlitchyEngine.Math; using GlitchyEngine.Math;
using System.Collections;
using System.IO;
namespace GlitchyEditor.Platform.Windows; namespace GlitchyEditor.Platform.Windows;
@@ -18,6 +20,8 @@ static
public static extern void OleUninitialize(); public static extern void OleUninitialize();
[Import("Ole32.lib"), CLink] [Import("Ole32.lib"), CLink]
public static extern HResult RegisterDragDrop(HWnd windowHandle, IDropTarget* dropTarget); public static extern HResult RegisterDragDrop(HWnd windowHandle, IDropTarget* dropTarget);
[Import("Ole32.lib"), CLink]
public static extern HResult RevokeDragDrop(HWnd windowHandle);
} }
[CRepr] [CRepr]
@@ -31,7 +35,7 @@ struct IDropTarget : IUnknown
public function [CallingConvention(.Stdcall)] HResult(IDropTarget* self, /*IDataObject*/ IUnknown* dataObject, uint32 grfKeyState, int2 point, ref DropEffect effect) DragEnter; public function [CallingConvention(.Stdcall)] HResult(IDropTarget* self, /*IDataObject*/ IUnknown* dataObject, uint32 grfKeyState, int2 point, ref DropEffect effect) DragEnter;
public function [CallingConvention(.Stdcall)] HResult(IDropTarget* self, uint32 grfKeyState, int2 point, ref DropEffect effect) DragOver; public function [CallingConvention(.Stdcall)] HResult(IDropTarget* self, uint32 grfKeyState, int2 point, ref DropEffect effect) DragOver;
public function [CallingConvention(.Stdcall)] HResult(IDropTarget* self) DragLeave; public function [CallingConvention(.Stdcall)] HResult(IDropTarget* self) DragLeave;
public function [CallingConvention(.Stdcall)] HResult(IDropTarget* self, /*IDataObject*/ IUnknown* dataObject, uint32 grfKeyState, int2 point, ref DropEffect effect) Drop; public function [CallingConvention(.Stdcall)] HResult(IDropTarget* self, IDataObject* dataObject, uint32 grfKeyState, int2 point, ref DropEffect effect) Drop;
} }
public new VTable* VT => (VTable*)mVT; public new VTable* VT => (VTable*)mVT;
@@ -51,11 +55,87 @@ struct IDropTarget : IUnknown
return VT.DragLeave(&this); return VT.DragLeave(&this);
} }
public HResult Drop(/*IDataObject*/ IUnknown* dataObject, uint32 grfKeyState, int2 point, ref DropEffect effect) mut public HResult Drop(IDataObject* dataObject, uint32 grfKeyState, int2 point, ref DropEffect effect) mut
{ {
return VT.Drop(&this, dataObject, grfKeyState, point, ref effect); return VT.Drop(&this, dataObject, grfKeyState, point, ref effect);
} }
} }
[CRepr]
public struct DVTARGETDEVICE
{
public uint32 tdSize;
public uint16 tdDriverNameOffset;
public uint16 tdDeviceNameOffset;
public uint16 tdPortNameOffset;
public uint16 tdExtDevmodeOffset;
public uint8[1] tdData_array;
public uint8* tdData mut => &tdData_array[0];
}
[CRepr]
public struct FORMATETC
{
public uint16 cfFormat;
public DVTARGETDEVICE* ptd;
public uint32 dwAspect;
public int32 lindex;
public uint32 tymed;
}
public typealias HDROP = int;
public typealias HBITMAP = int;
public typealias HENHMETAFILE = int;
public typealias PWSTR = char16*;
public typealias BOOL = int32;
[CRepr]
public struct STGMEDIUM
{
public uint32 tymed;
public using _Anonymous_e__Union Anonymous;
public IUnknown* pUnkForRelease;
[CRepr, Union]
public struct _Anonymous_e__Union
{
public HBITMAP hBitmap;
public void* hMetaFilePict;
public HENHMETAFILE hEnhMetaFile;
public int hGlobal;
public PWSTR lpszFileName;
public /*IStream*/IUnknown* pstm;
public /*IStorage*/IUnknown* pstg;
}
}
[CRepr]
public struct IDataObject : IUnknown
{
public const new Guid IID = .(0x0000010e, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
public new VTable* VT { get => (.)mVT; }
public HResult GetData(ref FORMATETC pformatetcIn, out STGMEDIUM pmedium) mut => VT.GetData(ref this, ref pformatetcIn, out pmedium);
public HResult GetDataHere(ref FORMATETC pformatetc, out STGMEDIUM pmedium) mut => VT.GetDataHere(ref this, ref pformatetc, out pmedium);
public HResult QueryGetData(ref FORMATETC pformatetc) mut => VT.QueryGetData(ref this, ref pformatetc);
public HResult GetCanonicalFormatEtc(ref FORMATETC pformatectIn, out FORMATETC pformatetcOut) mut => VT.GetCanonicalFormatEtc(ref this, ref pformatectIn, out pformatetcOut);
public HResult SetData(ref FORMATETC pformatetc, ref STGMEDIUM pmedium, BOOL fRelease) mut => VT.SetData(ref this, ref pformatetc, ref pmedium, fRelease);
public HResult EnumFormatEtc(uint32 dwDirection, out /*IEnumFORMATETC*/ IUnknown* ppenumFormatEtc) mut => VT.EnumFormatEtc(ref this, dwDirection, out ppenumFormatEtc);
public HResult DAdvise(ref FORMATETC pformatetc, uint32 advf, ref /*IAdviseSink*/ IUnknown* pAdvSink, out uint32 pdwConnection) mut => VT.DAdvise(ref this, ref pformatetc, advf, ref pAdvSink, out pdwConnection);
public HResult DUnadvise(uint32 dwConnection) mut => VT.DUnadvise(ref this, dwConnection);
public HResult EnumDAdvise(out /*IEnumSTATDATA*/ IUnknown* ppenumAdvise) mut => VT.EnumDAdvise(ref this, out ppenumAdvise);
[CRepr]
public struct VTable : IUnknown.VTable
{
public new function [CallingConvention(.Stdcall)] HResult(ref IDataObject self, ref FORMATETC pformatetcIn, out STGMEDIUM pmedium) GetData;
public new function [CallingConvention(.Stdcall)] HResult(ref IDataObject self, ref FORMATETC pformatetc, out STGMEDIUM pmedium) GetDataHere;
public new function [CallingConvention(.Stdcall)] HResult(ref IDataObject self, ref FORMATETC pformatetc) QueryGetData;
public new function [CallingConvention(.Stdcall)] HResult(ref IDataObject self, ref FORMATETC pformatectIn, out FORMATETC pformatetcOut) GetCanonicalFormatEtc;
public new function [CallingConvention(.Stdcall)] HResult(ref IDataObject self, ref FORMATETC pformatetc, ref STGMEDIUM pmedium, BOOL fRelease) SetData;
public new function [CallingConvention(.Stdcall)] HResult(ref IDataObject self, uint32 dwDirection, out /*IEnumFORMATETC*/ IUnknown* ppenumFormatEtc) EnumFormatEtc;
public new function [CallingConvention(.Stdcall)] HResult(ref IDataObject self, ref FORMATETC pformatetc, uint32 advf, ref /*IAdviseSink*/ IUnknown* pAdvSink, out uint32 pdwConnection) DAdvise;
public new function [CallingConvention(.Stdcall)] HResult(ref IDataObject self, uint32 dwConnection) DUnadvise;
public new function [CallingConvention(.Stdcall)] HResult(ref IDataObject self, out /*IEnumSTATDATA*/ IUnknown* ppenumAdvise) EnumDAdvise;
}
}
[CRepr] [CRepr]
enum DropEffect enum DropEffect
@@ -67,6 +147,49 @@ enum DropEffect
Scroll = 0x80000000, Scroll = 0x80000000,
} }
public enum CLIPBOARD_FORMATS : uint32
{
TEXT = 1,
BITMAP = 2,
METAFILEPICT = 3,
SYLK = 4,
DIF = 5,
TIFF = 6,
OEMTEXT = 7,
DIB = 8,
PALETTE = 9,
PENDATA = 10,
RIFF = 11,
WAVE = 12,
UNICODETEXT = 13,
ENHMETAFILE = 14,
HDROP = 15,
LOCALE = 16,
DIBV5 = 17,
MAX = 18,
OWNERDISPLAY = 128,
DSPTEXT = 129,
DSPBITMAP = 130,
DSPMETAFILEPICT = 131,
DSPENHMETAFILE = 142,
PRIVATEFIRST = 512,
PRIVATELAST = 767,
GDIOBJFIRST = 768,
GDIOBJLAST = 1023,
}
public enum TYMED : int32
{
HGLOBAL = 1,
FILE = 2,
ISTREAM = 4,
ISTORAGE = 8,
GDI = 16,
MFPICT = 32,
ENHMF = 64,
NULL = 0,
}
abstract class IDropTargetImplBase : RefCounted abstract class IDropTargetImplBase : RefCounted
{ {
[CRepr] [CRepr]
@@ -102,6 +225,12 @@ abstract class IDropTargetImplBase : RefCounted
Log.EngineLogger.Assert(result case .S_OK); Log.EngineLogger.Assert(result case .S_OK);
} }
public void Unregister()
{
HResult result = RevokeDragDrop(Application.Instance.Window.[Friend]_windowHandle);
Log.EngineLogger.Assert(result case .S_OK);
}
private static IDropTargetImplBase GetInstance(IUnknown* self) private static IDropTargetImplBase GetInstance(IUnknown* self)
{ {
IDropTargetImpl* impl = (.)self; IDropTargetImpl* impl = (.)self;
@@ -188,11 +317,51 @@ abstract class IDropTargetImplBase : RefCounted
return .E_FAIL; return .E_FAIL;
} }
[Import("shell32.dll"), CLink, CallingConvention(.Stdcall)]
public static extern uint32 DragQueryFileW(HDROP hDrop, uint32 iFile, char16* lpszFile, uint32 cch);
[Import("ole32.dll"), CLink, CallingConvention(.Stdcall)]
public static extern void ReleaseStgMedium(ref STGMEDIUM param0);
[CallingConvention(.Stdcall)] [CallingConvention(.Stdcall)]
private static HResult DropImpl(IDropTarget* self, /*IDataObject*/ IUnknown* dataObject, uint32 grfKeyState, int2 point, ref DropEffect effect) private static HResult DropImpl(IDropTarget* self, IDataObject* dataObject, uint32 grfKeyState, int2 point, ref DropEffect effect)
{ {
Self instance = GetInstance(self); Self instance = GetInstance(self);
// render the data into stgm using the data description in fmte
FORMATETC format = .()
{
cfFormat = (.)CLIPBOARD_FORMATS.HDROP,
ptd = null,
lindex = -1,
tymed = (.)TYMED.HGLOBAL
};
if (dataObject.GetData(ref format, var stgm).Succeeded)
{
HDROP hdrop = (HDROP)stgm.hGlobal;
uint32 fileCount = DragQueryFileW(hdrop, 0xFFFFFFFF, null, 0);
List<char16> buffer = scope List<char16>();
buffer.Resize(256);
for (uint32 i < fileCount)
{
uint32 requiredSize = DragQueryFileW(hdrop, i, null, 0);
buffer.Resize(requiredSize + 1);
uint32 retrievedSize = DragQueryFileW(hdrop, i, buffer.Ptr, (.)buffer.Count);
if (retrievedSize > 0 && retrievedSize < buffer.Count)
{
String str = scope String(buffer.Ptr);
Log.EngineLogger.Info($"Dropped File: {str}");
}
}
ReleaseStgMedium(ref stgm);
}
Result<DropEffect> result = instance.OnDrop(point); Result<DropEffect> result = instance.OnDrop(point);
if (result case .Ok(out effect)) if (result case .Ok(out effect))