Exemple #1
0
        /// <summary>
        /// Generates instructions to load arguments or default values onto the stack in a
        /// detour method.
        /// </summary>
        /// <param name="generator">The method where the calls will be added.</param>
        /// <param name="actualParams">The actual parameters required.</param>
        /// <param name="expectedParams">The parameters provided.</param>
        /// <param name="offset">The offset to start loading (0 = static, 1 = instance).</param>
        private static void LoadParameters(ILGenerator generator, ParameterInfo[] actualParams,
                                           Type[] expectedParams, int offset)
        {
            // Load the known method arguments onto the stack
            int n = expectedParams.Length, need = actualParams.Length + offset;

            if (n > 0)
            {
                generator.Emit(OpCodes.Ldarg_0);
            }
            if (n > 1)
            {
                generator.Emit(OpCodes.Ldarg_1);
            }
            if (n > 2)
            {
                generator.Emit(OpCodes.Ldarg_2);
            }
            if (n > 3)
            {
                generator.Emit(OpCodes.Ldarg_3);
            }
            for (int i = 4; i < n; i++)
            {
                generator.Emit(OpCodes.Ldarg_S, i);
            }
            // Load the rest as defaults
            for (int i = n; i < need; i++)
            {
                var param = actualParams[i - offset];
                PTranspilerTools.GenerateDefaultLoad(generator, param.ParameterType, param.
                                                     DefaultValue);
            }
        }
Exemple #2
0
        /// <summary>
        /// Creates a dynamic detour method of the specified delegate type to wrap a base game
        /// method with the specified name. The dynamic method will automatically adapt if
        /// optional parameters are added, filling in their default values.
        /// </summary>
        /// <typeparam name="D">The delegate type to be used to call the detour.</typeparam>
        /// <param name="target">The target method to be called.</param>
        /// <returns>The detour that will call that method.</returns>
        /// <exception cref="DetourException">If the delegate does not match the target.</exception>
        public static D Detour <D>(this MethodInfo target) where D : Delegate
        {
            if (target == null)
            {
                throw new ArgumentNullException("target");
            }
            if (target.ContainsGenericParameters)
            {
                throw new ArgumentException("Generic types must have all parameters defined");
            }
            var expected           = DelegateInfo.Create(typeof(D));
            var parentType         = target.DeclaringType;
            var expectedParamTypes = expected.ParameterTypes;
            var actualParams       = ValidateDelegate(expected, target);
            int offset             = target.IsStatic ? 0 : 1;
            // Method will be "declared" in the type of the target, as we are detouring around
            // a method of that type
            var caller = new DynamicMethod(target.Name + "_Detour", expected.ReturnType,
                                           expectedParamTypes, parentType, true);
            var generator = caller.GetILGenerator();
            // Load the known method arguments onto the stack
            int n = expectedParamTypes.Length, need = actualParams.Length + offset;

            if (n > 0)
            {
                generator.Emit(OpCodes.Ldarg_0);
            }
            if (n > 1)
            {
                generator.Emit(OpCodes.Ldarg_1);
            }
            if (n > 2)
            {
                generator.Emit(OpCodes.Ldarg_2);
            }
            if (n > 3)
            {
                generator.Emit(OpCodes.Ldarg_3);
            }
            for (int i = 4; i < n; i++)
            {
                generator.Emit(OpCodes.Ldarg_S, i);
            }
            // Load the rest as defaults
            for (int i = n; i < need; i++)
            {
                var param = actualParams[i - offset];
                PTranspilerTools.GenerateDefaultLoad(generator, param.ParameterType, param.
                                                     DefaultValue);
            }
            if (parentType.IsValueType || target.IsStatic)
            {
                generator.Emit(OpCodes.Call, target);
            }
            else
            {
                generator.Emit(OpCodes.Callvirt, target);
            }
            generator.Emit(OpCodes.Ret);
            // Define the parameter names, parameter indexes start at 1
            if (offset > 0)
            {
                caller.DefineParameter(1, ParameterAttributes.None, "this");
            }
            for (int i = offset; i < n; i++)
            {
                var oldParam = actualParams[i - offset];
                caller.DefineParameter(i + 1, oldParam.Attributes, oldParam.Name);
            }
#if DEBUG
            PUtil.LogDebug("Created delegate {0} for method {1}.{2} with parameters [{3}]".
                           F(caller.Name, parentType.FullName, target.Name, actualParams.Join(",")));
#endif
            return(caller.CreateDelegate(typeof(D)) as D);
        }