diff --git a/GlitchyEditor/src/Platform/Windows/DropSource.bf b/GlitchyEditor/src/Platform/Windows/DropSource.bf new file mode 100644 index 0000000..3659c24 --- /dev/null +++ b/GlitchyEditor/src/Platform/Windows/DropSource.bf @@ -0,0 +1,80 @@ +#if BF_PLATFORM_WINDOWS + +using System; +using DirectX.Common; +using GlitchyEngine.Platform.Windows.Com; + +namespace GlitchyEditor.Platform.Windows; + +[CRepr] +public struct IDropSource : IUnknown +{ + public const new Guid IID = .(0x00000121, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); + + public new VTable* VT { get => (.)mVT; } + + public HResult QueryContinueDrag(BigBool fEscapePressed, uint32 grfKeyState) mut => VT.QueryContinueDrag(&this, fEscapePressed, grfKeyState); + public HResult GiveFeedback(DropEffect dwEffect) mut => VT.GiveFeedback(&this, dwEffect); + + [CRepr] + public struct VTable : IUnknown.VTable + { + public new function [CallingConvention(.Stdcall)] HResult(IDropSource* self, BigBool fEscapePressed, uint32 grfKeyState) QueryContinueDrag; + public new function [CallingConvention(.Stdcall)] HResult(IDropSource* self, DropEffect dwEffect) GiveFeedback; + } +} + +abstract class IDropSourceImplBase : IUnknownImplBase +{ + protected override void InitVTable(ref IDropSource.VTable vTable) + { + vTable.QueryContinueDrag = => QueryContinueDragImpl; + vTable.GiveFeedback = => GiveFeedbackImpl; + } + + [CallingConvention(.Stdcall)] + private static HResult QueryContinueDragImpl(IDropSource* self, BigBool fEscapePressed, uint32 grfKeyState) + { + Self instance = GetInstance(self); + + // TODO: Translate keyStates (MK_CONTROL, etc...) + + if (instance.QueryContinueDrag(fEscapePressed, grfKeyState) case .Ok) + { + return .S_OK; + } + + return .E_FAIL; + } + + [CallingConvention(.Stdcall)] + private static HResult GiveFeedbackImpl(IDropSource* self, DropEffect effect) + { + Self instance = GetInstance(self); + + if (instance.GiveFeedback(effect) case .Ok) + { + return .S_OK; + } + + return .E_FAIL; + } + + public abstract Result QueryContinueDrag(bool escapePressed, uint32 grfKeyState); + public abstract Result GiveFeedback(DropEffect effect); +} + +class MyDropSource : IDropSourceImplBase +{ + public override Result QueryContinueDrag(bool escapePressed, uint32 grfKeyState) + { + Runtime.NotImplemented(); + } + + public override Result GiveFeedback(DropEffect effect) + { + Runtime.NotImplemented(); + } +} + +#endif diff --git a/GlitchyEditor/src/Platform/Windows/DropTarget.bf b/GlitchyEditor/src/Platform/Windows/DropTarget.bf index 148ac02..f17c586 100644 --- a/GlitchyEditor/src/Platform/Windows/DropTarget.bf +++ b/GlitchyEditor/src/Platform/Windows/DropTarget.bf @@ -9,6 +9,7 @@ using static System.Windows; using GlitchyEngine.Math; using System.Collections; using System.IO; +using GlitchyEngine.Platform.Windows.Com; namespace GlitchyEditor.Platform.Windows; @@ -191,28 +192,10 @@ public enum TYMED : int32 NULL = 0, } -abstract class IDropTargetImplBase : RefCounted +abstract class IDropTargetImplBase : IUnknownImplBase { - [CRepr] - private struct IDropTargetImpl : IDropTarget + protected override void InitVTable(ref IDropTarget.VTable vTable) { - public void* ClassPtr; - } - - IDropTargetImpl impl; - - IDropTarget.VTable vTable; - - public this() - { - impl = .(); - impl.[Friend]mVT = &vTable; - impl.ClassPtr = Internal.UnsafeCastToPtr(this); - - vTable.QueryInterface = => QueryInterfaceImpl; - vTable.AddRef = => AddRefImpl; - vTable.Release = => ReleaseImpl; - vTable.DragEnter = => DragEnterImpl; vTable.DragOver = => DragOverImpl; vTable.DragLeave = => DragLeaveImpl; @@ -221,7 +204,7 @@ abstract class IDropTargetImplBase : RefCounted public void Register() { - HResult result = RegisterDragDrop(Application.Instance.Window.[Friend]_windowHandle, &impl); + HResult result = RegisterDragDrop(Application.Instance.Window.[Friend]_windowHandle, InterfacePtr); Log.EngineLogger.Assert(result not case .E_OUTOFMEMORY, "Failed to register drag drop handler (E_OUTOFMEMORY). Make sure you called OleInitialize and not CoInitialize[Ex]"); Log.EngineLogger.Assert(result case .S_OK); } @@ -234,50 +217,6 @@ abstract class IDropTargetImplBase : RefCounted OleUninitialize(); } - private static IDropTargetImplBase GetInstance(IUnknown* self) - { - IDropTargetImpl* impl = (.)self; - - return (.)Internal.UnsafeCastToObject(impl.ClassPtr); - } - - private static HResult QueryInterfaceImpl(IUnknown* self, ref Guid riid, void** output) - { - Self instance = GetInstance(self); - - HResult result = .E_NOINTERFACE; - *output = null; - - if (riid == IUnknown.IID || riid == IDropTarget.IID) - { - *output = (IUnknown*)&instance.impl; - instance.AddRef(); - result = .S_OK; - } - - return result; - } - - private static uint32 AddRefImpl(IUnknown* self) - { - Self instance = GetInstance(self); - - instance.AddRef(); - return (uint32)instance.RefCount; - } - - private static uint32 ReleaseImpl(IUnknown* self) - { - Self instance = GetInstance(self); - - uint32 count = (uint32)instance.ReleaseRefNoDelete(); - - if (count == 0) - delete instance; - - return count; - } - // TODO: Data object? KeyState? public abstract Result OnDragEnter(int2 cursorPosition); public abstract Result OnDragOver(int2 cursorPosition); @@ -287,7 +226,7 @@ abstract class IDropTargetImplBase : RefCounted [CallingConvention(.Stdcall)] private static HResult DragEnterImpl(IDropTarget* self, /*IDataObject*/ IUnknown* dataObject, uint32 grfKeyState, int2 point, ref DropEffect effect) { - Self instance = GetInstance(self); + Self instance = GetInstance(self); Result result = instance.OnDragEnter(point); @@ -300,7 +239,7 @@ abstract class IDropTargetImplBase : RefCounted [CallingConvention(.Stdcall)] private static HResult DragOverImpl(IDropTarget* self, uint32 grfKeyState, int2 point, ref DropEffect effect) { - Self instance = GetInstance(self); + Self instance = GetInstance(self); Result result = instance.OnDragOver(point); if (result case .Ok(out effect)) @@ -312,7 +251,7 @@ abstract class IDropTargetImplBase : RefCounted [CallingConvention(.Stdcall)] private static HResult DragLeaveImpl(IDropTarget* self) { - Self instance = GetInstance(self); + Self instance = GetInstance(self); Result result = instance.OnDragLeave(); if (result case .Ok) @@ -330,7 +269,7 @@ abstract class IDropTargetImplBase : RefCounted [CallingConvention(.Stdcall)] 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 = .() @@ -368,7 +307,7 @@ abstract class IDropTargetImplBase : RefCounted int endIndex = paths.Length; // StringViews might be invalid until fixup step down below - files.Add(StringView(paths, startIndex, endIndex - startIndex)); + files.Add(StringView(paths, startIndex, endIndex - startIndex - 1)); } } @@ -381,7 +320,7 @@ abstract class IDropTargetImplBase : RefCounted for (ref StringView path in ref files) { path.Ptr = paths.Ptr + index; - index += path.Length; + index += path.Length + 1; } Result result = instance.OnDrop(point, files); diff --git a/GlitchyEngine/src/Platform/Windows/Com/IUnknownImpBase.bf b/GlitchyEngine/src/Platform/Windows/Com/IUnknownImpBase.bf new file mode 100644 index 0000000..3c8561a --- /dev/null +++ b/GlitchyEngine/src/Platform/Windows/Com/IUnknownImpBase.bf @@ -0,0 +1,93 @@ +using System; +using DirectX.Common; +using GlitchyEngine.Core; +using System.Diagnostics; + +namespace GlitchyEngine.Platform.Windows.Com; + +/// Base class for implementation of an COM-Interface using a Beef-Class. +abstract class IUnknownImplBase : RefCounter where TInterface : IUnknown, struct where TVTable : IUnknown.VTable +{ + [CRepr] + protected struct InterfaceImpl + { + public TInterface Base; + public void* ClassPtr; + } + + InterfaceImpl impl; + + private static TVTable vTable; + + protected TInterface* InterfacePtr => (TInterface*)&impl; + + public this() + { + impl = .(); + impl.Base.[Friend]mVT = (IUnknown.VTable*)&vTable; + impl.ClassPtr = Internal.UnsafeCastToPtr(this); + + if (vTable.QueryInterface == null) + { + vTable.QueryInterface = => QueryInterfaceImpl; + vTable.AddRef = => AddRefImpl; + vTable.Release = => ReleaseImpl; + + InitVTable(ref vTable); + } + } + + protected abstract void InitVTable(ref TVTable vTable); + + /// Get the beef instance from the interface. + protected static T GetInstance(IUnknown* self) where T : class + { + InterfaceImpl* impl = (.)self; + + Object beefInstance = Internal.UnsafeCastToObject(impl.ClassPtr); + + Debug.Assert(beefInstance is T); + + return (T)beefInstance; + } + + [CallingConvention(.Stdcall)] + private static HResult QueryInterfaceImpl(IUnknown* self, ref Guid riid, void** output) + { + Self instance = GetInstance(self); + + HResult result = .E_NOINTERFACE; + *output = null; + + if (riid == IUnknown.IID || riid == TInterface.IID) + { + *output = (IUnknown*)&instance.impl; + instance.AddRef(); + result = .S_OK; + } + + return result; + } + + [CallingConvention(.Stdcall)] + private static uint32 AddRefImpl(IUnknown* self) + { + Self instance = GetInstance(self); + + instance.AddRef(); + return (uint32)instance.RefCount; + } + + [CallingConvention(.Stdcall)] + private static uint32 ReleaseImpl(IUnknown* self) + { + Self instance = GetInstance(self); + + uint32 count = (uint32)instance.ReleaseRefNoDelete(); + + if (count == 0) + delete instance; + + return count; + } +}