From 3b7a54271ccf60a622fd4aa3d8f7650c3b67d609 Mon Sep 17 00:00:00 2001 From: Nikolay Kuznetsov Date: Tue, 26 Oct 2021 19:29:09 +0200 Subject: [PATCH] Fix binary compatibility of ClassInjector --- AssemblyUnhollower/AssemblyUnhollower.csproj | 2 +- README.md | 2 +- ReleaseChangelog.md | 1 + UnhollowerBaseLib/ClassInjector.cs | 22 +++++++++++++++----- UnhollowerBaseLib/UnhollowerBaseLib.csproj | 2 +- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/AssemblyUnhollower/AssemblyUnhollower.csproj b/AssemblyUnhollower/AssemblyUnhollower.csproj index 94cac43..2b58938 100644 --- a/AssemblyUnhollower/AssemblyUnhollower.csproj +++ b/AssemblyUnhollower/AssemblyUnhollower.csproj @@ -4,7 +4,7 @@ Exe net4.7.2;net5.0;netstandard2.1 enable - 0.4.16.0 + 0.4.16.1 latest true diff --git a/README.md b/README.md index aa474a7..3364868 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ Limitations: ## Implementing interfaces with injected types Starting with 0.4.16.0, injected types can implement IL2CPP interfaces. Just like previously, your type can't implement the interface directly, as it's still generated as a class. -However, you can pass additional interface types to `RegisterTypeInIl2Cpp`, and they will be implemented as interfaces on the IL2CPP version of your type. +However, you can pass additional interface types to `RegisterTypeInIl2CppWithInterfaces`, and they will be implemented as interfaces on the IL2CPP version of your type. Interface methods are matched to methods in your class by name, parameter count and genericness. Known caveats: * `obj.Cast()` will fail if you try to cast an object of your injected type to an interface. You can work around that with `new InterfaceType(obj.Pointer)` if you're absolutely sure it implements that interface. diff --git a/ReleaseChangelog.md b/ReleaseChangelog.md index cbebbd2..d9acb4d 100644 --- a/ReleaseChangelog.md +++ b/ReleaseChangelog.md @@ -9,4 +9,5 @@ Changes: * Xref scanner now considers CMOVcc opcodes for string references * Fixed deobfuscation map generator failing to run (it still generates bad maps for deobfuscated types though - some postprocessing is required) * Fixed newer Unity versions failing due to wrong native struct description + * 0.4.16.1 - fixed binary compatibility of ClassInjector API (at the cost of breaking binary compatibility with 0.4.16.0) \ No newline at end of file diff --git a/UnhollowerBaseLib/ClassInjector.cs b/UnhollowerBaseLib/ClassInjector.cs index e627ef9..0a1ca77 100644 --- a/UnhollowerBaseLib/ClassInjector.cs +++ b/UnhollowerBaseLib/ClassInjector.cs @@ -71,11 +71,23 @@ public static void AssignGcHandle(IntPtr pointer, GCHandle gcHandle) *(IntPtr*)targetGcHandlePointer = handleAsPointer; } - public static void RegisterTypeInIl2Cpp() where T : class => RegisterTypeInIl2Cpp(typeof(T), true); - public static void RegisterTypeInIl2Cpp(params INativeClassStruct[] interfaces) where T : class => RegisterTypeInIl2Cpp(typeof(T), true, interfaces); - public static void RegisterTypeInIl2Cpp(bool logSuccess, params INativeClassStruct[] interfaces) where T : class => RegisterTypeInIl2Cpp(typeof(T), logSuccess, interfaces); - public static void RegisterTypeInIl2Cpp(Type type, params INativeClassStruct[] interfaces) => RegisterTypeInIl2Cpp(type, true, interfaces); - public static void RegisterTypeInIl2Cpp(Type type, bool logSuccess, params INativeClassStruct[] interfaces) + public static void RegisterTypeInIl2Cpp() where T : class => RegisterTypeInIl2CppImpl(typeof(T), true, Array.Empty()); + public static void RegisterTypeInIl2Cpp(bool logSuccess) where T : class => RegisterTypeInIl2CppImpl(typeof(T), logSuccess, Array.Empty()); + public static void RegisterTypeInIl2Cpp(Type type, bool logSuccess) => RegisterTypeInIl2CppImpl(type, logSuccess, Array.Empty()); + public static void RegisterTypeInIl2CppWithInterfaces(params Type[] interfaces) where T : class => RegisterTypeInIl2CppWithInterfaces(typeof(T), true, interfaces); + public static void RegisterTypeInIl2CppWithInterfaces(bool logSuccess, params Type[] interfaces) where T : class => RegisterTypeInIl2CppWithInterfaces(typeof(T), logSuccess, interfaces); + public static void RegisterTypeInIl2CppWithInterfaces(Type type, bool logSuccess, params Type[] interfaces) + { + RegisterTypeInIl2CppImpl(type, logSuccess, interfaces.Select(it => + { + var classPointer = ReadClassPointerForType(it); + if (classPointer == IntPtr.Zero) + throw new ArgumentException($"Type {it} doesn't have an IL2CPP class pointer, which means it's not an IL2CPP interface"); + return UnityVersionHandler.Wrap((Il2CppClass*)classPointer); + }).ToArray()); + } + + public static void RegisterTypeInIl2CppImpl(Type type, bool logSuccess, params INativeClassStruct[] interfaces) { if(type == null) throw new ArgumentException($"Type argument cannot be null"); diff --git a/UnhollowerBaseLib/UnhollowerBaseLib.csproj b/UnhollowerBaseLib/UnhollowerBaseLib.csproj index 04ca74f..5e6ffb5 100644 --- a/UnhollowerBaseLib/UnhollowerBaseLib.csproj +++ b/UnhollowerBaseLib/UnhollowerBaseLib.csproj @@ -4,7 +4,7 @@ net4.7.2;netstandard2.1 true latest - 0.4.16.0 + 0.4.16.1