/// <summary> /// Create a new implementation context based on the delegate types and implementation /// </summary> /// <param name="iface"></param> /// <param name="impl"></param> /// <returns></returns> private static (IntPtr, IBaseInterface) Create(Plugin.InterfaceDelegates iface, Plugin.InterfaceImpl impl) { var instance = CreateInterfaceInstance(impl); var new_delegates = new List <Delegate>(); for (var i = 0; i < impl.methods.Count; i++) { // Find the delegate type that matches the method var mi = impl.methods[i]; var type = iface.delegate_types.Find(x => x.Name.Equals(mi.Name)); if (type == null) { Log.WriteLine("Unable to find delegate for {0} in {1}! (maybe you need to regen autogen?)", mi.Name, iface.name); return(IntPtr.Zero, null); } // Create new delegates that are bounded to this instance Delegate new_delegate; try { new_delegate = Delegate.CreateDelegate(type, instance, mi, true); } catch (Exception e) { Log.WriteLine("EXCEPTION whilst binding function {0}", mi.Name); throw e; } new_delegates.Add(new_delegate); } impl.stored_delegates.Add(new_delegates); // Create a new context (class) that mimics what the C++ compiler would generate // class: // vtable: // 1 // 2 // 3 // ... var ptr_size = Marshal.SizeOf(typeof(IntPtr)); // Allocate enough space for the new pointers in local memory var vtable = Marshal.AllocHGlobal(impl.methods.Count * ptr_size); for (var i = 0; i < new_delegates.Count; i++) { // Create all function pointers as neccessary Marshal.WriteIntPtr(vtable, i * ptr_size, Marshal.GetFunctionPointerForDelegate(new_delegates[i])); } impl.stored_function_pointers.Add(vtable); // create the context var new_context = Marshal.AllocHGlobal(ptr_size); // Write the pointer to the vtable at the address pointed to by new_context; Marshal.WriteIntPtr(new_context, vtable); return(new_context, (IBaseInterface)instance); }
public static void Load() { if (loaded) { return; } LoadedPlugins = new List <Plugin>(); foreach (var a in GetInterfaceAssemblies()) { var p = new Plugin { name = a.GetName().Name }; foreach (var t in a.GetTypes()) { if (IsInterfaceDelegate(t)) { var attribute = t.GetCustomAttribute <DelegateAttribute>(); var name = attribute.Name; var new_interface = new Plugin.InterfaceDelegates { name = name }; Log.WriteLine("Found interface delegates \"{0}\"", name); var types = t.GetNestedTypes(BindingFlags.Public); foreach (var type in types) { // Filter out types that are not delegates if (type.IsSubclassOf(typeof(System.Delegate))) { new_interface.delegate_types.Add(type); } } // Just assume all members are delegate types p.interface_delegates.Add(new_interface); } else if (IsInterfaceMap(t)) { var attribute = t.GetCustomAttribute <MapAttribute>(); var name = attribute.Name; var new_interface_map = new Plugin.InterfaceMap { name = name, this_type = t, methods = InterfaceMethodsForType(t), }; Log.WriteLine("Found interface map \"{0}\"", name); p.interface_maps.Add(new_interface_map); } else if (IsInterfaceImpl(t)) { var attribute = t.GetCustomAttribute <ImplAttribute>(); var name = attribute.Name; var new_interface_impl = new Plugin.InterfaceImpl { name = name, this_type = t, methods = InterfaceMethodsForType(t) }; Log.WriteLine("Found interface impl \"{0}\"", name); p.interface_impls.Add(new_interface_impl); } } LoadedPlugins.Add(p); } loaded = true; return; }