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); } }