using System.Threading.Tasks;
using WhiteMagic.Assembly;
using WhiteMagic.Execution;
namespace WhiteMagic;
///
/// An exported function resolved in the target process, obtained via
/// magic["module"]["function"]. Executes through one of the session's execution
/// strategies.
///
///
/// The default path uses the always-available
/// (CreateRemoteThread), which is safe for
/// thread-agnostic exports. For a call that touches single-threaded target state, obtain
/// the and route it through a , or use
/// when running in-process.
///
public sealed class RemoteFunction
{
private readonly Magic _magic;
/// The export name this function was resolved from.
public string Name { get; }
/// The absolute address of the function in the target process.
public IntPtr Address { get; }
internal RemoteFunction(Magic magic, string name, IntPtr address)
{
_magic = magic;
Name = name;
Address = address;
}
///
/// Calls the function via a remote thread and returns its result cast to
/// .
///
/// The calling convention (ignored on x64 targets).
/// Arguments to pass; primitives, pointers, enums, strings and
/// structs are supported.
public T Execute(CallConvention convention, params object?[] args)
{
return _magic.RemoteThread.Execute(Address, convention, args);
}
/// Asynchronous variant of .
public Task ExecuteAsync(CallConvention convention, params object?[] args)
{
return _magic.RemoteThread.ExecuteAsync(Address, convention, args);
}
///
/// Creates a managed delegate bound to this function for the in-process scenario.
///
/// The session is not in-process. The
/// resolved lives in the target process; a delegate to it would
/// access-violate when invoked from the host, so this is rejected for external sessions.
/// Use (remote thread) for external targets.
public TDelegate CreateDelegate() where TDelegate : Delegate
{
if (_magic.Memory is not InProcessReader)
{
throw new InvalidOperationException(
"CreateDelegate is only valid for an in-process session (Magic.OpenInProcess). " +
"The function address is not mapped into the host process for an external target; " +
"use Execute to call it via a remote thread.");
}
return new InProcessInvoker(_magic.Memory).CreateFunction(Address);
}
}