.net Lib.Harmony框架学习笔记 电脑版发表于:2024/7/13 19:48 ![.netcore](https://img.tnblog.net/arcimg/hb/c857299a86d84ee7b26d181a31e58234.jpg ".netcore") >#.net Lib.Harmony框架学习笔记 [TOC] Lib.Harmony框架介绍 ------------ tn2>Lib.Harmony 是一个用于 .NET 应用程序的库,主要用于运行时的代码修改和补丁操作。它允许开发者在不修改源代码的情况下,对已编译的 .NET 程序进行动态补丁,通过方法拦截和插入自定义代码来改变程序行为。 Harmony 支持多平台运行,包括 Windows、Linux 和 macOS,灵活性高,可以通过 IL 代码精确控制程序行为。 它在游戏开发中的 Mod 开发和企业软件的热修复及功能扩展中得到广泛应用,并拥有活跃的社区支持。 ![](https://img.tnblog.net/arcimg/hb/9e8bafc6ee244c0f90cf337731d26fd2.png) tn2>官网地址:https://www.patreon.com/pardeike 安装Lib.Harmony包 ------------ tn2>这里创建了一个控制台项目,然后进行安装`Lib.Harmony`。 ![](https://img.tnblog.net/arcimg/hb/80cbd03109c147ec969f795ec398c054.png) 基本使用 ------------ ### 类拦截 tn2>简单来讲对类中的某个方法进行拦截处理返回的请求。 以下面的例子为例: ```csharp public class Worker { public string HandlerThings() { Console.WriteLine("调用了"); return "你好"; } } ``` ```csharp // 标记补丁目标类为 Worker [HarmonyPatch(typeof(Worker))] // 标记补丁目标方法为 Worker 类的 HandlerThings 方法 [HarmonyPatch(nameof(Worker.HandlerThings))] public class HookWorker { /// <summary> /// 前置补丁方法,会在 HandlerThings 方法执行前调用 /// </summary> public static void Prefix() { Console.WriteLine("Prefix"); } /// <summary> /// 后置补丁方法,会在 HandlerThings 方法执行后调用 /// </summary> public static void Postfix() { Console.WriteLine("Postfix"); } /// <summary> /// 最终补丁方法,会在 HandlerThings 方法执行完毕后调用 /// </summary> public static void Finalizer() { Console.WriteLine("Finalizer"); } } ``` ```csharp using HarmonyLib; using LearningLibHarmony; using System.Reflection; Worker worker = new Worker(); Console.WriteLine(worker.HandlerThings()); // 传任意参数 var harmony = new Harmony("hmy"); harmony.PatchAll(Assembly.GetExecutingAssembly()); Console.WriteLine(); Console.WriteLine(worker.HandlerThings()); ``` ![](https://img.tnblog.net/arcimg/hb/9558781bd73a4bc79bfaa2c1152ec519.png) tn2>我们可以把`Prefix`改成bool,返回false将不会有任何返回值。 Prefix方法默认返回的true,表示需要调用原生方法,这里会将篡改的参数传入原生方法。 ```csharp public static bool Prefix() { Console.WriteLine("Prefix"); return false; } ``` ```csharp using HarmonyLib; using LearningLibHarmony; using System.Reflection; Worker worker = new Worker(); Console.WriteLine(worker.HandlerThings()); // 传任意参数 var harmony = new Harmony("hmy"); harmony.PatchAll(Assembly.GetExecutingAssembly()); Console.WriteLine(); Console.WriteLine("《?》"+worker.HandlerThings()); ``` ![](https://img.tnblog.net/arcimg/hb/255fee05d271445ca664aae1fb72c2fe.png) ### 参数篡改 tn2>更改传入的参数。 ```csharp public class Worker { public string HandlerThings(string instring1,string instring2) { Console.WriteLine($"调用了 参数1:{instring1} 参数2:{instring2}"); return instring1+ instring2; } } ``` ```csharp // 标记补丁目标类为 Worker [HarmonyPatch(typeof(Worker))] // 标记补丁目标方法为 Worker 类的 HandlerThings 方法 [HarmonyPatch(nameof(Worker.HandlerThings))] public class HookWorker { /// <summary> /// 前置补丁方法,会在 HandlerThings 方法执行前调用 /// </summary> public static bool Prefix(ref string instring1,ref string instring2) { Console.WriteLine($"Prefix Get param:{instring1} {instring2} "); instring1 = "Prefix1"; instring2 = "Prefix2"; Console.WriteLine($"Update ====> {instring1} {instring2} "); return true; } /// <summary> /// 后置补丁方法,会在 HandlerThings 方法执行后调用 /// </summary> public static void Postfix() { Console.WriteLine("Postfix"); } /// <summary> /// 最终补丁方法,会在 HandlerThings 方法执行完毕后调用 /// </summary> public static void Finalizer() { Console.WriteLine("Finalizer"); } } ``` ```csharp using HarmonyLib; using LearningLibHarmony; using System.Reflection; Worker worker = new Worker(); string mm = "mm"; string ff = "ff"; Console.WriteLine(worker.HandlerThings(mm,ff)); // 传任意参数 var harmony = new Harmony("hmy"); harmony.PatchAll(Assembly.GetExecutingAssembly()); Console.WriteLine(); Console.WriteLine("《?》"+worker.HandlerThings(mm,ff)); ``` ![](https://img.tnblog.net/arcimg/hb/808dd13ed9374ca09f9810cc5c681250.png) ### WPF自定义拦截 tn2>自定义消息框 ```csharp public class Hmy_MessageBox { public void Hmy_Show(string messageBoxText) { MessageBox.Show(messageBoxText); } } ``` tn2>App中注册自动拦截 ```csharp public partial class App : Application { //自动拦截注册 protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); var harmony = new Harmony("hmy"); harmony.PatchAll(Assembly.GetExecutingAssembly()); } } ``` tn2>自动拦截类 ```csharp [HarmonyPatch(typeof(Hmy_MessageBox))] [HarmonyPatch(nameof(Hmy_MessageBox.Hmy_Show))] [HarmonyPatch(new[] { typeof(string) })] public class HookHmy_MessageBox { public static bool Prefix(ref string messageBoxText) { if (!(messageBoxText == "不会更改的弹窗")) { messageBoxText = "改了"; } return true; } } ``` tn2>在窗体MainWindow.xaml里添加两个弹出提示框的按钮: ```xml <Window x:Class="LearningLibHarmony.WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:LearningLibHarmony.WpfApp1" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <Button Content="不会更改的弹窗" Width="120" Height="30" Click="Button_Click"></Button> <Button Content="何明洋" HorizontalAlignment="Left" Click="Button_Click" Margin="264,336,0,0" VerticalAlignment="Top" Height="39" Width="196"/> </Grid> </Window> ``` ```csharp public partial class MainWindow : Window { public Hmy_MessageBox _Hmy_MessageBox { get; set; } public MainWindow() { InitializeComponent(); _Hmy_MessageBox = new Hmy_MessageBox(); } private void Button_Click(object sender, RoutedEventArgs e) { var nowbutton = (Button)sender; _Hmy_MessageBox.Hmy_Show(nowbutton.Content.ToString()); } } ``` ![](https://img.tnblog.net/arcimg/hb/d4ffbcbc6cdd462f9e05337909a6e1e1.png) ![](https://img.tnblog.net/arcimg/hb/ad329f85bc4d4acdbf4f330ad966e9b8.png)