Пример #1
0
        private static MethodInfo GetPatchMethod <T>(T action) where T : Delegate
        {
            if (action.Method.IsStatic && action.Target == null)
            {
                return(action.Method);
            }
            if (MethodCache.TryGetValue(action, out var method))
            {
                return(method);
            }

            var actionParams = action.Method.GetParameters();

            var dmd = new DynamicMethodDefinition($"ActionWrapper_{action.Method.Name}", action.Method.ReturnType,
                                                  actionParams.Select(p => p.ParameterType).ToArray());

            for (var i = 0; i < dmd.Definition.Parameters.Count; i++)
            {
                var paramInfo = actionParams[i];
                var paramDef  = dmd.Definition.Parameters[i];
                paramDef.Name = paramInfo.Name;
            }

            var il          = dmd.GetILGenerator();
            var preserveCtx = action.Target != null && action.Target.GetType().GetFields().Any(x => !x.IsStatic);

            if (preserveCtx)
            {
                var currentCounter = delegateCounter++;
                DelegateCache[currentCounter] = action;

                var cacheField = AccessTools.Field(typeof(HarmonyDelegatePatchingExtensions), nameof(DelegateCache));
                var getMethod  = AccessTools.Method(typeof(Dictionary <int, Delegate>), "get_Item");

                il.Emit(OpCodes.Ldsfld, cacheField);
                il.Emit(OpCodes.Ldc_I4, currentCounter);
                il.Emit(OpCodes.Callvirt, getMethod);
            }
            else
            {
                if (action.Target == null)
                {
                    il.Emit(OpCodes.Ldnull);
                }
                else
                {
                    il.Emit(OpCodes.Newobj,
                            AccessTools.FirstConstructor(action.Target.GetType(),
                                                         x => x.GetParameters().Length == 0 && !x.IsStatic));
                }

                il.Emit(OpCodes.Ldftn, action.Method);
                il.Emit(OpCodes.Newobj, AccessTools.Constructor(typeof(T), new[] { typeof(object), typeof(IntPtr) }));
            }

            for (var i = 0; i < actionParams.Length; i++)
            {
                il.Emit(OpCodes.Ldarg_S, (short)i);
            }

            il.Emit(OpCodes.Callvirt, AccessTools.Method(typeof(T), "Invoke"));
            il.Emit(OpCodes.Ret);

            // Generate with cecil to ensure it's usable with Harmony (Harmony blocks DynamicMethods by default)
            var result = DMDGenerator <DMDCecilGenerator> .Generate(dmd);

            MethodCache[action] = result;
            return(result);
        }
Пример #2
0
 public static MethodInfo GenerateWith <T>(this DynamicMethodDefinition dmd, object context = null)
     where T : DMDGenerator <T>, new()
 {
     return(DMDGenerator <T> .Generate(dmd, context));
 }