Exemple #1
0
        /// <summary>
        /// Applies the patch described in the given PatchingManifest to the TargetAssembly.
        /// </summary>
        /// <param name="manifest">The PatchingManifest. Note that the instance will be populated with additional information (such as newly created types) during execution.</param>
        /// <param name="o"></param>
        public void PatchManifest(PatchingManifest manifest, IProgressMonitor o)
        {
            /*	The point of this method is to introduce all the patched elements in the correct order.
             *
             * Standard order of business for order between modify/remove/update:
             * 1. Remove Xs
             * 2. Create new Xs
             * 3. Update existing Xs (+ those we just created)
             */
            manifest.Specialize(TargetAssembly);
            o.TaskTitle = $"{manifest.PatchAssembly.Name.Name}";
            o.Current   = 0;
            o.Total     = 11;
            AssemblyDefinition targetAssemblyBackup = null;

            if (UseBackup)
            {
                targetAssemblyBackup = TargetAssembly.Clone();
            }

            try {
                CurrentMemberCache = manifest.CreateCache();
                //+INTRODUCE NEW TYPES
                //Declare all the new types, in the order of their nesting level (.e.g topmost types, nested types, types nested in those, etc),
                //But don't set anything that references other things, like BaseType, interfaces, custom attributes, etc.
                //Type parameters *are* added at this stage, but no constraints are specified.
                //DEPENDENCIES: None
                o.TaskText = "Introducing Types";
                IntroduceTypes(manifest.TypeActions);
                o.Current++;

                //+REMOVE EXISTING METHODS
                //Remove any methods that need removing.
                //DEPENDENCIES: Probably none
                o.TaskText = "Removing Methods";
                RemoveMethods(manifest.MethodActions);
                o.Current++;

                //+INTRODUCE NEW METHOD AND METHOD TYPE DEFINITIONS
                //Declare all the new methods and their type parameters, but do not set nything that references other types,
                //including return type, parameter types, and type parameter constraints
                //This is because method type variables must already exist.
                //This is performed now because types can reference attribute constructors that don't exist until we create them,
                //Don't set custom attributes in this stage.
                //DEPENDENCIES: Type definitions (when introduced to new types)
                o.TaskText = "Introducing Methods";
                IntroduceMethods(manifest.MethodActions);
                o.Current++;

                //+UPDATE METHOD DECLERATIONS
                //Update method declerations with parameters and return types
                //We do this separately, because a method's parameters and return types depend on that method's generic parameters
                //Don't set custom attributes in this stage though it's possible to do so.
                //This is to avoid code duplication.
                //DEPENDENCIES: Type definitions, method definitions
                o.TaskText = "Updating Type Declerations";
                UpdateMethodDeclerations(manifest.MethodActions);
                o.Current++;

                //+IMPORT ASSEMBLY/MODULE CUSTOM ATTRIBUTES
                //Add any custom attributes for things that aren't part of the method/type hierarchy, such as assemblies.
                //DEPENDENCIES: Method definitions, type definitions. (for attribute types and attribute constructors)
                o.TaskText = "Importing Assembly/Module Attributes";
                var patchingAssembly = manifest.PatchAssembly;

                //for assmebly:
                CopyCustomAttributesByImportAttribute(TargetAssembly, patchingAssembly,
                                                      patchingAssembly.GetCustomAttribute <ImportCustomAttributesAttribute>());

                //for module:
                CopyCustomAttributesByImportAttribute(TargetAssembly.MainModule, patchingAssembly.MainModule,
                                                      patchingAssembly.MainModule.GetCustomAttribute <ImportCustomAttributesAttribute>());
                o.Current++;

                //+UPDATE TYPE DEFINITIONS
                //Set the type information we didn't set in (1), according to the same order, including custom attributes.
                //When/if modifying type inheritance is allowed, this process will occur at this stage.
                //DEPENDENCIES: Type definitions (obviously), method definitions (for attribute constructors)
                o.TaskText = "Updating Type Definitions";
                UpdateTypes(manifest.TypeActions);
                o.Current++;

                //+FIELDS
                //remove/define/modify fields. This is where most enum processing happens. Custom attributes are set at this stage.
                //DEPENDENCIES: Type definitions, method definitions (for attribute constructors)
                o.TaskText = "Processing Fields";
                ClearReplacedTypes(manifest.TypeActions);
                RemoveFields(manifest.FieldActions);
                IntroduceFields(manifest.FieldActions);
                UpdateFields(manifest.FieldActions);
                o.Current++;

                //+PROPERTIES
                //Remove/define/modify properties. This doesn't change anything about methods. Custom attributes are set at this stage.
                //DEPENDENCIES: Type definitions, method definitions (attribute constructors, getter/setters)
                o.TaskText = "Processing Properties";
                RemoveProperties(manifest.PropertyActions);
                IntroduceProperties(manifest.PropertyActions);
                UpdateProperties(manifest.PropertyActions);
                o.Current++;

                //+EVENTS
                //Remove/define/modify events. This doesn't change anything about methods. Custom attributes are set at this stage.
                //DEPENENCIES: Type definitions, method definitions (attribute constructors, add/remove/invoke handlers)
                o.TaskText = "Introducing Events";
                RemoveEvents(manifest.EventActions);
                IntroduceEvents(manifest.EventActions);
                UpdateEvents(manifest.EventActions);
                o.Current++;

                //+FINALIZE METHODS, GENERATE METHOD BODIES
                //Fill/modify the bodies of all remaining methods, and also modify accessibility/attributes of existing ones.
                //Note that methods that are the source of DuplicatesBody will be resolved in their unmodified version,
                //so the modifications won't influence this functionality.
                //Custom attributes are set at this stage.
                //Also, explicit overrides (what in C# is explicit interface implementation) are specified here.
                //DEPENDENCIES: Type definitions, method definitions, method signature elements, field definitions
                o.TaskText = "Updating Method Bodies";
                UpdateMethods(manifest.MethodActions);
                o.Current++;

                //+ADD PATCHING HISTORY TO ASSEMBLY
                o.TaskText = "Updating History";
                if (EmbedHistory)
                {
                    TargetAssembly.AddPatchedByAssemblyAttribute(manifest.PatchAssembly, _assemblyHistoryIndex++, OriginalAssemblyMetadata);
                }
                o.Current++;
            }
            catch {
                if (UseBackup)
                {
                    TargetAssembly = targetAssemblyBackup;
                }
                throw;
            }
        }
Exemple #2
0
        /// <summary>
        /// Reads the specified assembly definition and creates a manifest.
        /// </summary>
        /// <param name="yourAssembly">The patch assembly to read.</param>
        /// <returns></returns>
        public PatchingManifest CreateManifest(AssemblyDefinition yourAssembly)
        {
            var multicast = yourAssembly.GetCustomAttributes <DisablePatchingByNameAttribute>();
            var filter    = CreateMemberFilter(multicast);

            var patchAssemblyAttr = yourAssembly.GetCustomAttribute <PatchAssemblyAttribute>();

            if (patchAssemblyAttr == null)
            {
                throw Errors.No_patch_assembly_attribute(yourAssembly);
            }
            var patchInfoTypeRefs =
                yourAssembly.MainModule.Types.Where(
                    x => x.CustomAttributes.Any(y => y.AttributeType.FullName == typeof(PatchInfoAttribute).FullName))
                .ToList
                    ();

            if (patchInfoTypeRefs.Count > 1)
            {
                throw Errors.More_than_one_PatchInfoAttribute(yourAssembly);
            }
            var infoTypeRef = patchInfoTypeRefs.FirstOrDefault();

            PatchInfoProxy info = null;

            if (infoTypeRef != null)
            {
                var infoTypeDef = infoTypeRef.Resolve();
                info = PatchInfoProxy.FromPatchAssembly(infoTypeDef.Module.FullyQualifiedName, infoTypeDef.Module.Assembly.Name.Name,
                                                        infoTypeDef.FullName);
                Log.Information("PatchInfo class successfuly loaded.");
            }
            else
            {
                Log.Warning($"This assembly does not have a class decorated with {nameof(PatchInfoAttribute)} so it cannot participate in automatic patching.");
            }

            var allTypesInOrder = GetAllTypesInNestingOrder(yourAssembly.MainModule.Types).ToList();
            //+ Organizing types by action attribute
            var typesByActionSeq =
                from type in allTypesInOrder
                let typeActionAttr = GetTypeActionAttribute(type)
                                     where typeActionAttr != null && Filter(type) && filter(type)
                                     let patchedTypeName = type.GetPatchedTypeFullName()
                                                           group new TypeAction()
            {
                YourType        = type,
                ActionAttribute = typeActionAttr,
            } by typeActionAttr.GetType();

            var types = typesByActionSeq.ToSimpleTypeLookup();

            var fields     = OrganizeMembers(types, x => x.Fields, filter);
            var methods    = OrganizeMembers(types, x => x.Methods, filter);
            var properties = OrganizeMembers(types, x => x.Properties, filter);
            var events     = OrganizeMembers(types, x => x.Events, filter);

            foreach (var eventAction in events[typeof(NewMemberAttribute)])
            {
                ImplicitlyAddNewMethods(methods, eventAction, vent => {
                    return(new[] {
                        vent.AddMethod,
                        vent.RemoveMethod,
                        vent.InvokeMethod,
                    }.Concat(vent.OtherMethods).Where(method => method != null));
                });
            }

            foreach (var propAction in properties[typeof(NewMemberAttribute)])
            {
                ImplicitlyAddNewMethods(methods, propAction, prop => {
                    return(new[] {
                        prop.GetMethod,
                        prop.SetMethod,
                    }.Concat(prop.OtherMethods).Where(method => method != null));
                });
            }

            var patchingManifest = new PatchingManifest()
            {
                EventActions    = events,
                FieldActions    = fields,
                PropertyActions = properties,
                MethodActions   = methods,
                TypeActions     = types,
                PatchAssembly   = yourAssembly,
                PatchInfo       = info
            };

            return(patchingManifest);
        }