/// <summary> /// Create an interface instance and context and whether to try and create a map /// </summary> /// <param name="name"></param> /// <param name="try_create_map"></param> /// <returns></returns> public static (IntPtr, IBaseInterface, bool) CreateInterface(string name, bool try_create_map = false) { // TODO: this really should "try" create map this should fail if it cant find a map and we want a map // Otherwise we are going to get unexpected behaviour // But then again some createinterfaces dont know whether they are going to be a map or not so... // Ensure that we are loaded before trying to query loaded plugins Loader.Load(); Plugin.InterfaceImpl impl = null; var is_map = try_create_map; if (try_create_map) { impl = FindInterfaceMap(name); } // Not trying to find a map or we couldnt find one (in the case that an interface is not servermapped) if (impl == null) { is_map = false; impl = FindImpl(name); } if (impl == null) { Log.WriteLine("Unable to find map or impl for interface {0}", name); return(IntPtr.Zero, null, false); } var iface = FindInterfaceDelegates(impl.name); if (iface == null) { Log.WriteLine("Unable to find delegates for interface that implements {0}", impl.name); return(IntPtr.Zero, null, false); } // Try to create a new context based on this interface + impl pair var(context, instance) = Create(iface, impl); return(context, instance, is_map); }
/// <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); }
/// <summary> /// Create an instance based on this implementation /// </summary> /// <param name="impl"></param> /// <returns></returns> public static object CreateInterfaceInstance(Plugin.InterfaceImpl impl) { return(Activator.CreateInstance(impl.this_type)); }
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; }