Hooking Normal Methods
To start hooking, we need a target method we want to hook. So, given the target type and method we want to hook:
namespace Lib;
public class LibraryClass{ public bool IsTrue { get; set; }
// We want to hook this. public int TakeAndReturnInt(int number) { return number; }
public void PrintFoo() { Console.WriteLine("Foo"); }}
Let’s generate hooks for the type:
// Tell MonoDetour's HookGen to generate hooks// for the target type.[MonoDetourTargets(typeof(LibraryClass))]public class LibraryClassHooks{ // ...}
Basic Hook
Now we can get to hooking. A simple hook we can do is:
[MonoDetourTargets(typeof(LibraryClass))]public class LibraryClassHooks{ // MonoDetourManager.InvokeHookInitializers will // call methods marked with this attribute in types // which have the MonoDetourTargetsAttribute. [MonoDetourHookInit] static void Init() { // Add a prefix hook which runs at the start of the target method. On.Lib.LibraryClass.TakeAndReturnInt.Prefix(Prefix_TakeAndReturnInt); }
static void Prefix_TakeAndReturnInt(LibraryClass self, ref int number){ // As soon as LibraryClass.TakeAndReturnInt runs, // call its method PrintFoo with its instance. self.PrintFoo();
// Increment the 'number' parameter by one. number += 1; }}
We can either call our LibraryClassHooks.Init
method manually, or use the following to call all methods marked with MonoDetourHookInit
attribute that are in types marked with the MonoDetourTargets
attribute:
internal static void InitAllHooks(){ // Searches for types with MonoDetourTargets to go through and // finds methods in them marked with MonoDetourHookInit and calls them. DefaultMonoDetourManager.Instance.InvokeHookInitializers();}
We can also add a hook that runs at the end of a method:
// Add a postfix hook which runs at the end of the target method.On.Lib.LibraryClass.TakeAndReturnInt.Postfix(Postfix_TakeAndReturnInt);// ...static void Postfix_TakeAndReturnInt(LibraryClass self, ref int number, ref int returnValue){ Console.WriteLine("Hello from postfix hook!");}
Changing Return Value
To change a return value, your hook must be a Postfix. We can use the returnValue
parameter for accessing and setting the return value.
On.Lib.LibraryClass.TakeAndReturnInt.Postfix(Postfix_TakeAndReturnInt);
static void Postfix_TakeAndReturnInt(LibraryClass self, ref int number, ref int returnValue){ returnValue += 50;}
Hooking Properties
MonoDetour.HookGen also generates hooks for properties, so this is the same case as with the basic hook example.
One thing to know though is that getter methods have a get_
prefix, and setter methods have a set_
prefix.
// Hook the getter method:On.Lib.LibraryClass.get_IsTrue.Prefix(Prefix_get_IsTrue);
// Hook the setter method:On.Lib.LibraryClass.set_IsTrue.Prefix(Prefix_set_IsTrue);// Note that if the property doesn't implement// a setter, there won't be a hook for it.