diff --git a/Il2CppInterop.Runtime/Injection/ClassInjector.cs b/Il2CppInterop.Runtime/Injection/ClassInjector.cs index 6db08110..63d91020 100644 --- a/Il2CppInterop.Runtime/Injection/ClassInjector.cs +++ b/Il2CppInterop.Runtime/Injection/ClassInjector.cs @@ -303,7 +303,7 @@ public static void RegisterTypeInIl2Cpp(Type type, RegisterTypeOptions options) classPointer.InstanceSize = (uint)(fieldOffset + sizeof(InjectedClassData)); classPointer.ActualSize = classPointer.InstanceSize; - var eligibleMethods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly).Where(IsMethodEligible).ToArray(); + var eligibleMethods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly).Where(IsMethodEligible).ToArray(); var methodsOffset = type.IsAbstract ? 1 : 2; // 1 is the finalizer, 1 is empty ctor var methodCount = methodsOffset + eligibleMethods.Length; @@ -550,7 +550,6 @@ private static bool IsFieldEligible(FieldInfo field) private static bool IsMethodEligible(MethodInfo method) { if (method.Name == "Finalize") return false; - if (method.IsStatic) return false; if (method.CustomAttributes.Any(it => typeof(HideFromIl2CppAttribute).IsAssignableFrom(it.AttributeType))) return false; @@ -583,10 +582,12 @@ private static bool IsMethodEligible(MethodInfo method) foreach (var parameter in method.GetParameters()) { var parameterType = parameter.ParameterType; - if (!IsTypeSupported(parameterType)) + if (!IsTypeSupported(parameterType) || + method.IsStatic && parameterType.IsGenericType && parameterType.ContainsGenericParameters) { Logger.Instance.LogWarning( - "Method {Method} on type {DeclaringType} has unsupported parameter {Parameter} of type {ParameterType}", method.ToString(), method.DeclaringType, parameter, parameterType); + "Method {Method} on type {DeclaringType} has unsupported parameter {Parameter} of type {ParameterType}", method.ToString(), + method.DeclaringType, parameter, parameterType); return false; } } @@ -726,6 +727,11 @@ private static bool IsMethodEligible(MethodInfo method) converted.Flags = Il2CppMethodFlags.METHOD_ATTRIBUTE_PUBLIC | Il2CppMethodFlags.METHOD_ATTRIBUTE_HIDE_BY_SIG; + if (monoMethod.IsStatic) + { + converted.Flags |= Il2CppMethodFlags.METHOD_ATTRIBUTE_STATIC; + } + if (monoMethod.IsAbstract) { converted.Flags |= Il2CppMethodFlags.METHOD_ATTRIBUTE_ABSTRACT; @@ -812,6 +818,16 @@ private static Delegate GetOrCreateTrampoline(MethodInfo monoMethod) return CreateTrampoline(monoMethod); } + private static Type[] GetNativeParameterTypes(MethodInfo monoMethod) + { + var nativeParameterTypes = new List(); + if (!monoMethod.IsStatic) + nativeParameterTypes.Add(typeof(IntPtr)); + nativeParameterTypes.AddRange(monoMethod.GetParameters().Select(it => it.ParameterType.NativeType())); + nativeParameterTypes.Add(typeof(Il2CppMethodInfo*)); + return nativeParameterTypes.ToArray(); + } + private static Delegate CreateInvoker(MethodInfo monoMethod) { DynamicMethod method; @@ -834,11 +850,12 @@ private static Delegate CreateInvoker(MethodInfo monoMethod) var body = method.GetILGenerator(); - body.Emit(OpCodes.Ldarg_2); + if (!monoMethod.IsStatic) + body.Emit(OpCodes.Ldarg_2); // obj for (var i = 0; i < monoMethod.GetParameters().Length; i++) { var parameterInfo = monoMethod.GetParameters()[i]; - body.Emit(OpCodes.Ldarg_3); + body.Emit(OpCodes.Ldarg_3); // args body.Emit(OpCodes.Ldc_I4, i * IntPtr.Size); body.Emit(OpCodes.Add_Ovf_Un); var nativeType = parameterInfo.ParameterType.NativeType(); @@ -847,10 +864,9 @@ private static Delegate CreateInvoker(MethodInfo monoMethod) body.Emit(OpCodes.Ldobj, nativeType); } - body.Emit(OpCodes.Ldarg_0); - body.EmitCalli(OpCodes.Calli, CallingConvention.Cdecl, monoMethod.ReturnType.NativeType(), - new[] { typeof(IntPtr) }.Concat(monoMethod.GetParameters().Select(it => it.ParameterType.NativeType())) - .ToArray()); + body.Emit(OpCodes.Ldarg_1); // methodMetadata + body.Emit(OpCodes.Ldarg_0); // methodPointer + body.EmitCalli(OpCodes.Calli, CallingConvention.Cdecl, monoMethod.ReturnType.NativeType(), GetNativeParameterTypes(monoMethod)); if (UnityVersionHandler.IsMetadataV29OrHigher) { @@ -916,33 +932,37 @@ private static void StaticVoidIntPtrInvoker_MetadataV29(IntPtr methodPointer, Il private static Delegate CreateTrampoline(MethodInfo monoMethod) { - var nativeParameterTypes = new[] { typeof(IntPtr) }.Concat(monoMethod.GetParameters() - .Select(it => it.ParameterType.NativeType()).Concat(new[] { typeof(Il2CppMethodInfo*) })).ToArray(); - - var managedParameters = new[] { monoMethod.DeclaringType } - .Concat(monoMethod.GetParameters().Select(it => it.ParameterType)).ToArray(); + var managedParameters = new List(); + if (!monoMethod.IsStatic) + managedParameters.Add(monoMethod.DeclaringType); + managedParameters.AddRange(monoMethod.GetParameters().Select(it => it.ParameterType)); var method = new DynamicMethod( "Trampoline_" + ExtractSignature(monoMethod) + monoMethod.DeclaringType + monoMethod.Name, MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, - monoMethod.ReturnType.NativeType(), nativeParameterTypes, + monoMethod.ReturnType.NativeType(), GetNativeParameterTypes(monoMethod), monoMethod.DeclaringType, true); - var signature = new DelegateSupport.MethodSignature(monoMethod, true); + var signature = new DelegateSupport.MethodSignature(monoMethod, !monoMethod.IsStatic); var delegateType = DelegateSupport.GetOrCreateDelegateType(signature, monoMethod); var body = method.GetILGenerator(); body.BeginExceptionBlock(); - body.Emit(OpCodes.Ldarg_0); - body.Emit(OpCodes.Call, - typeof(ClassInjectorBase).GetMethod(nameof(ClassInjectorBase.GetMonoObjectFromIl2CppPointer))!); - body.Emit(OpCodes.Castclass, monoMethod.DeclaringType); + if (!monoMethod.IsStatic) + { + body.Emit(OpCodes.Ldarg_0); + body.Emit(OpCodes.Call, + typeof(ClassInjectorBase).GetMethod(nameof(ClassInjectorBase.GetMonoObjectFromIl2CppPointer))!); + body.Emit(OpCodes.Castclass, monoMethod.DeclaringType); + } + + var indirectVariables = new LocalBuilder[managedParameters.Count]; - var indirectVariables = new LocalBuilder[managedParameters.Length]; + var argOffset = method.IsStatic ? 0 : 1; - for (var i = 1; i < managedParameters.Length; i++) + for (var i = argOffset; i < managedParameters.Count; i++) { var parameter = managedParameters[i]; if (parameter.IsSubclassOf(typeof(ValueType))) @@ -1012,7 +1032,7 @@ void HandleTypeConversion(Type type) body.Emit(OpCodes.Stloc, managedReturnVariable); } - for (var i = 1; i < managedParameters.Length; i++) + for (var i = argOffset; i < managedParameters.Count; i++) { var variable = indirectVariables[i]; if (variable == null)