MonoDetour
Adding to Your Project
Section titled “Adding to Your Project”You can add MonoDetour to your project by adding the following to your csproj:
<ItemGroup> <PackageReference Include="MonoDetour.HookGen" Version="0.7.*" PrivateAssets="all" /> <PackageReference Include="MonoDetour" Version="[*,2.0)" /> <!-- Highest version below 2.0 --></ItemGroup>Example: Hooking a Method
Section titled “Example: Hooking a Method”MonoDetour makes detouring methods type-safe by making use of C# source generators. Here’s what this means.
Your Problem
Section titled “Your Problem”You are running some app, but you want to modify it so that whenever its WriteMessage method runs, every instance of the string called is replaced with hooked.
namespace SomeApp;
public class SomeClass{ public void WriteMessage(string message) => Console.WriteLine(message);}The app does not have any way to configure this, not in a config or in its API, but fret not; this is what MonoDetour exists for!
Runtime Detouring
Section titled “Runtime Detouring”MonoDetour makes detouring methods at runtime in .NET apps easy without modifying any files on disk. In the following snippet, we apply the changes we want to the WriteMessage method with little code, where our detour to WriteMessage is enforced to be correct at compile-time:
using MonoDetour;using MonoDetour.HookGen;
// Tell MonoDetour.HookGen to generate hook helpers for the target type[MonoDetourTargets(typeof(SomeClass))]static class SomeClassHooks{ // Mark this method to be executed by MonoDetourManager.InvokeHookInitializers [MonoDetourHookInitialize] static void Init() { // Apply our prefix detour which runs before the target method. // 'Md' is the base namespace for generated hook helpers. Md.SomeApp.SomeClass.WriteMessage.Prefix(Prefix_SomeMethod) }
static void Prefix_SomeMethod(SomeType self, ref string message) { message = message.Replace("called", "hooked"); }}However, in the above snippet, we don’t call SomeClassHooks.Init. We’ll do it here in our program’s entry point:
using System.Reflection;using MonoDetour;
// Call all methods marked with [MonoDetourHookInitialize]// in classes marked with [MonoDetourTargets] in this assemblyMonoDetourManager.InvokeHookInitializers(Assembly.GetExecutingAssembly());
// Now when we call WriteMessage,// our prefix detour will run before the original method runsSomeClass someClass = new();someClass.WriteMessage("I have been called!");// Prints:// I have been hooked!In most real use cases, you likely would use MonoDetour in a plugin for a mod loader like BepInEx or MelonLoader, and the app we would be detouring would be some game.
When to Use MonoDetour
Section titled “When to Use MonoDetour”MonoDetour, like MonoMod.RuntimeDetour—the library MonoDetour wraps—is not a library you should use if you don’t absolutely need to. For the most part, this means that you should never use MonoDetour on your own assemblies, and you should only use it on assemblies you don’t control, which usually includes .NET games.