Esempio n. 1
0
        /// <summary>
        /// Creates a dynamic detour method of the specified delegate type to wrap a base game
        /// constructor. 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 constructor to be called.</param>
        /// <returns>The detour that will call that constructor.</returns>
        /// <exception cref="DetourException">If the delegate does not match the target.</exception>
        public static D Detour <D>(this ConstructorInfo target) where D : Delegate
        {
            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }
            if (target.ContainsGenericParameters)
            {
                throw new ArgumentException("Generic types must have all parameters defined");
            }
            if (target.IsStatic)
            {
                throw new ArgumentException("Static constructors cannot be called manually");
            }
            var expected           = DelegateInfo.Create(typeof(D));
            var parentType         = target.DeclaringType;
            var expectedParamTypes = expected.ParameterTypes;
            var actualParams       = ValidateDelegate(expected, target, parentType);
            // Method will be "declared" in the type of the target, as we are detouring around
            // a constructor of that type
            var caller = new DynamicMethod("Constructor_Detour", expected.ReturnType,
                                           expectedParamTypes, parentType, true);
            var generator = caller.GetILGenerator();

            LoadParameters(generator, actualParams, expectedParamTypes, 0);
            generator.Emit(OpCodes.Newobj, target);
            generator.Emit(OpCodes.Ret);
            FinishDynamicMethod(caller, actualParams, expectedParamTypes, 0);
#if DEBUG
            PUtil.LogDebug("Created delegate {0} for constructor {1} with parameters [{2}]".
                           F(caller.Name, parentType.FullName, actualParams.Join(",")));
#endif
            return(caller.CreateDelegate(typeof(D)) as D);
        }
Esempio n. 2
0
        /// <summary>
        /// Creates a dynamic detour method of the specified delegate type to wrap a base game
        /// constructor. 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="type">The target type.</param>
        /// <returns>The detour that will call that type's constructor.</returns>
        /// <exception cref="DetourException">If the delegate does not match any valid target method.</exception>
        public static D DetourConstructor <D>(this Type type) where D : Delegate
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }
            var constructors = type.GetConstructors(PPatchTools.BASE_FLAGS | BindingFlags.
                                                    Instance);
            // Determine delegate return type
            var             expected       = DelegateInfo.Create(typeof(D));
            ConstructorInfo bestMatch      = null;
            int             bestParamCount = int.MaxValue;

            foreach (var constructor in constructors)
            {
                try {
                    var result = ValidateDelegate(expected, constructor, type);
                    int n      = result.Length;
                    // Choose overload with fewest parameters to substitute
                    if (n < bestParamCount)
                    {
                        bestParamCount = n;
                        bestMatch      = constructor;
                    }
                } catch (DetourException) {
                    // Keep looking
                }
            }
            if (bestMatch == null)
            {
                throw new DetourException("No match found for {0} constructor".F(type.
                                                                                 FullName));
            }
            return(Detour <D>(bestMatch));
        }
Esempio n. 3
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="type">The target type.</param>
        /// <param name="name">The method name.</param>
        /// <returns>The detour that will call that method.</returns>
        /// <exception cref="DetourException">If the delegate does not match any valid target method.</exception>
        public static D Detour <D>(this Type type, string name) where D : Delegate
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException(nameof(name));
            }
            var methods = type.GetMethods(PPatchTools.BASE_FLAGS | BindingFlags.Static |
                                          BindingFlags.Instance);
            // Determine delegate return type
            var        expected       = DelegateInfo.Create(typeof(D));
            MethodInfo bestMatch      = null;
            int        bestParamCount = int.MaxValue;

            foreach (var method in methods)
            {
                if (method.Name == name)
                {
                    try {
                        var result = ValidateDelegate(expected, method, method.ReturnType);
                        int n      = result.Length;
                        // Choose overload with fewest parameters to substitute
                        if (n < bestParamCount)
                        {
                            bestParamCount = n;
                            bestMatch      = method;
                        }
                    } catch (DetourException) {
                        // Keep looking
                    }
                }
            }
            if (bestMatch == null)
            {
                throw new DetourException("No match found for {1}.{0}".F(name, type.FullName));
            }
            return(Detour <D>(bestMatch));
        }
Esempio n. 4
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(nameof(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, target.ReturnType);
            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();

            LoadParameters(generator, actualParams, expectedParamTypes, offset);
            if (parentType.IsValueType || target.IsStatic)
            {
                generator.Emit(OpCodes.Call, target);
            }
            else
            {
                generator.Emit(OpCodes.Callvirt, target);
            }
            generator.Emit(OpCodes.Ret);
            FinishDynamicMethod(caller, actualParams, expectedParamTypes, offset);
#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);
        }
Esempio n. 5
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);
        }