diff --git a/IPA.Injector/Virtualizer.cs b/IPA.Injector/Virtualizer.cs index a49128f6..2d0cf383 100644 --- a/IPA.Injector/Virtualizer.cs +++ b/IPA.Injector/Virtualizer.cs @@ -1,117 +1,117 @@ -using Mono.Cecil; +using Mono.Cecil; using Mono.Cecil.Rocks; using System; using System.Collections.Generic; -using System.IO; -using System.Reflection; - -namespace IPA.Injector -{ - internal class VirtualizedModule : IDisposable - { - private readonly FileInfo file; - private ModuleDefinition module; - - public static VirtualizedModule Load(string engineFile) - { - return new VirtualizedModule(engineFile); - } - - private VirtualizedModule(string assemblyFile) - { - file = new FileInfo(assemblyFile); - - LoadModules(); - } - - private void LoadModules() - { - module = ModuleDefinition.ReadModule(file.FullName, new ReaderParameters - { - ReadWrite = false, - InMemory = true, - ReadingMode = ReadingMode.Immediate - }); - } - - public void Virtualize(AssemblyName selfName, Action beforeChangeCallback = null) - { - var changed = false; - var virtualize = true; - foreach (var r in module.AssemblyReferences) - { - if (r.Name == selfName.Name) - { - virtualize = false; - if (r.Version != selfName.Version) - { - r.Version = selfName.Version; - changed = true; - } - } - } - - if (virtualize) - { - changed = true; - module.AssemblyReferences.Add(new AssemblyNameReference(selfName.Name, selfName.Version)); - - foreach (var type in module.Types) - { - VirtualizeType(type); - } - } - - if (changed) - { - beforeChangeCallback?.Invoke(); - module.Write(file.FullName); - } - } - - private TypeReference inModreqRef; - private TypeReference outModreqRef; - - private void VirtualizeType(TypeDefinition type) - { - if(type.IsSealed) - { - // Unseal - type.IsSealed = false; - } - +using System.IO; +using System.Reflection; + +namespace IPA.Injector +{ + internal class VirtualizedModule : IDisposable + { + private readonly FileInfo file; + private ModuleDefinition module; + + public static VirtualizedModule Load(string engineFile) + { + return new VirtualizedModule(engineFile); + } + + private VirtualizedModule(string assemblyFile) + { + file = new FileInfo(assemblyFile); + + LoadModules(); + } + + private void LoadModules() + { + module = ModuleDefinition.ReadModule(file.FullName, new ReaderParameters + { + ReadWrite = false, + InMemory = true, + ReadingMode = ReadingMode.Immediate + }); + } + + public void Virtualize(AssemblyName selfName, Action beforeChangeCallback = null) + { + var changed = false; + var virtualize = true; + foreach (var r in module.AssemblyReferences) + { + if (r.Name == selfName.Name) + { + virtualize = false; + if (r.Version != selfName.Version) + { + r.Version = selfName.Version; + changed = true; + } + } + } + + if (virtualize) + { + changed = true; + module.AssemblyReferences.Add(new AssemblyNameReference(selfName.Name, selfName.Version)); + + foreach (var type in module.Types) + { + VirtualizeType(type); + } + } + + if (changed) + { + beforeChangeCallback?.Invoke(); + module.Write(file.FullName); + } + } + + private TypeReference inModreqRef; + // private TypeReference outModreqRef; + + private void VirtualizeType(TypeDefinition type) + { + if(type.IsSealed) + { + // Unseal + type.IsSealed = false; + } + if (type.IsNestedPrivate) { type.IsNestedPrivate = false; type.IsNestedPublic = true; - } - - if (type.IsInterface) return; - if (type.IsAbstract) return; - - // These two don't seem to work. - if (type.Name == "SceneControl" || type.Name == "ConfigUI") return; - - // Take care of sub types - foreach (var subType in type.NestedTypes) - { - VirtualizeType(subType); - } - - foreach (var method in type.Methods) - { - if (method.IsManaged - && method.IsIL - && !method.IsStatic - && !method.IsVirtual - && !method.IsAbstract - && !method.IsAddOn - && !method.IsConstructor - && !method.IsSpecialName - && !method.IsGenericInstance - && !method.HasOverrides) - { - // fix In and Out parameters to have the modreqs required by the compiler + } + + if (type.IsInterface) return; + if (type.IsAbstract) return; + + // These two don't seem to work. + if (type.Name == "SceneControl" || type.Name == "ConfigUI") return; + + // Take care of sub types + foreach (var subType in type.NestedTypes) + { + VirtualizeType(subType); + } + + foreach (var method in type.Methods) + { + if (method.IsManaged + && method.IsIL + && !method.IsStatic + && (!method.IsVirtual || method.IsFinal) + && !method.IsAbstract + && !method.IsAddOn + && !method.IsConstructor + && !method.IsSpecialName + && !method.IsGenericInstance + && !method.HasOverrides) + { + // fix In parameters to have the modreqs required by the compiler foreach (var param in method.Parameters) { if (param.IsIn) @@ -119,27 +119,29 @@ namespace IPA.Injector inModreqRef ??= module.ImportReference(typeof(System.Runtime.InteropServices.InAttribute)); param.ParameterType = AddModreqIfNotExist(param.ParameterType, inModreqRef); } - if (param.IsOut) - { - outModreqRef ??= module.ImportReference(typeof(System.Runtime.InteropServices.OutAttribute)); - param.ParameterType = AddModreqIfNotExist(param.ParameterType, outModreqRef); - } - } - - method.IsVirtual = true; - method.IsPublic = true; - method.IsPrivate = false; - method.IsNewSlot = true; - method.IsHideBySig = true; - } - } - - foreach (var field in type.Fields) - { - if (field.IsPrivate) field.IsFamily = true; - } - } - + // Breaks override methods if modreq is applied to `out` parameters + //if (param.IsOut) + //{ + // outModreqRef ??= module.ImportReference(typeof(System.Runtime.InteropServices.OutAttribute)); + // param.ParameterType = AddModreqIfNotExist(param.ParameterType, outModreqRef); + //} + } + + method.IsVirtual = true; + method.IsFinal = false; + method.IsPublic = true; + method.IsPrivate = false; + method.IsNewSlot = true; + method.IsHideBySig = true; + } + } + + foreach (var field in type.Fields) + { + if (field.IsPrivate) field.IsFamily = true; + } + } + private TypeReference AddModreqIfNotExist(TypeReference type, TypeReference mod) { var (element, opt, req) = GetDecomposedModifiers(type); @@ -148,8 +150,8 @@ namespace IPA.Injector req.Add(mod); } return BuildModifiedType(element, opt, req); - } - + } + private (TypeReference Element, List ModOpt, List ModReq) GetDecomposedModifiers(TypeReference type) { var opt = new List(); @@ -166,8 +168,8 @@ namespace IPA.Injector } return (type, opt, req); - } - + } + private TypeReference BuildModifiedType(TypeReference type, IEnumerable opt, IEnumerable req) { foreach (var mod in req) @@ -181,37 +183,37 @@ namespace IPA.Injector } return type; - } - - #region IDisposable Support - private bool disposedValue = false; // To detect redundant calls - - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - module.Dispose(); - } - - disposedValue = true; - } - } - - ~VirtualizedModule() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(false); - } - - // This code added to correctly implement the disposable pattern. - public void Dispose() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(true); - GC.SuppressFinalize(this); - } - #endregion - } -} + } + + #region IDisposable Support + private bool disposedValue = false; // To detect redundant calls + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + module.Dispose(); + } + + disposedValue = true; + } + } + + ~VirtualizedModule() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(false); + } + + // This code added to correctly implement the disposable pattern. + public void Dispose() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(true); + GC.SuppressFinalize(this); + } + #endregion + } +}