예제 #1
0
        /// <summary>
        /// Gets the class that the method will operate in the context of.
        /// This is NOT necessarily the class that the method exists in.
        /// For extension methods the "this" parameter (first) will be returned
        /// regardless of whether it is a detour or not, pure static methods
        /// will return null (again, regardless of being a detour) as they
        /// don't operate in the context of class.  Instance methods will
        /// return the defining class for non-detours and the class being
        /// injected into for detours.
        /// </summary>
        /// <returns>The method target class</returns>
        /// <param name="info">MethodInfo of the method to check</param>
        /// <param name="attribute">DetourMember attribute</param>
        private static Type GetMethodTargetClass(MethodInfo info, DetourMember attribute = null)
        {
            var methodType = GetMethodType(info);

            if (methodType == MethodType.Static)
            {               // Pure static methods don't have a target class
                return(null);
            }
            if (methodType == MethodType.Extension)
            {               // Regardless of whether this is the detour method or the method to be detoured, for extension methods we take the target class from the first parameter
                return(info.GetParameters()[0].ParameterType);
            }

            if (attribute == null)
            {
                info.TryGetAttribute(out attribute);
            }
            if (attribute != null)
            {
                if (attribute.targetClass != DetourMember.DefaultTargetClass)
                {
                    return(attribute.targetClass);
                }
                return(info.DeclaringType.BaseType);
            }

            return(info.DeclaringType);
        }
예제 #2
0
        /// <summary>
        /// Returns a list of detour methods with matching sequence and timing from a class.
        /// </summary>
        /// <param name="detours">List to add the detours from this class to</param>
        /// <param name="destinationType">The class to check for detour methods</param>
        /// <param name="sequence">Injection sequence</param>
        /// <param name="timing">Injection timing</param>
        private static void GetDetouredMethods(ref List <DetourPair> detours, Type destinationType)
        {
            var destinationMethods = destinationType
                                     .GetMethods(UniversalBindingFlags)
                                     .Where(destinationMethod => destinationMethod.HasAttribute <DetourMember>())
                                     .ToList();

            if (destinationMethods.NullOrEmpty())
            {               // No methods to detour
                return;
            }
            foreach (var destinationMethod in destinationMethods)
            {
                DetourMember attribute = null;
                if (destinationMethod.TryGetAttribute(out attribute))
                {
                    var memberClass = GetDetourTargetClass(destinationMethod, attribute);
                    if (memberClass == null)
                    {                       // Report and ignore any missing classes
                        Log.Error(string.Format("MemberClass '{2}' resolved to null for '{0}.{1}'", destinationType.FullName, destinationMethod.Name, FullNameOfType(attribute.targetClass)));
                        continue;
                    }
                    var sourceMethod = GetDetouredMethodInt(memberClass, attribute.targetMember, destinationMethod);
                    if (sourceMethod == null)
                    {                       // Report and ignore any missing methods
                        Log.Error(string.Format("TargetMember '{2}.{3}' resolved to null for '{0}.{1}'", destinationType.FullName, destinationMethod.Name, memberClass.FullName, attribute.targetMember));
                        continue;
                    }
                    // Add detour for method
                    detours.Add(new DetourPair(GetMethodTargetClass(sourceMethod, null), sourceMethod, GetMethodTargetClass(destinationMethod, attribute), destinationMethod));
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Returns a list of detour property methods (get/set) with matching sequence and timing from a class.
        /// </summary>
        /// <param name="detours">List to add the detours from this class to</param>
        /// <param name="destinationType">The class to check for detour properties</param>
        /// <param name="sequence">Injection sequence</param>
        /// <param name="timing">Injection timing</param>
        private static void GetDetouredProperties(ref List <DetourPair> detours, Type destinationType)
        {
            var destinationProperties = destinationType
                                        .GetProperties(UniversalBindingFlags)
                                        .Where(destinationProperty => destinationProperty.HasAttribute <DetourMember>())
                                        .ToList();

            if (destinationProperties.NullOrEmpty())
            {               // No properties to detour
                return;
            }
            foreach (var destinationProperty in destinationProperties)
            {
                DetourMember attribute = null;
                if (destinationProperty.TryGetAttribute(out attribute))
                {
                    var memberClass = GetDetourTargetClass(destinationProperty, attribute);
                    if (memberClass == null)
                    {                       // Report and ignore any missing classes
                        Log.Error(string.Format("MemberClass '{2}' resolved to null for '{0}.{1}'", destinationType.FullName, destinationProperty.Name, FullNameOfType(attribute.targetClass)));
                        continue;
                    }
                    var sourceProperty = GetDetouredPropertyInt(memberClass, attribute.targetMember, destinationProperty);
                    if (sourceProperty == null)
                    {                       // Report and ignore any missing properties
                        Log.Error(string.Format("TargetMember '{2}.{3}' resolved to null for '{0}.{1}'", destinationType.FullName, destinationProperty.Name, memberClass.FullName, attribute.targetMember));
                        continue;
                    }
                    var destinationMethod = destinationProperty.GetGetMethod(true);
                    if (destinationMethod != null)
                    {                       // Check for get method detour
                        var sourceMethod = sourceProperty.GetGetMethod(true);
                        if (sourceMethod == null)
                        {                           // Report and ignore missing get method
                            Log.Error(string.Format("TargetMember '{2}.{3}' has no get method for '{0}.{1}'", destinationType.FullName, destinationProperty.Name, memberClass.FullName, attribute.targetMember));
                        }
                        else
                        {                           // Add detour for get method
                            detours.Add(new DetourPair(GetMethodTargetClass(sourceMethod, null), sourceMethod, GetMethodTargetClass(destinationMethod, attribute), destinationMethod));
                        }
                    }
                    destinationMethod = destinationProperty.GetSetMethod(true);
                    if (destinationMethod != null)
                    {                       // Check for set method detour
                        var sourceMethod = sourceProperty.GetSetMethod(true);
                        if (sourceMethod == null)
                        {                           // Report and ignore missing set method
                            Log.Error(string.Format("TargetMember '{2}.{3}' has no set method for '{0}.{1}'", destinationType.FullName, destinationProperty.Name, memberClass.FullName, attribute.targetMember));
                        }
                        else
                        {                           // Add detour for set method
                            detours.Add(new DetourPair(GetMethodTargetClass(sourceMethod, null), sourceMethod, GetMethodTargetClass(destinationMethod, attribute), destinationMethod));
                        }
                    }
                }
            }
        }
예제 #4
0
        /// <summary>
        /// Gets the class that a detour will be injected into.
        /// </summary>
        /// <returns>The detour target class</returns>
        /// <param name="info">MemberInfo of the member to check</param>
        /// <param name="attribute">DetourMember attribute</param>
        private static Type GetDetourTargetClass(MemberInfo info, DetourMember attribute)
        {
            if (attribute != null)
            {
                if (attribute.targetClass != DetourMember.DefaultTargetClass)
                {
                    return(attribute.targetClass);
                }
                var methodInfo = info as MethodInfo;
                if (
                    (info.DeclaringType.BaseType == typeof(System.Object)) &&
                    (methodInfo != null) &&
                    (GetMethodType(methodInfo) == MethodType.Extension)
                    )
                {
                    return(methodInfo.GetParameters()[0].ParameterType);
                }
                return(info.DeclaringType.BaseType);
            }

            return(info.DeclaringType);
        }