A game framework written with osu! in mind.
at master 61 lines 3.0 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using System; 5using System.Runtime.InteropServices; 6 7namespace osu.Framework.Platform.MacOS.Native 8{ 9 internal static class Class 10 { 11 [DllImport(Cocoa.LIB_OBJ_C)] 12 private static extern IntPtr class_replaceMethod(IntPtr classHandle, IntPtr selector, IntPtr method, string types); 13 14 [DllImport(Cocoa.LIB_OBJ_C)] 15 private static extern IntPtr class_getInstanceMethod(IntPtr classHandle, IntPtr selector); 16 17 [DllImport(Cocoa.LIB_OBJ_C)] 18 private static extern void method_exchangeImplementations(IntPtr method1, IntPtr method2); 19 20 [DllImport(Cocoa.LIB_OBJ_C)] 21 private static extern IntPtr objc_getClass(string name); 22 23 public static IntPtr Get(string name) 24 { 25 var id = objc_getClass(name); 26 if (id == IntPtr.Zero) 27 throw new ArgumentException("Unknown class: " + name); 28 29 return id; 30 } 31 32 public static void RegisterMethod(IntPtr handle, Delegate action, string selector, string typeString) => 33 class_replaceMethod(handle, Selector.Get(selector), Marshal.GetFunctionPointerForDelegate(action), typeString); 34 35 /// <summary> 36 /// Performs method swizzling for a given selector, using a given delegate implementation. 37 /// </summary> 38 /// <remarks> 39 /// This essentially adds a new Objective-C method, then swaps the implementation with an existing one. 40 /// Returns a selector to the newly registered method, which has the original implementation of 41 /// <paramref name="selector"/> before swizzling. 42 /// https://nshipster.com/method-swizzling/ 43 /// </remarks> 44 /// <param name="classHandle">The Objective-C class which should have a method swizzled.</param> 45 /// <param name="selector">The selector to swizzle.</param> 46 /// <param name="typeString">The type encoding of the selector.</param> 47 /// <param name="action">The delegate to use as the new implementation.</param> 48 /// <returns>A selector for the newly registered method, containing the old implementation.</returns> 49 public static IntPtr SwizzleMethod(IntPtr classHandle, string selector, string typeString, Delegate action) 50 { 51 var targetSelector = Selector.Get(selector); 52 var targetMethod = class_getInstanceMethod(classHandle, targetSelector); 53 var newMethodImplementation = Marshal.GetFunctionPointerForDelegate(action); 54 var newSelector = Selector.Get($"orig_{selector}"); 55 class_replaceMethod(classHandle, newSelector, newMethodImplementation, typeString); 56 var newMethod = class_getInstanceMethod(classHandle, newSelector); 57 method_exchangeImplementations(targetMethod, newMethod); 58 return newSelector; 59 } 60 } 61}