using System;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using WhiteMagic.Hooking;
namespace WhiteMagic.Execution;
///
/// A crash-safe work queue drained on the target's own thread via a detour on a
/// per-frame function. Callers queue work and receive the result (or exception)
/// on their own thread through a completion handle.
///
///
/// The pump assumes the frame function is parameterless and returns an .
/// This matches common per-frame functions such as D3D9 EndScene.
///
public sealed class MainThreadPump : IDisposable
{
private readonly DetourManager _detours;
private readonly IntPtr _frameAddress;
private readonly ConcurrentQueue _queue = new();
private readonly object _gate = new();
private Detour? _detour;
private bool _installed;
private bool _disposed;
///
/// Creates a pump that will hook the frame function at .
///
public MainThreadPump(DetourManager detours, IntPtr frameAddress)
{
_detours = detours;
_frameAddress = frameAddress;
}
/// Returns after the frame hook has been applied.
public bool IsInstalled => _installed;
/// Installs the frame-function detour.
public void Install()
{
if (_installed)
return;
_detour = _detours.Create("MainThreadPump", _frameAddress, (FrameDelegate)PumpHook);
_detour.Apply();
_installed = true;
}
///
/// Queues work to run on the hooked thread and blocks until it completes.
///
public TResult Execute(Func work)
{
var tcs = new TaskCompletionSource