Overview
IGameInteropProvider is responsible for the creation of hooks. It allows plugins to hook game functions using various methods including signatures, symbols, and addresses.
Namespace
Enums
HookBackend
public enum HookBackend
{
Automatic, // Choose the best backend automatically
Reloaded, // Use Reloaded hooks
MinHook // Use MinHook (use only after consulting Dalamud team)
}
Methods
InitializeFromAttributes
public void InitializeFromAttributes(object self);
Initializes Hook<T> members decorated with the SignatureAttribute. Also initializes any delegate members and fills out any IntPtr members decorated with the SignatureAttribute with the resolved address.
HookFromFunctionPointerVariable
public Hook<T> HookFromFunctionPointerVariable<T>(nint address, T detour) where T : Delegate;
Creates a hook by replacing the original address with an address pointing to a newly created jump to the detour.
A memory address to install a hook
Callback function. Delegate must have the same original function prototype
The hook with the supplied parameters
HookFromImport
public Hook<T> HookFromImport<T>(
ProcessModule? module,
string moduleName,
string functionName,
uint hintOrOrdinal,
T detour) where T : Delegate;
Creates a hook by rewriting import table address.
Module to check for. Current process’ main module if null
Name of the DLL, including the extension
Decorated name of the function
Hint or ordinal. 0 to unspecify
The hook with the supplied parameters
HookFromSymbol
public Hook<T> HookFromSymbol<T>(
string moduleName,
string exportName,
T detour,
HookBackend backend = HookBackend.Automatic) where T : Delegate;
Creates a hook using GetProcAddress to infer the hooking address. The hook is not activated until Enable() is called.
A name of the module currently loaded in memory (e.g., ws2_32.dll)
A name of the exported function (e.g., send)
Hooking library to use (default: Automatic)
The hook with the supplied parameters
HookFromAddress
public Hook<T> HookFromAddress<T>(
nint procAddress,
T detour,
HookBackend backend = HookBackend.Automatic) where T : Delegate;
public Hook<T> HookFromAddress<T>(
nuint procAddress,
T detour,
HookBackend backend = HookBackend.Automatic) where T : Delegate;
public unsafe Hook<T> HookFromAddress<T>(
void* procAddress,
T detour,
HookBackend backend = HookBackend.Automatic) where T : Delegate;
Creates a hook from a memory address. The hook is not activated until Enable() is called.
procAddress
nint | nuint | void*
required
A memory address to install a hook
Hooking library to use (default: Automatic)
The hook with the supplied parameters
HookFromSignature
public Hook<T> HookFromSignature<T>(
string signature,
T detour,
HookBackend backend = HookBackend.Automatic) where T : Delegate;
Creates a hook from a signature into the Dalamud target module.
Signature of function to hook
Hooking library to use (default: Automatic)
The hook with the supplied parameters
Example Usage
public class MyPlugin : IDalamudPlugin
{
private readonly IGameInteropProvider interop;
private Hook<MyDelegate>? myHook;
private delegate nint MyDelegate(nint a, nint b);
public MyPlugin(IGameInteropProvider interop)
{
this.interop = interop;
// Create a hook from a signature
this.myHook = this.interop.HookFromSignature<MyDelegate>(
"E8 ?? ?? ?? ?? 48 8B D8 48 85 C0",
MyDetour);
// Enable the hook
this.myHook.Enable();
}
private nint MyDetour(nint a, nint b)
{
// Your detour code here
Log.Information($"Hook called with: {a:X}, {b:X}");
// Call the original function
var result = this.myHook!.Original(a, b);
return result;
}
public void Dispose()
{
this.myHook?.Dispose();
}
}
Advanced Usage
Using SignatureAttribute
public class MyHooks
{
private delegate nint MyFunctionDelegate(nint a, nint b);
[Signature("E8 ?? ?? ?? ?? 48 8B D8")]
private Hook<MyFunctionDelegate>? myHook = null;
public MyHooks(IGameInteropProvider interop)
{
// Initialize all hooks from attributes
interop.InitializeFromAttributes(this);
// Set up the detour
if (this.myHook != null)
{
this.myHook.Enable();
}
}
private nint MyDetour(nint a, nint b)
{
return this.myHook!.Original(a, b);
}
}
Hook from Known Address
public void CreateAddressHook(nint address)
{
var hook = this.interop.HookFromAddress<MyDelegate>(
address,
MyDetour);
hook.Enable();
}
Hook External Function
private delegate int SendDelegate(
IntPtr socket,
IntPtr buffer,
int length,
int flags);
public void HookWinsockSend()
{
var hook = this.interop.HookFromSymbol<SendDelegate>(
"ws2_32.dll",
"send",
SendDetour);
hook.Enable();
}
private int SendDetour(
IntPtr socket,
IntPtr buffer,
int length,
int flags)
{
Log.Information($"Sending {length} bytes");
return hook.Original(socket, buffer, length, flags);
}
Conditional Hook Execution
private nint MyDetour(nint a, nint b)
{
// Add custom logic
if (ShouldModifyBehavior())
{
// Return custom value
return customValue;
}
// Call original
return this.myHook!.Original(a, b);
}
Hook Lifecycle
- Create - Create the hook using one of the
HookFrom* methods
- Enable - Call
Enable() on the hook to activate it
- Use - Your detour function will be called instead of the original
- Disable - Call
Disable() to temporarily deactivate
- Dispose - Call
Dispose() to remove the hook permanently
- Always dispose hooks in your plugin’s
Dispose() method
- Call
Enable() after creating a hook to activate it
- Use
Original to call the original function from your detour
- The delegate type must match the original function’s signature exactly
- Use
HookBackend.Automatic unless you have specific requirements
- Only use
MinHook backend after consulting with the Dalamud team
- Hooks can be temporarily disabled with
Disable() and re-enabled with Enable()
- SignatureAttribute allows for cleaner hook initialization
- Be careful with hook detours - errors can crash the game