Example #1
0
        private static void CreatePatchedMethod(ILContext il) {
            ILCursor c = new ILCursor(il);

            // The original method uses System.Reflection.Emit.

            System.Type t_DynamicTools = GetHarmonyType("DynamicTools");

            // Find and replace DynamicTools.CreateDynamicMethod
            if (!c.TryGotoNext(i => i.MatchCall(t_DynamicTools, "CreateDynamicMethod"))) {
                // Not the right method. Harmony defines two CreatePatchedMethod methods.
                il.MakeReadOnly();
                return;
            }
            c.Next.OpCode = OpCodes.Call;
            c.Next.Operand = il.Import(typeof(HarmonyDetourBridge).GetMethod("CreateDMD", BindingFlags.NonPublic | BindingFlags.Static));
            
            // Find the variable holding the "dynamic method" and update it.
            int varDMDi = -1;
            c.GotoNext(i => i.MatchStloc(out varDMDi));
            VariableDefinition varDMD = il.Body.Variables[varDMDi];
            varDMD.VariableType = il.Import(typeof(DynamicMethodDefinition));

            // Find and replace patch.GetILGenerator
            c.GotoNext(i => i.MatchCallvirt<System.Reflection.Emit.DynamicMethod>("GetILGenerator"));
            c.Next.OpCode = OpCodes.Call;
            c.Next.Operand = il.Import(typeof(DynamicMethodDefinition).GetMethod("GetILGenerator", BindingFlags.Public | BindingFlags.Instance));

            // Find and remove DynamicTools.PrepareDynamicMethod
            c.GotoNext(i => i.MatchCall(t_DynamicTools, "PrepareDynamicMethod"));
            c.Next.OpCode = OpCodes.Pop;
            c.Next.Operand = null;

            // Go to the next ldloc that loads the DynamicMethod.
            // No matter if it gets stored into a local variable or returned immediately,
            // grab it, store it separately and push null as a replacement.
            c.GotoNext(i => i.MatchLdloc(varDMDi));
            c.Index++;
            c.EmitDelegate<Func<DynamicMethodDefinition, System.Reflection.Emit.DynamicMethod>>(dmd => {
                _LastWrapperDMD = dmd;
                return null;
            });
        }