日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

动态IL织入框架Harmony简单入手

發布時間:2023/12/4 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 动态IL织入框架Harmony简单入手 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Harmony是一個開放源代碼庫,旨在在運行時替換、修飾或修改任何現有C#方法。它的主要用在用Mono語言編寫的游戲和插件,但是該技術可以與任何.NET版本一起使用。它還照顧對同一方法的多次更改(它們累積而不是覆蓋)。

它為每個原始方法創建DynamicMethod方法,并向其織入代碼,該代碼在開始和結束時調用自定義方法。它還允許您編寫過濾器來處理原始的IL代碼,從而可以對原始方法進行更詳細的操作。

文檔可以在這里找到。

  • 最新2.0版本終于支持.net core.

  • Harmony支持手動(Patch)和自動(PatchAll)織入

  • 織入位置可以是執行前(Prefix)、執行后(Postfix)和終結囂(Finalizer),也可以更詳細的手動修改IL(Transpiler)

  • 支持構造函數、Getter/Setter、虛/非虛方法、靜態方法

手動模式

class NoneGenericClass {private readonly bool _isRunning = true;private int _counter = 1;public int DoSomething(){Console.WriteLine(nameof(DoSomething));if (_isRunning){_counter++;}return _counter * 10;}public static int DoSomething2(){Console.WriteLine(nameof(DoSomething2));return 3333;}public IEnumerable<int> GetNumbers(){Console.WriteLine(nameof(GetNumbers));yield return 1;yield return 2;yield return 3;} }static class NoneGenericClassPatcher {public static void Patch(){var harmony = new Harmony(nameof(NoneGenericClassPatcher));harmony.Patch(typeof(NoneGenericClass).GetMethod(nameof(NoneGenericClass.DoSomething)),new HarmonyMethod(GetMethod(nameof(MyPrefix))),new HarmonyMethod(GetMethod(nameof(MyPostfix))),new HarmonyMethod(GetMethod(nameof(MyTranspiler))),new HarmonyMethod(GetMethod(nameof(MyFinalizer))));Console.WriteLine(new NoneGenericClass().DoSomething());Console.WriteLine();harmony.Patch(typeof(NoneGenericClass).GetMethod(nameof(NoneGenericClass.GetNumbers)),new HarmonyMethod(GetMethod(nameof(MyPrefix))),new HarmonyMethod(GetMethod(nameof(PassthroughPostfix))),new HarmonyMethod(GetMethod(nameof(MyTranspiler))),new HarmonyMethod(GetMethod(nameof(MyFinalizer))));Console.WriteLine(string.Join(", ", new NoneGenericClass().GetNumbers())); //BUG:有Finalizer方法時PassthroughPostfix不生效Console.WriteLine();harmony.Patch(typeof(NoneGenericClass).GetMethod(nameof(NoneGenericClass.DoSomething2)),new HarmonyMethod(GetMethod(nameof(StaticPrefix))),new HarmonyMethod(GetMethod(nameof(MyPostfix))),new HarmonyMethod(GetMethod(nameof(MyTranspiler))),new HarmonyMethod(GetMethod(nameof(MyFinalizer))));Console.WriteLine(NoneGenericClass.DoSomething2());}static MethodInfo GetMethod(string name) => typeof(NoneGenericClassPatcher).GetMethod(name, BindingFlags.Static | BindingFlags.Public);public static bool MyPrefix(out Stopwatch __state, ref bool ____isRunning){__state = Stopwatch.StartNew();Console.WriteLine($"{nameof(MyPrefix)} {____isRunning}");return true;}public static bool StaticPrefix(out Stopwatch __state){__state = Stopwatch.StartNew();Console.WriteLine($"{nameof(StaticPrefix)}");return true;}public static void MyPostfix(Stopwatch __state, ref int __result, MethodBase __originalMethod){Console.WriteLine($"{__state.ElapsedMilliseconds} {__result++}");Console.WriteLine(nameof(MyPostfix));}public static IEnumerable<int> PassthroughPostfix(IEnumerable<int> values){yield return 0;foreach (var value in values)if (value > 1)yield return value * 10;yield return 99;Console.WriteLine(nameof(PassthroughPostfix));}// looks for STDFLD someField and inserts CALL MyExtraMethod before itpublic static IEnumerable<CodeInstruction> MyTranspiler(IEnumerable<CodeInstruction> instructions){Console.WriteLine(nameof(MyTranspiler));//var found = false;foreach (var instruction in instructions){//if (instruction.opcode == OpCodes.Stfld && instruction.operand == f_someField)//{// yield return new CodeInstruction(OpCodes.Call, m_MyExtraMethod);// found = true;//}yield return instruction;}//if (found == false)// ReportError("Cannot find <Stdfld someField> in OriginalType.OriginalMethod");}public static void MyFinalizer(Exception __exception){Console.WriteLine($"{nameof(MyFinalizer)} {__exception}");} }

自動模式

public class Annotations {private readonly bool _isRunning;public IEnumerable<int> GetNumbers(){Console.WriteLine(nameof(GetNumbers));yield return 1;yield return 2;yield return 3;} }[HarmonyPatch(typeof(Annotations))] [HarmonyPatch(nameof(Annotations.GetNumbers))] public class AnnotationsPatcher {static AccessTools.FieldRef<Annotations, bool> isRunningRef =AccessTools.FieldRefAccess<Annotations, bool>("_isRunning");public static void Patch(){var harmony = new Harmony(nameof(AnnotationsPatcher));harmony.PatchAll();Console.WriteLine(string.Join(", ", new Annotations().GetNumbers()));}static bool Prefix(Annotations __instance){Console.WriteLine("Prefix");return true;}/// <summary>Not working</summary>static IEnumerable<int> Postfix(IEnumerable<int> values){yield return 0;foreach (var value in values)if (value > 1)yield return value * 10;yield return 99;Console.WriteLine(nameof(Postfix));}// looks for STDFLD someField and inserts CALL MyExtraMethod before itpublic static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions){Console.WriteLine(nameof(Transpiler));//var found = false;foreach (var instruction in instructions){//if (instruction.opcode == OpCodes.Stfld && instruction.operand == f_someField)//{// yield return new CodeInstruction(OpCodes.Call, m_MyExtraMethod);// found = true;//}yield return instruction;}//if (found == false)// ReportError("Cannot find <Stdfld someField> in OriginalType.OriginalMethod");} }

運行代碼

static void Main(string[] args) {NoneGenericClassPatcher.Patch();Console.WriteLine();AnnotationsPatcher.Patch(); }

輸出結果

MyTranspiler MyPrefix True DoSomething 20 MyPostfix MyFinalizerMyTranspiler MyPrefix True MyFinalizer GetNumbers 1, 2, 3MyTranspiler StaticPrefix DoSomething2 3333 MyPostfix MyFinalizerTranspiler Prefix GetNumbers Postfix 0, 20, 30, 99

總結

以上是生活随笔為你收集整理的动态IL织入框架Harmony简单入手的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。