// // Mono.VisualC.Interop.ABI.VTable.cs: abstract vtable // // Author: // Alexander Corrado (alexander.corrado@gmail.com) // // Copyright (C) 2010 Alexander Corrado // using System; using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; using System.Runtime.InteropServices; namespace Mono.VisualC.Interop.ABI { public delegate VTable MakeVTableDelegate (IList delegateTypes, Delegate [] overrides); // TODO: RTTI .. support virtual inheritance public abstract class VTable : IDisposable { public static MakeVTableDelegate DefaultImplementation = VTableManaged.Implementation; protected IntPtr basePtr, vtPtr; // FIXME: Either make this a lazy list that only generates the delegate type if // it is needed, and/or cache generated delegate types (see FIXME in CppAbi::DefineVTableDelegate) protected IList delegate_types; // The Length of the array will be equal to the number of entries in the vtable; // entries that aren't overridden will be NULL. protected Delegate [] overrides; public virtual int EntryCount { get { return overrides.Length; } } public virtual int EntrySize { get { return Marshal.SizeOf (typeof (IntPtr)); } } public abstract MethodInfo PrepareVirtualCall (MethodInfo target, CallingConvention? callingConvention, ILGenerator callsite, LocalBuilder nativePtr, FieldInfo vtableField, int vtableIndex); // Subclasses must allocate vtPtr! public VTable (IList delegateTypes, Delegate [] overrides) { this.delegate_types = delegateTypes; this.overrides = overrides; this.basePtr = IntPtr.Zero; this.vtPtr = IntPtr.Zero; } protected virtual void WriteOverrides (int offset) { IntPtr vtEntryPtr; for (int i = 0; i < EntryCount; i++) { if (overrides [i] != null) // managed override vtEntryPtr = Marshal.GetFunctionPointerForDelegate (overrides [i]); else vtEntryPtr = IntPtr.Zero; Marshal.WriteIntPtr (vtPtr, offset, vtEntryPtr); offset += EntrySize; } } public virtual void InitInstance (IntPtr instance) { if (basePtr == IntPtr.Zero) { basePtr = Marshal.ReadIntPtr (instance); if ((basePtr != IntPtr.Zero) && (basePtr != vtPtr)) { int offset = 0; for (int i = 0; i < EntryCount; i++) { if (overrides [i] == null) Marshal.WriteIntPtr (vtPtr, offset, Marshal.ReadIntPtr (basePtr, offset)); offset += EntrySize; } } } Marshal.WriteIntPtr (instance, vtPtr); } public virtual void ResetInstance (IntPtr instance) { Marshal.WriteIntPtr (instance, basePtr); } public IntPtr Pointer { get { return vtPtr; } } protected virtual void Dispose (bool disposing) { if (vtPtr != IntPtr.Zero) { Marshal.FreeHGlobal (vtPtr); vtPtr = IntPtr.Zero; } } // TODO: This WON'T usually be called because VTables are associated with classes // (not instances) and managed C++ class wrappers are staticly held? public void Dispose () { Dispose (true); GC.SuppressFinalize (this); } ~VTable () { Dispose (false); } public static bool BindToSignatureAndAttribute (MemberInfo member, object obj) { bool result = BindToSignature (member, obj); if (member.GetCustomAttributes (typeof (OverrideNativeAttribute), true).Length != 1) return false; return result; } public static bool BindToSignature (MemberInfo member, object obj) { MethodInfo imethod = (MethodInfo) obj; MethodInfo candidate = (MethodInfo) member; if (!candidate.Name.Equals (imethod.Name)) return false; ParameterInfo[] invokeParams = imethod.GetParameters (); ParameterInfo[] methodParams = candidate.GetParameters (); if (invokeParams.Length == methodParams.Length) { for (int i = 0; i < invokeParams.Length; i++) { if (!invokeParams [i].ParameterType.IsAssignableFrom (methodParams [i].ParameterType)) return false; } } else if (invokeParams.Length == methodParams.Length + 1) { for (int i = 1; i < invokeParams.Length; i++) { if (!invokeParams [i].ParameterType.IsAssignableFrom (methodParams [i - 1].ParameterType)) return false; } } else return false; return true; } } }