You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

125 lines
3.4 KiB

  1. using Mono.Cecil;
  2. using System;
  3. using System.IO;
  4. using System.Reflection;
  5. namespace IPA.Injector
  6. {
  7. internal class VirtualizedModule
  8. {
  9. private readonly FileInfo file;
  10. private ModuleDefinition module;
  11. public static VirtualizedModule Load(string engineFile)
  12. {
  13. return new VirtualizedModule(engineFile);
  14. }
  15. private VirtualizedModule(string assemblyFile)
  16. {
  17. file = new FileInfo(assemblyFile);
  18. LoadModules();
  19. }
  20. private void LoadModules()
  21. {
  22. module = ModuleDefinition.ReadModule(file.FullName, new ReaderParameters
  23. {
  24. ReadWrite = false,
  25. InMemory = true,
  26. ReadingMode = ReadingMode.Immediate
  27. });
  28. }
  29. ~VirtualizedModule()
  30. {
  31. module?.Dispose();
  32. }
  33. /// <summary>
  34. ///
  35. /// </summary>
  36. public void Virtualize(AssemblyName selfName, Action beforeChangeCallback = null)
  37. {
  38. var changed = false;
  39. var virtualize = true;
  40. foreach (var r in module.AssemblyReferences)
  41. {
  42. if (r.Name == selfName.Name)
  43. {
  44. virtualize = false;
  45. if (r.Version != selfName.Version)
  46. {
  47. r.Version = selfName.Version;
  48. changed = true;
  49. }
  50. }
  51. }
  52. if (virtualize)
  53. {
  54. changed = true;
  55. module.AssemblyReferences.Add(new AssemblyNameReference(selfName.Name, selfName.Version));
  56. foreach (var type in module.Types)
  57. {
  58. VirtualizeType(type);
  59. }
  60. }
  61. if (changed)
  62. {
  63. beforeChangeCallback?.Invoke();
  64. module.Write(file.FullName);
  65. }
  66. }
  67. private void VirtualizeType(TypeDefinition type)
  68. {
  69. if(type.IsSealed)
  70. {
  71. // Unseal
  72. type.IsSealed = false;
  73. }
  74. if (type.IsInterface) return;
  75. if (type.IsAbstract) return;
  76. // These two don't seem to work.
  77. if (type.Name == "SceneControl" || type.Name == "ConfigUI") return;
  78. // Take care of sub types
  79. foreach (var subType in type.NestedTypes)
  80. {
  81. VirtualizeType(subType);
  82. }
  83. foreach (var method in type.Methods)
  84. {
  85. if (method.IsManaged
  86. && method.IsIL
  87. && !method.IsStatic
  88. && !method.IsVirtual
  89. && !method.IsAbstract
  90. && !method.IsAddOn
  91. && !method.IsConstructor
  92. && !method.IsSpecialName
  93. && !method.IsGenericInstance
  94. && !method.HasOverrides)
  95. {
  96. method.IsVirtual = true;
  97. method.IsPublic = true;
  98. method.IsPrivate = false;
  99. method.IsNewSlot = true;
  100. method.IsHideBySig = true;
  101. }
  102. }
  103. foreach (var field in type.Fields)
  104. {
  105. if (field.IsPrivate) field.IsFamily = true;
  106. }
  107. }
  108. }
  109. }