#if CPP using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.InteropServices; namespace UnityExplorer.Core.Runtime.Il2Cpp { [SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "External methods")] public static class ICallManager { [DllImport("GameAssembly", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern IntPtr il2cpp_resolve_icall([MarshalAs(UnmanagedType.LPStr)] string name); private static readonly Dictionary iCallCache = new Dictionary(); /// /// Helper to get and cache an iCall by providing the signature (eg. "UnityEngine.Resources::FindObjectsOfTypeAll"). /// /// The Type of Delegate to provide for the iCall. /// The signature of the iCall you want to get. /// The delegate if successful. /// If the iCall could not be found. public static T GetICall(string signature) where T : Delegate { if (iCallCache.ContainsKey(signature)) return (T)iCallCache[signature]; IntPtr ptr = il2cpp_resolve_icall(signature); if (ptr == IntPtr.Zero) throw new MissingMethodException($"Could not find any iCall with the signature '{signature}'!"); Delegate iCall = Marshal.GetDelegateForFunctionPointer(ptr, typeof(T)); iCallCache.Add(signature, iCall); return (T)iCall; } private static readonly Dictionary s_unreliableCache = new Dictionary(); /// /// Get an iCall which may be one of multiple different signatures (ie, it changed in different Unity versions). /// Each possible signature must have the same Type pattern, it can only vary by name. /// public static T GetICallUnreliable(IEnumerable possibleSignatures) where T : Delegate { // use the first possible signature as the 'key'. string key = possibleSignatures.First(); if (s_unreliableCache.ContainsKey(key)) return (T)s_unreliableCache[key]; T iCall; IntPtr ptr; foreach (var sig in possibleSignatures) { ptr = il2cpp_resolve_icall(sig); if (ptr != IntPtr.Zero) { iCall = (T)Marshal.GetDelegateForFunctionPointer(ptr, typeof(T)); s_unreliableCache.Add(key, iCall); return iCall; } } throw new MissingMethodException($"Could not find any iCall from list of provided signatures starting with '{key}'!"); } } } #endif