mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
Remove OLE interop dependency.
This commit is contained in:
parent
96bb94b9d5
commit
0c53741b1d
6 changed files with 76 additions and 39 deletions
|
|
@ -8,6 +8,7 @@ using System.Threading.Tasks;
|
|||
using Dalamud.Configuration.Internal;
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.Gui.Internal;
|
||||
using Dalamud.Interface.DragDrop;
|
||||
using Dalamud.Interface.Internal;
|
||||
using Dalamud.Plugin.Internal;
|
||||
using Dalamud.Utility;
|
||||
|
|
@ -135,6 +136,9 @@ internal sealed class Dalamud : IServiceType
|
|||
// will not receive any windows messages
|
||||
Service<DalamudIME>.GetNullable()?.Dispose();
|
||||
|
||||
// this must be done before unloading interface manager, since it relies on the window handle members.
|
||||
Service<DragDropManager>.GetNullable()?.Dispose();
|
||||
|
||||
// this must be done before unloading plugins, or it can cause a race condition
|
||||
// due to rendering happening on another thread, where a plugin might receive
|
||||
// a render call after it has been disposed, which can crash if it attempts to
|
||||
|
|
|
|||
|
|
@ -82,7 +82,6 @@
|
|||
</PackageReference>
|
||||
<PackageReference Include="System.Collections.Immutable" Version="7.0.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Interop" Version="17.0" />
|
||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||
<PackageReference Include="System.Reflection.MetadataLoadContext" Version="7.0.0" />
|
||||
<PackageReference Include="System.Resources.Extensions" Version="7.0.0" />
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Text;
|
||||
|
||||
using Microsoft.VisualStudio.OLE.Interop;
|
||||
|
||||
// ReSharper disable UnusedMember.Local
|
||||
// ReSharper disable IdentifierTypo
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
|
@ -12,6 +12,29 @@ namespace Dalamud.Interface.DragDrop;
|
|||
/// <summary> Implements interop enums and function calls to interact with external drag and drop. </summary>
|
||||
internal partial class DragDropManager
|
||||
{
|
||||
internal struct POINTL
|
||||
{
|
||||
[ComAliasName("Microsoft.VisualStudio.OLE.Interop.LONG")]
|
||||
public int x;
|
||||
[ComAliasName("Microsoft.VisualStudio.OLE.Interop.LONG")]
|
||||
public int y;
|
||||
}
|
||||
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[Guid("00000122-0000-0000-C000-000000000046")]
|
||||
[ComImport]
|
||||
public interface IDropTarget
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
void DragEnter([MarshalAs(UnmanagedType.Interface), In] IDataObject pDataObj, [ComAliasName("Microsoft.VisualStudio.OLE.Interop.DWORD"), In] uint grfKeyState, [ComAliasName("Microsoft.VisualStudio.OLE.Interop.POINTL"), In] POINTL pt, [ComAliasName("Microsoft.VisualStudio.OLE.Interop.DWORD"), In, Out] ref uint pdwEffect);
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
void DragOver([ComAliasName("Microsoft.VisualStudio.OLE.Interop.DWORD"), In] uint grfKeyState, [ComAliasName("Microsoft.VisualStudio.OLE.Interop.POINTL"), In] POINTL pt, [ComAliasName("Microsoft.VisualStudio.OLE.Interop.DWORD"), In, Out] ref uint pdwEffect);
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
void DragLeave();
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
void Drop([MarshalAs(UnmanagedType.Interface), In] IDataObject pDataObj, [ComAliasName("Microsoft.VisualStudio.OLE.Interop.DWORD"), In] uint grfKeyState, [ComAliasName("Microsoft.VisualStudio.OLE.Interop.POINTL"), In] POINTL pt, [ComAliasName("Microsoft.VisualStudio.OLE.Interop.DWORD"), In, Out] ref uint pdwEffect);
|
||||
}
|
||||
|
||||
private static class DragDropInterop
|
||||
{
|
||||
[Flags]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Interface.Internal;
|
||||
using ImGuiNET;
|
||||
using Serilog;
|
||||
|
||||
|
|
@ -11,17 +12,22 @@ namespace Dalamud.Interface.DragDrop;
|
|||
/// A manager that keeps state of external windows drag and drop events,
|
||||
/// and can be used to create ImGui drag and drop sources and targets for those external events.
|
||||
/// </summary>
|
||||
internal partial class DragDropManager : IDisposable, IDragDropManager
|
||||
[ServiceManager.EarlyLoadedService]
|
||||
internal partial class DragDropManager : IDisposable, IDragDropManager, IServiceType
|
||||
{
|
||||
private readonly UiBuilder uiBuilder;
|
||||
|
||||
private InterfaceManager? interfaceManager;
|
||||
private int lastDropFrame = -2;
|
||||
private int lastTooltipFrame = -1;
|
||||
|
||||
/// <summary> Initializes a new instance of the <see cref="DragDropManager"/> class.</summary>
|
||||
/// <param name="uiBuilder">The parent <see cref="UiBuilder"/> instance.</param>
|
||||
public DragDropManager(UiBuilder uiBuilder)
|
||||
=> this.uiBuilder = uiBuilder;
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private DragDropManager()
|
||||
{
|
||||
Service<InterfaceManager.InterfaceManagerWithScene>.GetAsync().ContinueWith(task =>
|
||||
{
|
||||
this.interfaceManager = task.Result.Manager;
|
||||
this.Enable();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary> Gets a value indicating whether external drag and drop is available at all. </summary>
|
||||
public bool ServiceAvailable { get; private set; }
|
||||
|
|
@ -44,14 +50,15 @@ internal partial class DragDropManager : IDisposable, IDragDropManager
|
|||
/// <summary> Enable external drag and drop. </summary>
|
||||
public void Enable()
|
||||
{
|
||||
if (this.ServiceAvailable)
|
||||
if (this.ServiceAvailable || this.interfaceManager == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var ret2 = DragDropInterop.RegisterDragDrop(this.uiBuilder.WindowHandlePtr, this);
|
||||
var ret2 = DragDropInterop.RegisterDragDrop(this.interfaceManager.WindowHandlePtr, this);
|
||||
Log.Information($"[DragDrop] Registered window {this.interfaceManager.WindowHandlePtr} for external drag and drop operations. ({ret2})");
|
||||
Marshal.ThrowExceptionForHR(ret2);
|
||||
this.ServiceAvailable = true;
|
||||
}
|
||||
|
|
@ -71,7 +78,8 @@ internal partial class DragDropManager : IDisposable, IDragDropManager
|
|||
|
||||
try
|
||||
{
|
||||
DragDropInterop.RevokeDragDrop(this.uiBuilder.WindowHandlePtr);
|
||||
DragDropInterop.RevokeDragDrop(this.interfaceManager!.WindowHandlePtr);
|
||||
Log.Information($"[DragDrop] Disabled external drag and drop operations for window {this.interfaceManager.WindowHandlePtr}.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,29 +2,29 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Text;
|
||||
|
||||
using Dalamud.Utility;
|
||||
using ImGuiNET;
|
||||
using Microsoft.VisualStudio.OLE.Interop;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Interface.DragDrop;
|
||||
|
||||
/// <summary> Implements the IDropTarget interface to interact with external drag and dropping. </summary>
|
||||
internal partial class DragDropManager : IDropTarget
|
||||
internal partial class DragDropManager : DragDropManager.IDropTarget
|
||||
{
|
||||
private int lastUpdateFrame = -1;
|
||||
|
||||
/// <summary> Create the drag and drop formats we accept. </summary>
|
||||
private static readonly FORMATETC[] FormatEtc =
|
||||
{
|
||||
private static FORMATETC FormatEtc =
|
||||
new()
|
||||
{
|
||||
cfFormat = (ushort)DragDropInterop.ClipboardFormat.CF_HDROP,
|
||||
cfFormat = (short)DragDropInterop.ClipboardFormat.CF_HDROP,
|
||||
ptd = nint.Zero,
|
||||
dwAspect = (uint)DragDropInterop.DVAspect.DVASPECT_CONTENT,
|
||||
dwAspect = DVASPECT.DVASPECT_CONTENT,
|
||||
lindex = -1,
|
||||
tymed = (uint)DragDropInterop.TYMED.TYMED_HGLOBAL,
|
||||
},
|
||||
tymed = TYMED.TYMED_HGLOBAL,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -39,7 +39,7 @@ internal partial class DragDropManager : IDropTarget
|
|||
this.IsDragging = true;
|
||||
UpdateIo((DragDropInterop.ModifierKeys)grfKeyState, true);
|
||||
|
||||
if (pDataObj.QueryGetData(FormatEtc) != 0)
|
||||
if (pDataObj.QueryGetData(ref FormatEtc) != 0)
|
||||
{
|
||||
pdwEffect = 0;
|
||||
}
|
||||
|
|
@ -50,17 +50,24 @@ internal partial class DragDropManager : IDropTarget
|
|||
this.HasPaths = this.Files.Count + this.Directories.Count > 0;
|
||||
this.Extensions = this.Files.Select(Path.GetExtension).Where(p => !p.IsNullOrEmpty()).Distinct().ToHashSet();
|
||||
}
|
||||
Log.Debug("[DragDrop] Entering external Drag and Drop with {KeyState} at {PtX}, {PtY} and with {N} files.", (DragDropInterop.ModifierKeys)grfKeyState, pt.x, pt.y, this.Files.Count + this.Directories.Count);
|
||||
}
|
||||
|
||||
/// <summary> Invoked every windows update-frame as long as the drag and drop process keeps hovering over an FFXIV-related viewport. </summary>
|
||||
/// <param name="grfKeyState"> The mouse button used to drag as well as key modifiers. </param>
|
||||
/// <param name="pt"> The global cursor position. </param>
|
||||
/// <param name="pdwEffect"> Effects that can be used with this drag and drop process. </param>
|
||||
/// <remarks> Can be invoked more often than once a XIV frame, can also be less often (?). </remarks>
|
||||
/// <remarks> Can be invoked more often than once a XIV frame, so we are keeping track of frames to skip unnecessary updates. </remarks>
|
||||
public void DragOver(uint grfKeyState, POINTL pt, ref uint pdwEffect)
|
||||
{
|
||||
var frame = ImGui.GetFrameCount();
|
||||
if (frame != this.lastUpdateFrame)
|
||||
{
|
||||
this.lastUpdateFrame = frame;
|
||||
UpdateIo((DragDropInterop.ModifierKeys)grfKeyState, false);
|
||||
pdwEffect &= (uint)DragDropInterop.DropEffects.Copy;
|
||||
Log.Verbose("[DragDrop] External Drag and Drop with {KeyState} at {PtX}, {PtY}.", (DragDropInterop.ModifierKeys)grfKeyState, pt.x, pt.y);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Invoked whenever a drag and drop process that hovered over any FFXIV-related viewport leaves all FFXIV-related viewports. </summary>
|
||||
|
|
@ -70,6 +77,7 @@ internal partial class DragDropManager : IDropTarget
|
|||
this.Files = Array.Empty<string>();
|
||||
this.Directories = Array.Empty<string>();
|
||||
this.Extensions = new HashSet<string>();
|
||||
Log.Debug("[DragDrop] Leaving external Drag and Drop.");
|
||||
}
|
||||
|
||||
/// <summary> Invoked whenever a drag process ends by dropping over any FFXIV-related viewport. </summary>
|
||||
|
|
@ -90,6 +98,8 @@ internal partial class DragDropManager : IDropTarget
|
|||
{
|
||||
pdwEffect = 0;
|
||||
}
|
||||
|
||||
Log.Debug("[DragDrop] Dropping {N} files with {KeyState} at {PtX}, {PtY}.", this.Files.Count + this.Directories.Count, (DragDropInterop.ModifierKeys)grfKeyState, pt.x, pt.y);
|
||||
}
|
||||
|
||||
private static void UpdateIo(DragDropInterop.ModifierKeys keys, bool entering)
|
||||
|
|
@ -189,12 +199,8 @@ internal partial class DragDropManager : IDropTarget
|
|||
|
||||
try
|
||||
{
|
||||
var stgMedium = new STGMEDIUM[]
|
||||
{
|
||||
default,
|
||||
};
|
||||
data.GetData(FormatEtc, stgMedium);
|
||||
var numFiles = DragDropInterop.DragQueryFile(stgMedium[0].unionmember, uint.MaxValue, new StringBuilder(), 0);
|
||||
data.GetData(ref FormatEtc, out var stgMedium);
|
||||
var numFiles = DragDropInterop.DragQueryFile(stgMedium.unionmember, uint.MaxValue, new StringBuilder(), 0);
|
||||
var files = new string[numFiles];
|
||||
var sb = new StringBuilder(1024);
|
||||
var directoryCount = 0;
|
||||
|
|
@ -202,11 +208,11 @@ internal partial class DragDropManager : IDropTarget
|
|||
for (var i = 0u; i < numFiles; ++i)
|
||||
{
|
||||
sb.Clear();
|
||||
var ret = DragDropInterop.DragQueryFile(stgMedium[0].unionmember, i, sb, sb.Capacity);
|
||||
var ret = DragDropInterop.DragQueryFile(stgMedium.unionmember, i, sb, sb.Capacity);
|
||||
if (ret >= sb.Capacity)
|
||||
{
|
||||
sb.Capacity = ret + 1;
|
||||
ret = DragDropInterop.DragQueryFile(stgMedium[0].unionmember, i, sb, sb.Capacity);
|
||||
ret = DragDropInterop.DragQueryFile(stgMedium.unionmember, i, sb, sb.Capacity);
|
||||
}
|
||||
|
||||
if (ret > 0 && ret < sb.Capacity)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public sealed class UiBuilder : IDisposable
|
|||
private readonly string namespaceName;
|
||||
private readonly InterfaceManager interfaceManager = Service<InterfaceManager>.Get();
|
||||
private readonly GameFontManager gameFontManager = Service<GameFontManager>.Get();
|
||||
private readonly DragDropManager dragDropManager;
|
||||
private readonly DragDropManager dragDropManager = Service<DragDropManager>.Get();
|
||||
|
||||
private bool hasErrorWindow = false;
|
||||
private bool lastFrameUiHideState = false;
|
||||
|
|
@ -49,8 +49,6 @@ public sealed class UiBuilder : IDisposable
|
|||
this.stopwatch = new Stopwatch();
|
||||
this.hitchDetector = new HitchDetector($"UiBuilder({namespaceName})", this.configuration.UiBuilderHitch);
|
||||
this.namespaceName = namespaceName;
|
||||
this.dragDropManager = new DragDropManager(this);
|
||||
this.dragDropManager.Enable();
|
||||
|
||||
this.interfaceManager.Draw += this.OnDraw;
|
||||
this.interfaceManager.BuildFonts += this.OnBuildFonts;
|
||||
|
|
@ -406,7 +404,6 @@ public sealed class UiBuilder : IDisposable
|
|||
/// </summary>
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
this.dragDropManager.Dispose();
|
||||
this.interfaceManager.Draw -= this.OnDraw;
|
||||
this.interfaceManager.BuildFonts -= this.OnBuildFonts;
|
||||
this.interfaceManager.ResizeBuffers -= this.OnResizeBuffers;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue