mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
Remove most hand-authored native functions
This commit is contained in:
parent
1bc216ccd6
commit
fe562e8cf3
14 changed files with 204 additions and 1744 deletions
|
|
@ -21,6 +21,7 @@ using Dalamud.Utility;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
|
using Windows.Win32.UI.WindowsAndMessaging;
|
||||||
|
|
||||||
namespace Dalamud.Configuration.Internal;
|
namespace Dalamud.Configuration.Internal;
|
||||||
|
|
||||||
|
|
@ -595,11 +596,15 @@ internal sealed class DalamudConfiguration : IInternalDisposableService
|
||||||
{
|
{
|
||||||
// https://source.chromium.org/chromium/chromium/src/+/main:ui/gfx/animation/animation_win.cc;l=29?q=ReducedMotion&ss=chromium
|
// https://source.chromium.org/chromium/chromium/src/+/main:ui/gfx/animation/animation_win.cc;l=29?q=ReducedMotion&ss=chromium
|
||||||
var winAnimEnabled = 0;
|
var winAnimEnabled = 0;
|
||||||
var success = NativeFunctions.SystemParametersInfo(
|
var success = false;
|
||||||
(uint)NativeFunctions.AccessibilityParameter.SPI_GETCLIENTAREAANIMATION,
|
unsafe
|
||||||
0,
|
{
|
||||||
ref winAnimEnabled,
|
success = Windows.Win32.PInvoke.SystemParametersInfo(
|
||||||
0);
|
SYSTEM_PARAMETERS_INFO_ACTION.SPI_GETCLIENTAREAANIMATION,
|
||||||
|
0,
|
||||||
|
&winAnimEnabled,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ using Dalamud.Utility;
|
||||||
using Dalamud.Utility.Timing;
|
using Dalamud.Utility.Timing;
|
||||||
using PInvoke;
|
using PInvoke;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
using Windows.Win32.Foundation;
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
[assembly: InternalsVisibleTo("Dalamud.CorePlugin")]
|
[assembly: InternalsVisibleTo("Dalamud.CorePlugin")]
|
||||||
|
|
@ -29,7 +30,7 @@ namespace Dalamud;
|
||||||
/// The main Dalamud class containing all subsystems.
|
/// The main Dalamud class containing all subsystems.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ServiceManager.ProvidedService]
|
[ServiceManager.ProvidedService]
|
||||||
internal sealed class Dalamud : IServiceType
|
internal sealed unsafe class Dalamud : IServiceType
|
||||||
{
|
{
|
||||||
#region Internals
|
#region Internals
|
||||||
|
|
||||||
|
|
@ -79,7 +80,7 @@ internal sealed class Dalamud : IServiceType
|
||||||
{
|
{
|
||||||
Log.Verbose("=============== GAME THREAD KICKOFF ===============");
|
Log.Verbose("=============== GAME THREAD KICKOFF ===============");
|
||||||
Timings.Event("Game thread kickoff");
|
Timings.Event("Game thread kickoff");
|
||||||
NativeFunctions.SetEvent(mainThreadContinueEvent);
|
Windows.Win32.PInvoke.SetEvent(new HANDLE(mainThreadContinueEvent));
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleServiceInitFailure(Task t)
|
void HandleServiceInitFailure(Task t)
|
||||||
|
|
@ -116,9 +117,9 @@ internal sealed class Dalamud : IServiceType
|
||||||
HandleServiceInitFailure(t);
|
HandleServiceInitFailure(t);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.DefaultExceptionFilter = NativeFunctions.SetUnhandledExceptionFilter(nint.Zero);
|
this.DefaultExceptionFilter = SetExceptionHandler(nint.Zero);
|
||||||
NativeFunctions.SetUnhandledExceptionFilter(this.DefaultExceptionFilter);
|
SetExceptionHandler(this.DefaultExceptionFilter);
|
||||||
Log.Debug($"SE default exception filter at {this.DefaultExceptionFilter.ToInt64():X}");
|
Log.Debug($"SE default exception filter at {new IntPtr(this.DefaultExceptionFilter):X}");
|
||||||
|
|
||||||
var debugSig = "40 55 53 57 48 8D AC 24 70 AD FF FF";
|
var debugSig = "40 55 53 57 48 8D AC 24 70 AD FF FF";
|
||||||
this.DebugExceptionFilter = Service<TargetSigScanner>.Get().ScanText(debugSig);
|
this.DebugExceptionFilter = Service<TargetSigScanner>.Get().ScanText(debugSig);
|
||||||
|
|
@ -189,27 +190,29 @@ internal sealed class Dalamud : IServiceType
|
||||||
/// Replace the current exception handler with the default one.
|
/// Replace the current exception handler with the default one.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal void UseDefaultExceptionHandler() =>
|
internal void UseDefaultExceptionHandler() =>
|
||||||
this.SetExceptionHandler(this.DefaultExceptionFilter);
|
SetExceptionHandler(this.DefaultExceptionFilter);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Replace the current exception handler with a debug one.
|
/// Replace the current exception handler with a debug one.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal void UseDebugExceptionHandler() =>
|
internal void UseDebugExceptionHandler() =>
|
||||||
this.SetExceptionHandler(this.DebugExceptionFilter);
|
SetExceptionHandler(this.DebugExceptionFilter);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disable the current exception handler.
|
/// Disable the current exception handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal void UseNoExceptionHandler() =>
|
internal void UseNoExceptionHandler() =>
|
||||||
this.SetExceptionHandler(nint.Zero);
|
SetExceptionHandler(nint.Zero);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Helper function to set the exception handler.
|
/// Helper function to set the exception handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void SetExceptionHandler(nint newFilter)
|
private static nint SetExceptionHandler(nint newFilter)
|
||||||
{
|
{
|
||||||
var oldFilter = NativeFunctions.SetUnhandledExceptionFilter(newFilter);
|
var oldFilter =
|
||||||
Log.Debug("Set ExceptionFilter to {0}, old: {1}", newFilter, oldFilter);
|
Windows.Win32.PInvoke.SetUnhandledExceptionFilter((delegate* unmanaged[Stdcall]<global::Windows.Win32.System.Diagnostics.Debug.EXCEPTION_POINTERS*, int>)newFilter);
|
||||||
|
Log.Debug("Set ExceptionFilter to {0}, old: {1}", newFilter, (nint)oldFilter);
|
||||||
|
return (nint)oldFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetupClientStructsResolver(DirectoryInfo cacheDir)
|
private void SetupClientStructsResolver(DirectoryInfo cacheDir)
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,10 @@
|
||||||
<Deterministic>true</Deterministic>
|
<Deterministic>true</Deterministic>
|
||||||
<Nullable>annotations</Nullable>
|
<Nullable>annotations</Nullable>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
|
||||||
|
<!-- Enable when cswin32 properly supports implementing COM interfaces and we can
|
||||||
|
make IDropTarget work -->
|
||||||
|
<!-- <DisableRuntimeMarshalling>true</DisableRuntimeMarshalling> -->
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Label="Configuration">
|
<PropertyGroup Label="Configuration">
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@ using Serilog.Events;
|
||||||
using Windows.Win32.Foundation;
|
using Windows.Win32.Foundation;
|
||||||
using Windows.Win32.UI.WindowsAndMessaging;
|
using Windows.Win32.UI.WindowsAndMessaging;
|
||||||
|
|
||||||
using static Dalamud.NativeFunctions;
|
|
||||||
|
|
||||||
namespace Dalamud;
|
namespace Dalamud;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -264,10 +262,12 @@ public sealed class EntryPoint
|
||||||
var symbolPath = Path.Combine(info.AssetDirectory, "UIRes", "pdb");
|
var symbolPath = Path.Combine(info.AssetDirectory, "UIRes", "pdb");
|
||||||
var searchPath = $".;{symbolPath}";
|
var searchPath = $".;{symbolPath}";
|
||||||
|
|
||||||
// Remove any existing Symbol Handler and Init a new one with our search path added
|
var currentProcess = Windows.Win32.PInvoke.GetCurrentProcess_SafeHandle();
|
||||||
SymCleanup(GetCurrentProcess());
|
|
||||||
|
|
||||||
if (!SymInitialize(GetCurrentProcess(), searchPath, true))
|
// Remove any existing Symbol Handler and Init a new one with our search path added
|
||||||
|
Windows.Win32.PInvoke.SymCleanup(currentProcess);
|
||||||
|
|
||||||
|
if (!Windows.Win32.PInvoke.SymInitialize(currentProcess, searchPath, true))
|
||||||
throw new Win32Exception();
|
throw new Win32Exception();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
|
||||||
|
|
@ -55,4 +55,37 @@ internal sealed class WinSockHandlers : IInternalDisposableService
|
||||||
|
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Native ws2_32 functions.
|
||||||
|
/// </summary>
|
||||||
|
private static class NativeFunctions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// See https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-setsockopt.
|
||||||
|
/// The setsockopt function sets a socket option.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="socket">
|
||||||
|
/// A descriptor that identifies a socket.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="level">
|
||||||
|
/// The level at which the option is defined (for example, SOL_SOCKET).
|
||||||
|
/// </param>
|
||||||
|
/// <param name="optName">
|
||||||
|
/// The socket option for which the value is to be set (for example, SO_BROADCAST). The optname parameter must be a
|
||||||
|
/// socket option defined within the specified level, or behavior is undefined.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="optVal">
|
||||||
|
/// A pointer to the buffer in which the value for the requested option is specified.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="optLen">
|
||||||
|
/// The size, in bytes, of the buffer pointed to by the optval parameter.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>
|
||||||
|
/// If no error occurs, setsockopt returns zero. Otherwise, a value of SOCKET_ERROR is returned, and a specific error
|
||||||
|
/// code can be retrieved by calling WSAGetLastError.
|
||||||
|
/// </returns>
|
||||||
|
[DllImport("ws2_32.dll", CallingConvention = CallingConvention.Winapi, EntryPoint = "setsockopt")]
|
||||||
|
public static extern int SetSockOpt(IntPtr socket, SocketOptionLevel level, SocketOptionName optName, ref IntPtr optVal, int optLen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -200,11 +200,11 @@ public abstract class Hook<T> : IDalamudHook where T : Delegate
|
||||||
if (EnvironmentConfiguration.DalamudForceMinHook)
|
if (EnvironmentConfiguration.DalamudForceMinHook)
|
||||||
useMinHook = true;
|
useMinHook = true;
|
||||||
|
|
||||||
var moduleHandle = NativeFunctions.GetModuleHandleW(moduleName);
|
using var moduleHandle = Windows.Win32.PInvoke.GetModuleHandle(moduleName);
|
||||||
if (moduleHandle == IntPtr.Zero)
|
if (moduleHandle.IsInvalid)
|
||||||
throw new Exception($"Could not get a handle to module {moduleName}");
|
throw new Exception($"Could not get a handle to module {moduleName}");
|
||||||
|
|
||||||
var procAddress = NativeFunctions.GetProcAddress(moduleHandle, exportName);
|
var procAddress = (nint)Windows.Win32.PInvoke.GetProcAddress(moduleHandle, exportName);
|
||||||
if (procAddress == IntPtr.Zero)
|
if (procAddress == IntPtr.Zero)
|
||||||
throw new Exception($"Could not get the address of {moduleName}::{exportName}");
|
throw new Exception($"Could not get the address of {moduleName}::{exportName}");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,14 +29,14 @@ internal class AssertHandler : IDisposable
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="AssertHandler"/> class.
|
/// Initializes a new instance of the <see cref="AssertHandler"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public AssertHandler()
|
public unsafe AssertHandler()
|
||||||
{
|
{
|
||||||
this.callback = (expr, file, line) => this.OnImGuiAssert(expr, file, line);
|
this.callback = this.OnImGuiAssert;
|
||||||
}
|
}
|
||||||
|
|
||||||
private delegate void AssertCallbackDelegate(
|
private unsafe delegate void AssertCallbackDelegate(
|
||||||
[MarshalAs(UnmanagedType.LPStr)] string expr,
|
void* expr,
|
||||||
[MarshalAs(UnmanagedType.LPStr)] string file,
|
void* file,
|
||||||
int line);
|
int line);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -53,15 +53,15 @@ internal class AssertHandler : IDisposable
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register the cimgui assert handler with the native library.
|
/// Register the cimgui assert handler with the native library.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Setup()
|
public unsafe void Setup()
|
||||||
{
|
{
|
||||||
CustomNativeFunctions.igCustom_SetAssertCallback(this.callback);
|
CustomNativeFunctions.igCustom_SetAssertCallback(Marshal.GetFunctionPointerForDelegate(this.callback).ToPointer());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unregister the cimgui assert handler with the native library.
|
/// Unregister the cimgui assert handler with the native library.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Shutdown()
|
public unsafe void Shutdown()
|
||||||
{
|
{
|
||||||
CustomNativeFunctions.igCustom_SetAssertCallback(null);
|
CustomNativeFunctions.igCustom_SetAssertCallback(null);
|
||||||
}
|
}
|
||||||
|
|
@ -72,8 +72,19 @@ internal class AssertHandler : IDisposable
|
||||||
this.Shutdown();
|
this.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnImGuiAssert(string expr, string file, int line)
|
private unsafe void OnImGuiAssert(void* pExpr, void* pFile, int line)
|
||||||
{
|
{
|
||||||
|
var expr = Marshal.PtrToStringAnsi(new IntPtr(pExpr));
|
||||||
|
var file = Marshal.PtrToStringAnsi(new IntPtr(pFile));
|
||||||
|
if (expr == null || file == null)
|
||||||
|
{
|
||||||
|
Log.Warning("ImGui assertion failed: {Expr} at {File}:{Line} (failed to parse)",
|
||||||
|
expr,
|
||||||
|
file,
|
||||||
|
line);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var key = $"{file}:{line}";
|
var key = $"{file}:{line}";
|
||||||
if (this.ignoredAsserts.Contains(key))
|
if (this.ignoredAsserts.Contains(key))
|
||||||
return;
|
return;
|
||||||
|
|
@ -218,11 +229,11 @@ internal class AssertHandler : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class CustomNativeFunctions
|
private static unsafe class CustomNativeFunctions
|
||||||
{
|
{
|
||||||
[DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)]
|
||||||
#pragma warning disable SA1300
|
#pragma warning disable SA1300
|
||||||
public static extern void igCustom_SetAssertCallback(AssertCallbackDelegate? callback);
|
public static extern void igCustom_SetAssertCallback(void* cb);
|
||||||
#pragma warning restore SA1300
|
#pragma warning restore SA1300
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,8 @@ using TerraFX.Interop.Windows;
|
||||||
|
|
||||||
using static TerraFX.Interop.Windows.Windows;
|
using static TerraFX.Interop.Windows.Windows;
|
||||||
|
|
||||||
|
using DWMWINDOWATTRIBUTE = Windows.Win32.Graphics.Dwm.DWMWINDOWATTRIBUTE;
|
||||||
|
|
||||||
// general dev notes, here because it's easiest
|
// general dev notes, here because it's easiest
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -487,12 +489,13 @@ internal partial class InterfaceManager : IInternalDisposableService
|
||||||
{
|
{
|
||||||
if (this.GameWindowHandle == 0)
|
if (this.GameWindowHandle == 0)
|
||||||
throw new InvalidOperationException("Game window is not yet ready.");
|
throw new InvalidOperationException("Game window is not yet ready.");
|
||||||
|
|
||||||
var value = enabled ? 1u : 0u;
|
var value = enabled ? 1u : 0u;
|
||||||
DwmSetWindowAttribute(
|
global::Windows.Win32.PInvoke.DwmSetWindowAttribute(
|
||||||
this.GameWindowHandle,
|
new(this.GameWindowHandle.Value),
|
||||||
(uint)DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE,
|
DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE,
|
||||||
&value,
|
&value,
|
||||||
sizeof(int)).ThrowOnError();
|
sizeof(uint)).ThrowOnFailure();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InterfaceManager WhenFontsReady()
|
private static InterfaceManager WhenFontsReady()
|
||||||
|
|
|
||||||
|
|
@ -70,12 +70,12 @@ public interface IFontAtlasBuildToolkitPreBuild : IFontAtlasBuildToolkit
|
||||||
/// Adds a font from memory region allocated using <see cref="ImGuiHelpers.AllocateMemory"/>.<br />
|
/// Adds a font from memory region allocated using <see cref="ImGuiHelpers.AllocateMemory"/>.<br />
|
||||||
/// <b>It WILL crash if you try to use a memory pointer allocated in some other way.</b><br />
|
/// <b>It WILL crash if you try to use a memory pointer allocated in some other way.</b><br />
|
||||||
/// <b>
|
/// <b>
|
||||||
/// Do NOT call <see cref="ImGuiNative.igMemFree"/> on the <paramref name="dataPointer"/> once this function has
|
/// Do NOT call <see cref="ImGui.MemFree"/> on the <paramref name="dataPointer"/> once this function has
|
||||||
/// been called, unless <paramref name="freeOnException"/> is set and the function has thrown an error.
|
/// been called, unless <paramref name="freeOnException"/> is set and the function has thrown an error.
|
||||||
/// </b>
|
/// </b>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dataPointer">Memory address for the data allocated using <see cref="ImGuiHelpers.AllocateMemory"/>.</param>
|
/// <param name="dataPointer">Memory address for the data allocated using <see cref="ImGuiHelpers.AllocateMemory"/>.</param>
|
||||||
/// <param name="dataSize">The size of the font file..</param>
|
/// <param name="dataSize">The size of the font file.</param>
|
||||||
/// <param name="fontConfig">The font config.</param>
|
/// <param name="fontConfig">The font config.</param>
|
||||||
/// <param name="freeOnException">Free <paramref name="dataPointer"/> if an exception happens.</param>
|
/// <param name="freeOnException">Free <paramref name="dataPointer"/> if an exception happens.</param>
|
||||||
/// <param name="debugTag">A debug tag.</param>
|
/// <param name="debugTag">A debug tag.</param>
|
||||||
|
|
@ -155,7 +155,7 @@ public interface IFontAtlasBuildToolkitPreBuild : IFontAtlasBuildToolkit
|
||||||
/// used as the font size. Specify -1 to use the default font size.
|
/// used as the font size. Specify -1 to use the default font size.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="glyphRanges">The glyph ranges. Use <see cref="FontAtlasBuildToolkitUtilities"/>.ToGlyphRange to build.</param>
|
/// <param name="glyphRanges">The glyph ranges. Use <see cref="FontAtlasBuildToolkitUtilities"/>.ToGlyphRange to build.</param>
|
||||||
/// <returns>A font returned from <see cref="ImFontAtlasPtr.AddFont"/>.</returns>
|
/// <returns>A font returned from <see cref="ImFontAtlasPtr.AddFont(ImFontConfig*)"/>.</returns>
|
||||||
ImFontPtr AddDalamudDefaultFont(float sizePx, ushort[]? glyphRanges = null);
|
ImFontPtr AddDalamudDefaultFont(float sizePx, ushort[]? glyphRanges = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -56,9 +56,9 @@ public interface IFontHandle : IDisposable
|
||||||
/// You may not access the font once you dispose this object.
|
/// You may not access the font once you dispose this object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A disposable object that will pop the font on dispose.</returns>
|
/// <returns>A disposable object that will pop the font on dispose.</returns>
|
||||||
/// <exception cref="InvalidOperationException">If called outside of the main thread.</exception>
|
/// <exception cref="InvalidOperationException">If called outside the main thread.</exception>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// <para>This function uses <see cref="ImGui.PushFont"/>, and may do extra things.
|
/// <para>This function uses <see cref="ImGui.PushFont(ImFontPtr)"/>, and may do extra things.
|
||||||
/// Use <see cref="IDisposable.Dispose"/> or <see cref="Pop"/> to undo this operation.
|
/// Use <see cref="IDisposable.Dispose"/> or <see cref="Pop"/> to undo this operation.
|
||||||
/// Do not use <see cref="ImGui.PopFont"/>.</para>
|
/// Do not use <see cref="ImGui.PopFont"/>.</para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,9 @@ using Dalamud.Utility;
|
||||||
using FFXIVClientStructs.FFXIV.Client.System.Memory;
|
using FFXIVClientStructs.FFXIV.Client.System.Memory;
|
||||||
using FFXIVClientStructs.FFXIV.Client.System.String;
|
using FFXIVClientStructs.FFXIV.Client.System.String;
|
||||||
using Microsoft.Extensions.ObjectPool;
|
using Microsoft.Extensions.ObjectPool;
|
||||||
|
using Windows.Win32.Foundation;
|
||||||
using Windows.Win32.System.Memory;
|
using Windows.Win32.System.Memory;
|
||||||
|
|
||||||
using static Dalamud.NativeFunctions;
|
|
||||||
|
|
||||||
using LPayloadType = Lumina.Text.Payloads.PayloadType;
|
using LPayloadType = Lumina.Text.Payloads.PayloadType;
|
||||||
using LSeString = Lumina.Text.SeString;
|
using LSeString = Lumina.Text.SeString;
|
||||||
|
|
||||||
|
|
@ -28,6 +27,8 @@ public static unsafe class MemoryHelper
|
||||||
private static readonly ObjectPool<StringBuilder> StringBuilderPool =
|
private static readonly ObjectPool<StringBuilder> StringBuilderPool =
|
||||||
ObjectPool.Create(new StringBuilderPooledObjectPolicy());
|
ObjectPool.Create(new StringBuilderPooledObjectPolicy());
|
||||||
|
|
||||||
|
private static readonly HANDLE ThisProcessPseudoHandle = new(unchecked((nint)0xFFFFFFFF));
|
||||||
|
|
||||||
#region Cast
|
#region Cast
|
||||||
|
|
||||||
/// <summary>Casts the given memory address as the reference to the live object.</summary>
|
/// <summary>Casts the given memory address as the reference to the live object.</summary>
|
||||||
|
|
@ -863,14 +864,22 @@ public static unsafe class MemoryHelper
|
||||||
unchecked
|
unchecked
|
||||||
{
|
{
|
||||||
var length = value.Length;
|
var length = value.Length;
|
||||||
var result = NativeFunctions.ReadProcessMemory((nint)0xFFFFFFFF, memoryAddress, value, length, out _);
|
fixed (byte* pVal = value)
|
||||||
|
{
|
||||||
|
var result = Windows.Win32.PInvoke.ReadProcessMemory(
|
||||||
|
ThisProcessPseudoHandle,
|
||||||
|
memoryAddress.ToPointer(),
|
||||||
|
pVal,
|
||||||
|
(nuint)length,
|
||||||
|
null);
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
throw new MemoryReadException($"Unable to read memory at {Util.DescribeAddress(memoryAddress)} of length {length} (result={result})");
|
throw new MemoryReadException($"Unable to read memory at {Util.DescribeAddress(memoryAddress)} of length {length} (result={result})");
|
||||||
|
|
||||||
var last = Marshal.GetLastWin32Error();
|
var last = Marshal.GetLastWin32Error();
|
||||||
if (last > 0)
|
if (last > 0)
|
||||||
throw new MemoryReadException($"Unable to read memory at {Util.DescribeAddress(memoryAddress)} of length {length} (error={last})");
|
throw new MemoryReadException($"Unable to read memory at {Util.DescribeAddress(memoryAddress)} of length {length} (error={last})");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -885,14 +894,22 @@ public static unsafe class MemoryHelper
|
||||||
unchecked
|
unchecked
|
||||||
{
|
{
|
||||||
var length = data.Length;
|
var length = data.Length;
|
||||||
var result = NativeFunctions.WriteProcessMemory((nint)0xFFFFFFFF, memoryAddress, data, length, out _);
|
fixed (byte* pData = data)
|
||||||
|
{
|
||||||
|
var result = Windows.Win32.PInvoke.WriteProcessMemory(
|
||||||
|
ThisProcessPseudoHandle,
|
||||||
|
memoryAddress.ToPointer(),
|
||||||
|
pData,
|
||||||
|
(nuint)length,
|
||||||
|
null);
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
throw new MemoryWriteException($"Unable to write memory at {Util.DescribeAddress(memoryAddress)} of length {length} (result={result})");
|
throw new MemoryWriteException($"Unable to write memory at {Util.DescribeAddress(memoryAddress)} of length {length} (result={result})");
|
||||||
|
|
||||||
var last = Marshal.GetLastWin32Error();
|
var last = Marshal.GetLastWin32Error();
|
||||||
if (last > 0)
|
if (last > 0)
|
||||||
throw new MemoryWriteException($"Unable to write memory at {Util.DescribeAddress(memoryAddress)} of length {length} (error={last})");
|
throw new MemoryWriteException($"Unable to write memory at {Util.DescribeAddress(memoryAddress)} of length {length} (error={last})");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -12,6 +12,11 @@ HWND_TOPMOST
|
||||||
HWND_NOTOPMOST
|
HWND_NOTOPMOST
|
||||||
SET_WINDOW_POS_FLAGS
|
SET_WINDOW_POS_FLAGS
|
||||||
|
|
||||||
|
SetEvent
|
||||||
|
|
||||||
|
SymInitialize
|
||||||
|
SymCleanup
|
||||||
|
|
||||||
OpenClipboard
|
OpenClipboard
|
||||||
SetClipboardData
|
SetClipboardData
|
||||||
CloseClipboard
|
CloseClipboard
|
||||||
|
|
@ -22,14 +27,34 @@ GlobalLock
|
||||||
GlobalUnlock
|
GlobalUnlock
|
||||||
GLOBAL_ALLOC_FLAGS
|
GLOBAL_ALLOC_FLAGS
|
||||||
|
|
||||||
MEM_ALLOCATION_TYPE
|
|
||||||
VirtualAlloc
|
VirtualAlloc
|
||||||
VirtualProtect
|
VirtualProtect
|
||||||
VirtualFree
|
VirtualFree
|
||||||
|
VirtualQuery
|
||||||
|
|
||||||
|
SetUnhandledExceptionFilter
|
||||||
|
|
||||||
ReadProcessMemory
|
ReadProcessMemory
|
||||||
WriteProcessMemory
|
WriteProcessMemory
|
||||||
|
|
||||||
|
FlashWindowEx
|
||||||
|
|
||||||
|
GetProcAddress
|
||||||
|
GetModuleHandle
|
||||||
|
GetForegroundWindow
|
||||||
GetCurrentProcess
|
GetCurrentProcess
|
||||||
|
GetWindowThreadProcessId
|
||||||
|
|
||||||
MessageBoxW
|
MessageBoxW
|
||||||
|
|
||||||
|
SystemParametersInfo
|
||||||
|
|
||||||
|
SystemParametersInfo
|
||||||
|
|
||||||
|
DwmSetWindowAttribute
|
||||||
|
|
||||||
|
setsockopt
|
||||||
|
|
||||||
|
RegisterDragDrop
|
||||||
|
RevokeDragDrop
|
||||||
|
DragQueryFileW
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,9 @@ using Windows.Win32.System.Memory;
|
||||||
using Windows.Win32.System.Ole;
|
using Windows.Win32.System.Ole;
|
||||||
using Windows.Win32.UI.WindowsAndMessaging;
|
using Windows.Win32.UI.WindowsAndMessaging;
|
||||||
|
|
||||||
using static TerraFX.Interop.Windows.Windows;
|
using FLASHWINFO = Windows.Win32.UI.WindowsAndMessaging.FLASHWINFO;
|
||||||
|
|
||||||
using HWND = Windows.Win32.Foundation.HWND;
|
using HWND = Windows.Win32.Foundation.HWND;
|
||||||
|
using MEMORY_BASIC_INFORMATION = Windows.Win32.System.Memory.MEMORY_BASIC_INFORMATION;
|
||||||
using Win32_PInvoke = Windows.Win32.PInvoke;
|
using Win32_PInvoke = Windows.Win32.PInvoke;
|
||||||
|
|
||||||
namespace Dalamud.Utility;
|
namespace Dalamud.Utility;
|
||||||
|
|
@ -202,14 +202,14 @@ public static class Util
|
||||||
}
|
}
|
||||||
|
|
||||||
MEMORY_BASIC_INFORMATION mbi;
|
MEMORY_BASIC_INFORMATION mbi;
|
||||||
if (VirtualQuery((void*)p, &mbi, (nuint)sizeof(MEMORY_BASIC_INFORMATION)) == 0)
|
if (Win32_PInvoke.VirtualQuery((void*)p, &mbi, (nuint)sizeof(MEMORY_BASIC_INFORMATION)) == 0)
|
||||||
return $"0x{p:X}(???)";
|
return $"0x{p:X}(???)";
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
sb.Append($"0x{p:X}(");
|
sb.Append($"0x{p:X}(");
|
||||||
for (int i = 0, c = 0; i < PageProtectionFlagNames.Length; i++)
|
for (int i = 0, c = 0; i < PageProtectionFlagNames.Length; i++)
|
||||||
{
|
{
|
||||||
if ((mbi.Protect & (1 << i)) == 0)
|
if (((uint)mbi.Protect & (1 << i)) == 0)
|
||||||
continue;
|
continue;
|
||||||
if (c++ != 0)
|
if (c++ != 0)
|
||||||
sb.Append(" | ");
|
sb.Append(" | ");
|
||||||
|
|
@ -577,25 +577,44 @@ public static class Util
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if the current application has focus, false otherwise.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// If the current application is focused.
|
||||||
|
/// </returns>
|
||||||
|
public static unsafe bool ApplicationIsActivated()
|
||||||
|
{
|
||||||
|
var activatedHandle = Win32_PInvoke.GetForegroundWindow();
|
||||||
|
if (activatedHandle == IntPtr.Zero)
|
||||||
|
return false; // No window is currently activated
|
||||||
|
|
||||||
|
uint pid;
|
||||||
|
_ = Win32_PInvoke.GetWindowThreadProcessId(activatedHandle, &pid);
|
||||||
|
if (Marshal.GetLastWin32Error() != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return pid == Environment.ProcessId;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Request that Windows flash the game window to grab the user's attention.
|
/// Request that Windows flash the game window to grab the user's attention.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="flashIfOpen">Attempt to flash even if the game is currently focused.</param>
|
/// <param name="flashIfOpen">Attempt to flash even if the game is currently focused.</param>
|
||||||
public static void FlashWindow(bool flashIfOpen = false)
|
public static unsafe void FlashWindow(bool flashIfOpen = false)
|
||||||
{
|
{
|
||||||
if (NativeFunctions.ApplicationIsActivated() && !flashIfOpen)
|
if (ApplicationIsActivated() && !flashIfOpen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var flashInfo = new NativeFunctions.FlashWindowInfo
|
var flashInfo = new FLASHWINFO
|
||||||
{
|
{
|
||||||
Size = (uint)Marshal.SizeOf<NativeFunctions.FlashWindowInfo>(),
|
cbSize = (uint)sizeof(FLASHWINFO),
|
||||||
Count = uint.MaxValue,
|
uCount = uint.MaxValue,
|
||||||
Timeout = 0,
|
dwTimeout = 0,
|
||||||
Flags = NativeFunctions.FlashWindow.All | NativeFunctions.FlashWindow.TimerNoFG,
|
dwFlags = FLASHWINFO_FLAGS.FLASHW_ALL | FLASHWINFO_FLAGS.FLASHW_TIMERNOFG,
|
||||||
Hwnd = Process.GetCurrentProcess().MainWindowHandle,
|
hwnd = new HWND(Process.GetCurrentProcess().MainWindowHandle.ToPointer()),
|
||||||
};
|
};
|
||||||
|
Win32_PInvoke.FlashWindowEx(flashInfo);
|
||||||
NativeFunctions.FlashWindowEx(ref flashInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue