diff --git a/Mono.VisualC.Interop/ABI/CppAbi.cs b/Mono.VisualC.Interop/ABI/CppAbi.cs index 779ba2f2..cbe9d092 100644 --- a/Mono.VisualC.Interop/ABI/CppAbi.cs +++ b/Mono.VisualC.Interop/ABI/CppAbi.cs @@ -17,9 +17,11 @@ using System.Runtime.InteropServices; namespace Mono.VisualC.Interop.ABI { - //TODO: Exception handling, operator overloading etc. - //TODO: Allow interface to override default calling convention - public abstract class CppAbi { + //FIXME: Exception handling, operator overloading etc. + //FIXME: Allow interface to override default calling convention + //FIXME: Better interface validation- for example, throw exception + // when [VirtualDestructor] is applied to base interface but not derived + public abstract partial class CppAbi { protected ModuleBuilder impl_module; protected TypeBuilder impl_type; @@ -31,12 +33,46 @@ namespace Mono.VisualC.Interop.ABI { protected FieldBuilder vtable_field, native_size_field; protected ILGenerator ctor_il; - // default settings that subclasses can override: + // Default settings that subclasses can override: protected MakeVTableDelegate make_vtable_method = VTable.DefaultImplementation; protected MemberFilter vtable_override_filter = VTable.BindToSignatureAndAttribute; + // These methods might be more commonly overridden for a given C++ ABI: + + public virtual MethodType GetMethodType (MethodInfo imethod) + { + if (imethod.Name.Equals (class_name)) + return MethodType.NativeCtor; + else if (imethod.Name.Equals ("Alloc")) + return MethodType.ManagedAlloc; + else if (imethod.Name.Equals ("Destruct")) + return MethodType.NativeDtor; + + return MethodType.Native; + } + + public virtual int FieldOffsetPadding { + get { return Marshal.SizeOf (typeof (IntPtr)); } + } + + protected virtual int NativeSize { + get { + // By default: native size = C++ class size + field offset padding (usually just vtable pointer) + // FIXME: Only include vtable ptr if there are virtual functions? Here I guess it doesn't really matter, + // we're just allocing extra memory. + return Marshal.SizeOf (layout_type) + FieldOffsetPadding; + } + } + + // The members below must be implemented for a given C++ ABI: + + public abstract string GetMangledMethodName (MethodInfo methodInfo); + public abstract CallingConvention? GetCallingConvention (MethodInfo methodInfo); + + private struct EmptyNativeLayout { } + + // The ImplementClass overrides are the main entry point to the Abi API: - private struct EmptyNativeLayout { } public Iface ImplementClass (Type wrapperType, string lib, string className) { return this.ImplementClass (wrapperType, lib, className); @@ -55,40 +91,33 @@ namespace Mono.VisualC.Interop.ABI { DefineImplType (); - var properties = ( // get all properties defined on the interface - from property in interface_type.GetProperties () - select property - ).Union ( // ... as well as those defined on inherited interfaces - from iface in interface_type.GetInterfaces () - from property in iface.GetProperties () - select property - ); - - var methods = ( // get all methods defined on inherited interfaces first - from iface in interface_type.GetInterfaces () - from method in iface.GetMethods () - select method - ).Union ( // ... as well as those defined on this interface - from method in interface_type.GetMethods () - orderby method.MetadataToken - select method - ); - - // TODO: If a method in a base class interface is defined again in a child class - // interface with exactly the same signature, it will prolly share a vtable slot????? - - // first, pull in all virtual methods from base classes - var baseVirtualMethods = GetBaseVirtualMethods (interface_type); - var virtualMethods = baseVirtualMethods.Concat ( // now create managed overrides for virtuals in this class - from method in methods - where Modifiers.IsVirtual (method) - orderby method.MetadataToken - select GetManagedOverrideTrampoline (method, vtable_override_filter) - ); + var properties = GetProperties (); + var methods = GetMethods (interface_type); + var bases = GetBasesRecursive (interface_type); + + IEnumerable baseVirtualMethods = Enumerable.Empty (); + + if (bases.Any ()) // FIXME: We're assuming that first declared base is non-virtual primary base (and thus shares primary vtable) + baseVirtualMethods = from method in GetVirtualMethods (bases.First ()) + select method; + + var vtableSlots = from method in baseVirtualMethods.Concat (GetVirtualMethods (interface_type)) + let delegateType = DefineVTableDelegate (method) + select new { DelegateType = delegateType, + Override = GetManagedOverrideTrampoline (method, delegateType, vtable_override_filter) + }; + + var virtualDtorSlots = from iface in bases.With (interface_type) + where iface.IsDefined (typeof (VirtualDestructorAttribute), false) + from i in new int [] { 0, 1 } + select new { DelegateType = (Type)null, Override = (Delegate)null }; + + vtableSlots = vtableSlots.Concat (virtualDtorSlots); // ONLY make vtable if there are virtual methods - if (virtualMethods.Any ()) - vtable = make_vtable_method (virtualMethods.ToArray ()); + if (vtableSlots.Any ()) + vtable = make_vtable_method (vtableSlots.Select (s => s.DelegateType).ToList (), + vtableSlots.Select (s => s.Override).ToArray ()); else vtable = null; @@ -96,13 +125,9 @@ namespace Mono.VisualC.Interop.ABI { // Implement all methods foreach (var method in methods) { - // Skip over special methods like property accessors -- properties will be handled later - if (method.IsSpecialName) - continue; - DefineMethod (method, vtableIndex); - if (Modifiers.IsVirtual (method)) + if (IsVirtual (method)) vtableIndex++; } @@ -114,62 +139,67 @@ namespace Mono.VisualC.Interop.ABI { return (Iface)Activator.CreateInstance (impl_type.CreateType (), vtable, NativeSize); } - protected virtual IEnumerable GetBaseVirtualMethods (Type searchStart) + protected virtual IEnumerable GetProperties () + { + return ( // get all properties defined on the interface + from property in interface_type.GetProperties () + select property + ).Union ( // ... as well as those defined on inherited interfaces + from iface in interface_type.GetInterfaces () + from property in iface.GetProperties () + select property + ); + } + + protected virtual IEnumerable GetMethods (Type interfaceType) + { + // get all methods defined on inherited interfaces first + var methods = ( + from iface in interfaceType.GetInterfaces () + from method in iface.GetMethods () + where !method.IsSpecialName + select method + ).Concat ( + from method in interfaceType.GetMethods () + where !method.IsSpecialName + orderby method.MetadataToken + select method + ); + + return methods; + } + + protected virtual IEnumerable GetVirtualMethods (Type interfaceType) + { + var delegates = ( + from method in GetMethods (interfaceType) + where IsVirtual (method) + select method + ); + return delegates; + } + + protected virtual IEnumerable GetBasesRecursive (Type searchStart) { - var bases = from baseIface in searchStart.GetInterfaces () - where baseIface.Name.Equals ("Base`1") - from iface in baseIface.GetGenericArguments () - select iface; - - List virtualMethods = new List (); - - foreach (var iface in bases) - { - virtualMethods.AddRange (GetBaseVirtualMethods (iface)); - - var methods = from method in iface.GetMethods () - where Modifiers.IsVirtual (method) - orderby method.MetadataToken - select GetManagedOverrideTrampoline (method, vtable_override_filter); - - virtualMethods.AddRange (methods); - } - - return virtualMethods; + var immediateBases = ( + from baseIface in searchStart.GetInterfaces () + where baseIface.Name.Equals ("Base`1") + from iface in baseIface.GetGenericArguments () + select iface + ); + + if (!immediateBases.Any ()) + return Enumerable.Empty (); + + List allBases = new List (); + foreach (var baseInterface in immediateBases) { + allBases.AddRange (GetBasesRecursive (baseInterface)); + allBases.Add (baseInterface); + } + + return allBases; } - // These methods might be more commonly overridden for a given C++ ABI: - - public virtual MethodType GetMethodType (MethodInfo imethod) - { - if (imethod.Name.Equals (class_name)) - return MethodType.NativeCtor; - else if (imethod.Name.Equals ("Alloc")) - return MethodType.ManagedAlloc; - else if (imethod.Name.Equals ("Destruct")) - return MethodType.NativeDtor; - - return MethodType.Native; - } - - public virtual int FieldOffsetPadding { - get { return Marshal.SizeOf (typeof (IntPtr)); } - } - - protected virtual int NativeSize { - get { - // By default: native size = C++ class size + field offset padding (usually just vtable pointer) - // TODO: Only include vtable ptr if there are virtual functions? Here I guess it doesn't really matter, - // we're just allocing extra memory. - return Marshal.SizeOf (layout_type) + FieldOffsetPadding; - } - } - - // The members below must be implemented for a given C++ ABI: - - public abstract string GetMangledMethodName (MethodInfo methodInfo); - public abstract CallingConvention GetCallingConvention (MethodInfo methodInfo); - protected virtual void DefineImplType () { string implTypeName = interface_type.Name + "_" + layout_type.Name + "_" + this.GetType ().Name + "_Impl"; @@ -198,7 +228,7 @@ namespace Mono.VisualC.Interop.ABI { { // 0. Introspect method MethodType methodType = GetMethodType (interfaceMethod); - Type[] parameterTypes = Util.GetMethodParameterTypes (interfaceMethod, false); + Type[] parameterTypes = Util.GetMethodParameterTypes (interfaceMethod); // 1. Generate managed trampoline to call native method MethodBuilder trampoline = GetMethodBuilder (interfaceMethod); @@ -207,7 +237,7 @@ namespace Mono.VisualC.Interop.ABI { if (methodType == MethodType.NoOp) { // return NULL if method is supposed to return a value - // TODO: this will make value types explode? + // FIXME: this will make value types explode? if (!interfaceMethod.ReturnType.Equals (typeof (void))) il.Emit (OpCodes.Ldnull); il.Emit (OpCodes.Ret); @@ -223,7 +253,7 @@ namespace Mono.VisualC.Interop.ABI { LocalBuilder nativePtr = null; // If we're not a static method, do the following ... - if (!Modifiers.IsStatic (interfaceMethod)) + if (!IsStatic (interfaceMethod)) { isStatic = false; if (parameterTypes.Length < 1) @@ -237,23 +267,28 @@ namespace Mono.VisualC.Interop.ABI { } MethodInfo nativeMethod; - if (Modifiers.IsVirtual (interfaceMethod)) + bool isVirtual; + + if (IsVirtual (interfaceMethod)) { + isVirtual = true; nativeMethod = vtable.PrepareVirtualCall (interfaceMethod, GetCallingConvention (interfaceMethod), il, nativePtr, vtable_field, index); - else + } else { + isVirtual = false; nativeMethod = GetPInvokeForMethod (interfaceMethod); + } switch (methodType) { case MethodType.NativeCtor: - EmitConstruct (il, nativeMethod, parameterTypes.Length, nativePtr); + EmitConstruct (il, nativeMethod, parameterTypes, nativePtr); break; case MethodType.NativeDtor: - EmitDestruct (il, nativeMethod, parameterTypes.Length, cppInstancePtr, nativePtr); + EmitDestruct (il, nativeMethod, isVirtual, parameterTypes, cppInstancePtr, nativePtr); break; default: // regular native method - EmitCallNative (il, nativeMethod, isStatic, parameterTypes.Length, nativePtr); + EmitCallNative (il, nativeMethod, isStatic, parameterTypes, nativePtr); break; } @@ -320,7 +355,7 @@ namespace Mono.VisualC.Interop.ABI { * Implements the managed trampoline that will be invoked from the vtable by native C++ code when overriding * the specified C++ virtual method with the specified managed one. */ - protected virtual Delegate GetManagedOverrideTrampoline (MethodInfo interfaceMethod, MemberFilter binder) + protected virtual Delegate GetManagedOverrideTrampoline (MethodInfo interfaceMethod, Type delegateType, MemberFilter binder) { if (wrapper_type == null) return null; @@ -329,8 +364,7 @@ namespace Mono.VisualC.Interop.ABI { if (targetMethod == null) return null; - Type delegateType = Util.GetDelegateTypeForMethodInfo (impl_module, interfaceMethod, GetCallingConvention (interfaceMethod)); - Type[] parameterTypes = Util.GetMethodParameterTypes (interfaceMethod, true); + Type[] parameterTypes = GetParameterTypesForPInvoke (interfaceMethod).ToArray (); // TODO: According to http://msdn.microsoft.com/en-us/library/w16z8yc4.aspx // The dynamic method created with this constructor has access to public and internal members of all the types contained in module m. @@ -385,7 +419,7 @@ namespace Mono.VisualC.Interop.ABI { protected virtual MethodBuilder GetMethodBuilder (MethodInfo interfaceMethod) { - Type[] parameterTypes = Util.GetMethodParameterTypes (interfaceMethod, false); + Type[] parameterTypes = Util.GetMethodParameterTypes (interfaceMethod); MethodBuilder methodBuilder = impl_type.DefineMethod (interfaceMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual, interfaceMethod.ReturnType, parameterTypes); Util.ApplyMethodParameterAttributes (interfaceMethod, methodBuilder, false); @@ -401,17 +435,48 @@ namespace Mono.VisualC.Interop.ABI { if (entryPoint == null) throw new NotSupportedException ("Could not mangle method name."); - Type[] parameterTypes = Util.GetMethodParameterTypes (signature, true); + Type[] parameterTypes = GetParameterTypesForPInvoke (signature).ToArray (); MethodBuilder builder = impl_type.DefinePInvokeMethod ("__$" + signature.Name + "_Impl", library, entryPoint, MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.PinvokeImpl, - CallingConventions.Any, signature.ReturnType, parameterTypes, - GetCallingConvention (signature), CharSet.Ansi); + CallingConventions.Standard, signature.ReturnType, parameterTypes, + GetCallingConvention (signature).Value, CharSet.Ansi); builder.SetImplementationFlags (builder.GetMethodImplementationFlags () | MethodImplAttributes.PreserveSig); Util.ApplyMethodParameterAttributes (signature, builder, true); return builder; } + protected virtual Type DefineVTableDelegate (MethodInfo targetMethod) + { + // FIXME: Actually return the same delegate type instead of creating a new one if + // a suitable type already exists?? + CallingConvention? callingConvention = GetCallingConvention (targetMethod); + string delTypeName = "_" + targetMethod.DeclaringType.Name + "_" + targetMethod.Name + "_VTdel"; + while (CppLibrary.interopModule.GetType (delTypeName) != null) + delTypeName += "_"; + + TypeAttributes typeAttr = TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass; + TypeBuilder del = CppLibrary.interopModule.DefineType (delTypeName, typeAttr, typeof(MulticastDelegate)); + + if (callingConvention.HasValue) { + ConstructorInfo ufpa = typeof (UnmanagedFunctionPointerAttribute).GetConstructor (new Type [] { typeof (CallingConvention) }); + CustomAttributeBuilder unmanagedPointer = new CustomAttributeBuilder (ufpa, new object [] { callingConvention.Value }); + del.SetCustomAttribute (unmanagedPointer); + } + + MethodAttributes ctorAttr = MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public; + ConstructorBuilder ctor = del.DefineConstructor (ctorAttr, CallingConventions.Standard, new Type[] { typeof(object), typeof(System.IntPtr) }); + ctor.SetImplementationFlags (MethodImplAttributes.Runtime | MethodImplAttributes.Managed); + + Type[] parameterTypes = GetParameterTypesForPInvoke (targetMethod).ToArray (); + MethodAttributes methodAttr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual; + + MethodBuilder invokeMethod = del.DefineMethod ("Invoke", methodAttr, targetMethod.ReturnType, parameterTypes); + invokeMethod.SetImplementationFlags (MethodImplAttributes.Runtime | MethodImplAttributes.Managed); + + return del.CreateType (); + } + /** * Emits IL to allocate the memory for a new instance of the C++ class. * To complete method, emit OpCodes.Ret. @@ -441,29 +506,37 @@ namespace Mono.VisualC.Interop.ABI { new Type[] { typeof (int) }, null)); } - protected virtual void EmitConstruct (ILGenerator il, MethodInfo nativeMethod, int parameterCount, + protected virtual void EmitConstruct (ILGenerator il, MethodInfo nativeMethod, Type [] parameterTypes, LocalBuilder nativePtr) { - EmitCallNative (il, nativeMethod, false, parameterCount, nativePtr); + EmitCallNative (il, nativeMethod, false, parameterTypes, nativePtr); EmitInitVTable (il, nativePtr); } - protected virtual void EmitDestruct (ILGenerator il, MethodInfo nativeMethod, int parameterCount, + protected virtual void EmitDestruct (ILGenerator il, MethodInfo nativeMethod, bool isVirtual, Type [] parameterTypes, LocalBuilder cppInstancePtr, LocalBuilder nativePtr) { // bail if we weren't alloc'd by managed code Label bail = il.DefineLabel (); + Label retNormal = il.DefineLabel (); il.Emit (OpCodes.Ldloca_S, cppInstancePtr); - il.Emit (OpCodes.Brfalse_S, bail); + il.Emit (OpCodes.Brfalse_S, bail); // <- FIXME? (would this ever branch?) il.Emit (OpCodes.Ldloca_S, cppInstancePtr); il.Emit (OpCodes.Call, typeof (CppInstancePtr).GetProperty ("IsManagedAlloc").GetGetMethod ()); il.Emit (OpCodes.Brfalse_S, bail); EmitResetVTable (il, nativePtr); - EmitCallNative (il, nativeMethod, false, parameterCount, nativePtr); + EmitCallNative (il, nativeMethod, false, parameterTypes, nativePtr); + il.Emit (OpCodes.Br_S, retNormal); + // before we bail, we have to pop the vtbl delegate from the stack if this + // is a virtual destructor il.MarkLabel (bail); + if (isVirtual) + il.Emit (OpCodes.Pop); + + il.MarkLabel (retNormal); } /** @@ -471,7 +544,7 @@ namespace Mono.VisualC.Interop.ABI { * GetPInvokeForMethod or the MethodInfo of a vtable method. * To complete method, emit OpCodes.Ret. */ - protected virtual void EmitCallNative (ILGenerator il, MethodInfo nativeMethod, bool isStatic, int parameterCount, + protected virtual void EmitCallNative (ILGenerator il, MethodInfo nativeMethod, bool isStatic, Type [] parameterTypes, LocalBuilder nativePtr) { int argLoadStart = 1; // For static methods, just strip off arg0 (.net this pointer) @@ -480,12 +553,33 @@ namespace Mono.VisualC.Interop.ABI { argLoadStart = 2; // For instance methods, strip off CppInstancePtr and pass the corresponding IntPtr il.Emit (OpCodes.Ldloc_S, nativePtr); } - for (int i = argLoadStart; i <= parameterCount; i++) - il.Emit (OpCodes.Ldarg, i); + for (int i = argLoadStart; i <= parameterTypes.Length; i++) { + EmitSpecialParameterMarshal (il, parameterTypes [i - 1]); + il.Emit (OpCodes.Ldarg, i); + } il.Emit (OpCodes.Call, nativeMethod); } + // Note: when this is modified, usually GetParameterTypesForPInvoke types should be updated too + protected virtual void EmitSpecialParameterMarshal (ILGenerator il, Type parameterType) + { + // auto marshal bool to C++ bool type (0 = false , 1 = true ) + // auto marshal ICppObject + } + + protected virtual IEnumerable GetParameterTypesForPInvoke (MethodInfo method) + { + var originalTypes = Util.GetMethodParameterTypes (method); + + var pinvokeTypes = originalTypes.Transform ( + // CppInstancePtr implements ICppObject + For.InputsWhere ((Type t) => typeof (ICppObject).IsAssignableFrom (t)).Emit (typeof (IntPtr)), + For.UnmatchedInput ().Emit (t => t) + ); + return pinvokeTypes; + } + /** * Emits IL to set the vtable pointer of the instance (if class has a vtable). * This should usually happen in the managed wrapper of the C++ instance constructor. diff --git a/Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs b/Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs index 93492c53..5c75af13 100644 --- a/Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs +++ b/Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs @@ -21,7 +21,7 @@ namespace Mono.VisualC.Interop.ABI { { } - public override CallingConvention GetCallingConvention (MethodInfo methodInfo) + public override CallingConvention? GetCallingConvention (MethodInfo methodInfo) { return CallingConvention.Cdecl; } @@ -50,13 +50,13 @@ namespace Mono.VisualC.Interop.ABI { } nm.Append ('E'); - int argStart = (Modifiers.IsStatic (methodInfo)? 0 : 1); + int argStart = (IsStatic (methodInfo)? 0 : 1); if (parameters.Length == argStart) // no args (other than C++ "this" object) nm.Append ('v'); else for (int i = argStart; i < parameters.Length; i++) - nm.Append (GetTypeCode (Modifiers.GetMangleType (parameters[i]))); + nm.Append (GetTypeCode (GetMangleType (parameters [i], parameters [i].ParameterType))); return nm.ToString (); } diff --git a/Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs b/Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs index 82e8e3f3..c2542ea9 100644 --- a/Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs +++ b/Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs @@ -8,23 +8,27 @@ // using System; +using System.Linq; using System.Text; using System.Reflection; +using System.Collections.Generic; using System.Runtime.InteropServices; using Mono.VisualC.Interop; namespace Mono.VisualC.Interop.ABI { + + // FIXME: No 64-bit support public class MsvcAbi : CppAbi { public MsvcAbi () { } - public override CallingConvention GetCallingConvention (MethodInfo methodInfo) + public override CallingConvention? GetCallingConvention (MethodInfo methodInfo) { - // FIXME: Varargs methods..? + // FIXME: Varargs methods ... ? - if (Modifiers.IsStatic (methodInfo)) + if (IsStatic (methodInfo)) return CallingConvention.Cdecl; else return CallingConvention.ThisCall; @@ -38,30 +42,37 @@ namespace Mono.VisualC.Interop.ABI { StringBuilder nm = new StringBuilder ("?", 30); + if (methodType == MethodType.NativeCtor) + nm.Append ("?0"); + else if (methodType == MethodType.NativeDtor) + nm.Append ("?1"); + else + nm.Append (methodName).Append ('@'); + // FIXME: This has to include not only the name of the immediate containing class, // but also all names of containing classes and namespaces up the hierarchy. - nm.Append (methodName).Append ('@').Append (class_name).Append ("@@"); + nm.Append (class_name).Append ("@@"); // function modifiers are a matrix of consecutive uppercase letters // depending on access type and virtual (far)/static (far)/far modifiers // first, access type char funcModifier = 'Q'; // (public) - if (Modifiers.IsProtected (methodInfo)) + if (IsProtected (methodInfo)) funcModifier = 'I'; - else if (Modifiers.IsPrivate (methodInfo)) + else if (IsPrivate (methodInfo)) // (probably don't need this) funcModifier = 'A'; // now, offset based on other modifiers - if (Modifiers.IsStatic (methodInfo)) - funcModifier += 2; - else if (Modifiers.IsVirtual (methodInfo)) // (do we need this?) - funcModifier += 4; + if (IsStatic (methodInfo)) + funcModifier += (char)2; + else if (IsVirtual (methodInfo) || IsVirtualDtor (methodInfo)) + funcModifier += (char)4; nm.Append (funcModifier); // FIXME: deal with storage classes for "this" i.e. the "const" in -> int foo () const; - if (!Modifiers.IsStatic (methodInfo)) + if (!IsStatic (methodInfo)) nm.Append ('A'); switch (GetCallingConvention (methodInfo)) { @@ -80,9 +91,100 @@ namespace Mono.VisualC.Interop.ABI { } // FIXME: handle const, volatile modifiers on return type - nm.Append ("?A"); + // FIXME: the manual says this is only omitted for simple types.. are we doing the right thing here? + CppType returnType = GetMangleType (methodInfo.ReturnTypeCustomAttributes, methodInfo.ReturnType); + if (returnType.ElementType == CppTypes.Class || + returnType.ElementType == CppTypes.Struct || + returnType.ElementType == CppTypes.Union) + nm.Append ("?A"); + + if (methodType == MethodType.NativeCtor || methodType == MethodType.NativeDtor) + nm.Append ('@'); + else + nm.Append (GetTypeCode (returnType)); - } + int argStart = (IsStatic (methodInfo)? 0 : 1); + if (parameters.Length == argStart) { // no args (other than C++ "this" object) + nm.Append ("XZ"); + return nm.ToString (); + } else + for (int i = argStart; i < parameters.Length; i++) + nm.Append (GetTypeCode (GetMangleType (parameters [i], parameters [i].ParameterType))); + + nm.Append ("@Z"); + return nm.ToString (); + } + + public virtual string GetTypeCode (CppType mangleType) + { + CppTypes element = mangleType.ElementType; + IEnumerable modifiers = mangleType.Modifiers; + + StringBuilder code = new StringBuilder (); + + var ptr = For.AnyInputIn (CppModifiers.Pointer); + var ptrRefOrArray = For.AnyInputIn (CppModifiers.Pointer, CppModifiers.Reference, CppModifiers.Array); + + var modifierCode = modifiers.Reverse ().Transform ( + + Choose.TopOne ( + For.AllInputsIn (CppModifiers.Const, CppModifiers.Volatile).InAnyOrder ().After (ptrRefOrArray).Emit ('D'), + For.AnyInputIn (CppModifiers.Const).After (ptrRefOrArray).Emit ('B'), + For.AnyInputIn (CppModifiers.Volatile).After (ptrRefOrArray).Emit ('C'), + For.AnyInput ().After (ptrRefOrArray).Emit ('A') + ), + + For.AnyInputIn (CppModifiers.Array).Emit ('Q'), + For.AnyInputIn (CppModifiers.Reference).Emit ('A'), + + Choose.TopOne ( + ptr.After ().AllInputsIn (CppModifiers.Const, CppModifiers.Volatile).InAnyOrder ().Emit ('S'), + ptr.After ().AnyInputIn (CppModifiers.Const).Emit ('Q'), + ptr.After ().AnyInputIn (CppModifiers.Volatile).Emit ('R'), + ptr.Emit ('P') + ), + + ptrRefOrArray.AtEnd ().Emit ('A') + ); + code.Append (modifierCode.ToArray ()); + + switch (element) { + case CppTypes.Void: + code.Append ('X'); + break; + case CppTypes.Int: + code.Append (modifiers.Transform ( + For.AllInputsIn (CppModifiers.Unsigned, CppModifiers.Short).InAnyOrder ().Emit ('G') + ).DefaultIfEmpty ('H').ToArray ()); + break; + case CppTypes.Char: + code.Append ('D'); + break; + case CppTypes.Class: + code.Append ('V'); + code.Append(mangleType.ElementTypeName); + code.Append ("@@"); + break; + case CppTypes.Struct: + code.Append ('U'); + code.Append(mangleType.ElementTypeName); + code.Append ("@@"); + break; + case CppTypes.Union: + code.Append ('T'); + code.Append(mangleType.ElementTypeName); + code.Append ("@@"); + break; + case CppTypes.Enum: + code.Append ("W4"); + code.Append(mangleType.ElementTypeName); + code.Append ("@@"); + break; + + } + + return code.ToString (); + } } } diff --git a/Mono.VisualC.Interop/ABI/Impl/VirtualOnlyAbi.cs b/Mono.VisualC.Interop/ABI/Impl/VirtualOnlyAbi.cs index 177d4eb3..cc819dd0 100644 --- a/Mono.VisualC.Interop/ABI/Impl/VirtualOnlyAbi.cs +++ b/Mono.VisualC.Interop/ABI/Impl/VirtualOnlyAbi.cs @@ -11,9 +11,8 @@ using System; using System.Reflection; using System.Reflection.Emit; using System.Runtime.InteropServices; -using Mono.VisualC.Interop.ABI; -namespace Mono.VisualC.Interop { +namespace Mono.VisualC.Interop.ABI { public class VirtualOnlyAbi : CppAbi { @@ -37,10 +36,10 @@ namespace Mono.VisualC.Interop { throw new NotSupportedException ("Name mangling is not supported by this class. All C++ interface methods must be declared virtual."); } - public override CallingConvention DefaultCallingConvention { - get { - throw new NotSupportedException ("This class does not support this property."); - } + public override CallingConvention? GetCallingConvention (MethodInfo methodInfo) + { + // Use platform default + return null; } } } diff --git a/Mono.VisualC.Interop/ABI/VTable.cs b/Mono.VisualC.Interop/ABI/VTable.cs index e8381b25..8203985e 100644 --- a/Mono.VisualC.Interop/ABI/VTable.cs +++ b/Mono.VisualC.Interop/ABI/VTable.cs @@ -15,21 +15,22 @@ using System.Reflection.Emit; using System.Runtime.InteropServices; namespace Mono.VisualC.Interop.ABI { - public delegate VTable MakeVTableDelegate (Delegate[] overrides); + public delegate VTable MakeVTableDelegate (IList delegateTypes, Delegate [] overrides); // TODO: RTTI .. support virtual inheritance public abstract class VTable : IDisposable { - // The COM-interop-based implemenation is the default because it offers better - // performance (I think?) than the fully-managed implementation. public static MakeVTableDelegate DefaultImplementation = VTableManaged.Implementation; protected IntPtr basePtr, vtPtr; - // This is a bit of a misnomer since 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; + // 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; } @@ -38,12 +39,13 @@ namespace Mono.VisualC.Interop.ABI { get { return Marshal.SizeOf (typeof (IntPtr)); } } - public abstract MethodInfo PrepareVirtualCall (MethodInfo target, CallingConvention callingConvention, ILGenerator callsite, + public abstract MethodInfo PrepareVirtualCall (MethodInfo target, CallingConvention? callingConvention, ILGenerator callsite, LocalBuilder nativePtr, FieldInfo vtableField, int vtableIndex); // Subclasses must allocate vtPtr! - public VTable (Delegate[] overrides) + public VTable (IList delegateTypes, Delegate [] overrides) { + this.delegate_types = delegateTypes; this.overrides = overrides; this.basePtr = IntPtr.Zero; this.vtPtr = IntPtr.Zero; diff --git a/Mono.VisualC.Interop/ABI/VTableCOM.cs b/Mono.VisualC.Interop/ABI/VTableCOM.cs index 954d41dd..a2fd9ba1 100644 --- a/Mono.VisualC.Interop/ABI/VTableCOM.cs +++ b/Mono.VisualC.Interop/ABI/VTableCOM.cs @@ -18,18 +18,12 @@ using System.Runtime.InteropServices; namespace Mono.VisualC.Interop.ABI { public class VTableCOM : VTable { - public static MakeVTableDelegate Implementation = (entries) => { return new VTableCOM (entries); }; - private VTableCOM (Delegate[] entries) : base(entries) + public static MakeVTableDelegate Implementation = (types, overrides) => { return new VTableCOM (types, overrides); }; + private VTableCOM (IList types, Delegate [] overrides) : base(types, overrides) { - int managedOverrides = (from entry in entries - where entry != null - select entry).Count(); - - vtPtr = Marshal.AllocHGlobal ((EntryCount + managedOverrides) * EntrySize); - WriteOverrides (0); } - public override MethodInfo PrepareVirtualCall (MethodInfo target, CallingConvention callingConvention, ILGenerator callsite, + public override MethodInfo PrepareVirtualCall (MethodInfo target, CallingConvention? callingConvention, ILGenerator callsite, LocalBuilder nativePtr, FieldInfo vtableField, int vtableIndex) { throw new System.NotImplementedException (); diff --git a/Mono.VisualC.Interop/ABI/VTableManaged.cs b/Mono.VisualC.Interop/ABI/VTableManaged.cs index 137a2ce0..ced963e2 100644 --- a/Mono.VisualC.Interop/ABI/VTableManaged.cs +++ b/Mono.VisualC.Interop/ABI/VTableManaged.cs @@ -16,26 +16,19 @@ using System.Runtime.InteropServices; namespace Mono.VisualC.Interop.ABI { public class VTableManaged : VTable { - private ModuleBuilder implModule; - public static MakeVTableDelegate Implementation = (entries) => { return new VTableManaged (entries); }; - private VTableManaged (Delegate[] entries) : base(entries) + public static MakeVTableDelegate Implementation = (types, overrides) => { return new VTableManaged (types, overrides); }; + private VTableManaged (IList types, Delegate [] overrides) : base(types, overrides) { - this.implModule = CppLibrary.interopModule; this.vtPtr = Marshal.AllocHGlobal (EntryCount * EntrySize); WriteOverrides (0); } - public override MethodInfo PrepareVirtualCall (MethodInfo target, CallingConvention callingConvention, ILGenerator callsite, + public override MethodInfo PrepareVirtualCall (MethodInfo target, CallingConvention? callingConvention, ILGenerator callsite, LocalBuilder nativePtr, FieldInfo vtableField, int vtableIndex) { - Type delegateType; - if (overrides [vtableIndex] != null) - delegateType = overrides [vtableIndex].GetType (); - else - delegateType = Util.GetDelegateTypeForMethodInfo (implModule, target, callingConvention); - + Type delegateType = delegate_types [vtableIndex]; MethodInfo getDelegate = typeof (VTableManaged).GetMethod ("GetDelegateForNative").MakeGenericMethod (delegateType); // load this._vtable diff --git a/Mono.VisualC.Interop/AssemblyInfo.cs b/Mono.VisualC.Interop/AssemblyInfo.cs index d0fd3549..81e80482 100644 --- a/Mono.VisualC.Interop/AssemblyInfo.cs +++ b/Mono.VisualC.Interop/AssemblyInfo.cs @@ -31,4 +31,4 @@ using System.Runtime.CompilerServices; [assembly: CLSCompliant(true)] // TODO: This will not work if we ever support saving these assemblies -[assembly: InternalsVisibleTo("__CPPLibraryImplAssembly")] \ No newline at end of file +[assembly: InternalsVisibleTo("__CppLibraryImplAssembly")] \ No newline at end of file diff --git a/Mono.VisualC.Interop/Attributes.cs b/Mono.VisualC.Interop/Attributes.cs index 0f49d0bb..f6eced20 100644 --- a/Mono.VisualC.Interop/Attributes.cs +++ b/Mono.VisualC.Interop/Attributes.cs @@ -16,10 +16,17 @@ namespace Mono.VisualC.Interop { #region Interface method attributes [AttributeUsage (AttributeTargets.Method)] public class VirtualAttribute : Attribute {} + + [AttributeUsage (AttributeTargets.Interface)] + public class VirtualDestructorAttribute : Attribute {} + [AttributeUsage (AttributeTargets.Method)] public class StaticAttribute : Attribute {} + + // FIXME: Will we ever be calling private methods? [AttributeUsage (AttributeTargets.Method)] public class PrivateAttribute : Attribute {} + [AttributeUsage (AttributeTargets.Method)] public class ProtectedAttribute : Attribute {} @@ -44,37 +51,46 @@ namespace Mono.VisualC.Interop { [AttributeUsage (AttributeTargets.Method)] public class OverrideNativeAttribute : Attribute {} +} + +namespace Mono.VisualC.Interop.ABI { +using Mono.VisualC.Interop; - public static class Modifiers { + public partial class CppAbi { - public static bool IsVirtual (MethodInfo method) + public virtual bool IsVirtual (MethodInfo method) { - return method.IsDefined (typeof (VirtualAttribute), false); + return method.IsDefined (typeof (VirtualAttribute), false); } - public static bool IsStatic (MethodInfo method) + public virtual bool IsVirtualDtor (MethodInfo method) + { + return GetMethodType (method) == MethodType.NativeDtor && + interface_type.IsDefined (typeof (VirtualDestructorAttribute), false); + } + public virtual bool IsStatic (MethodInfo method) { return method.IsDefined (typeof (StaticAttribute), false); } - public static bool IsPrivate (MethodInfo method) + public virtual bool IsPrivate (MethodInfo method) { return method.IsDefined (typeof (PrivateAttribute), false); } - public static bool IsProtected (MethodInfo method) + public virtual bool IsProtected (MethodInfo method) { return method.IsDefined (typeof (ProtectedAttribute), false); } - public static CppType GetMangleType (ParameterInfo param) + public virtual CppType GetMangleType (ICustomAttributeProvider icap, Type managedType) { CppType mangleType = new CppType (); - MangleAsAttribute maa = (MangleAsAttribute)param.GetCustomAttributes (typeof (MangleAsAttribute), false).FirstOrDefault (); + MangleAsAttribute maa = (MangleAsAttribute)icap.GetCustomAttributes (typeof (MangleAsAttribute), false).FirstOrDefault (); if (maa != null) mangleType = maa.MangleType; // this means that either no MangleAsAttribute was defined, or // only CppModifiers were applied .. apply CppType from managed parameter type if (mangleType.ElementType == CppTypes.Unknown && mangleType.ElementTypeName == null) - mangleType.ApplyTo (CppType.ForManagedType (param.ParameterType)); + mangleType.ApplyTo (CppType.ForManagedType (managedType)); else if (mangleType.ElementType == CppTypes.Unknown) // FIXME: otherwise, we just assume it's CppTypes.Class for now. mangleType.ElementType = CppTypes.Class; diff --git a/Mono.VisualC.Interop/CppInstancePtr.cs b/Mono.VisualC.Interop/CppInstancePtr.cs index 82e711be..dc924788 100644 --- a/Mono.VisualC.Interop/CppInstancePtr.cs +++ b/Mono.VisualC.Interop/CppInstancePtr.cs @@ -32,8 +32,6 @@ namespace Mono.VisualC.Interop { if (!implCache.TryGetValue (typeof (Iface), out cachedImpl)) { - // Since we're only using the VTable to allow C++ code to call managed methods, - // there is no advantage to using VTableCOM. Also, VTableCOM is based on this. VirtualOnlyAbi virtualABI = new VirtualOnlyAbi (VTableManaged.Implementation, VTable.BindToSignature); impl = virtualABI.ImplementClass (typeof (TWrapper), string.Empty, string.Empty); implCache.Add (typeof (Iface), impl); diff --git a/Mono.VisualC.Interop/CppLibrary.cs b/Mono.VisualC.Interop/CppLibrary.cs index 114baca3..d6618ffc 100644 --- a/Mono.VisualC.Interop/CppLibrary.cs +++ b/Mono.VisualC.Interop/CppLibrary.cs @@ -28,11 +28,11 @@ namespace Mono.VisualC.Interop { static CppLibrary () { - AssemblyName assemblyName = new AssemblyName ("__CPPLibraryImplAssembly"); - string moduleName = "__CPPLibraryImplModule"; + AssemblyName assemblyName = new AssemblyName ("__CppLibraryImplAssembly"); + string moduleName = "CppLibraryImplAssembly.dll"; - interopAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly (assemblyName, AssemblyBuilderAccess.Run); - interopModule = interopAssembly.DefineDynamicModule (moduleName); + interopAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly (assemblyName, AssemblyBuilderAccess.RunAndSave); + interopModule = interopAssembly.DefineDynamicModule (moduleName, moduleName, true); } public CppLibrary (string name, CppAbi abi) @@ -55,6 +55,12 @@ namespace Mono.VisualC.Interop { get { return abi; } } + // Mainly for debugging at this point + public static void SaveInteropAssembly () + { + interopAssembly.Save ("CppLibraryImplAssembly.dll"); + } + // For working with a class that you are not instantiating // from managed code and where access to fields is not necessary public Iface GetClass (string className) diff --git a/Mono.VisualC.Interop/CppType.cs b/Mono.VisualC.Interop/CppType.cs index 0bee5280..ba000a8f 100644 --- a/Mono.VisualC.Interop/CppType.cs +++ b/Mono.VisualC.Interop/CppType.cs @@ -121,7 +121,7 @@ namespace Mono.VisualC.Interop { { } - public CppType (params object[] cppTypeSpec) + public CppType (params object[] cppTypeSpec) : this () { ElementType = CppTypes.Unknown; ElementTypeName = null; diff --git a/Mono.VisualC.Interop/IEnumerableTransform.cs b/Mono.VisualC.Interop/IEnumerableTransform.cs index c234d997..6cb3a7cb 100644 --- a/Mono.VisualC.Interop/IEnumerableTransform.cs +++ b/Mono.VisualC.Interop/IEnumerableTransform.cs @@ -108,6 +108,7 @@ namespace Mono.VisualC.Interop { return RuleResult.MatchEmit; satisfied = previousRule.SatisfiedBy (input) != RuleResult.NoMatch; + return RuleResult.NoMatch; } } @@ -268,7 +269,6 @@ namespace Mono.VisualC.Interop { } public RuleResult SatisfiedBy (InputData input) { - bool satisfied = false; foreach (var rule in rules) { RuleResult result = rule.SatisfiedBy (input.NewContext ()); if (result != RuleResult.NoMatch) { @@ -280,6 +280,22 @@ namespace Mono.VisualC.Interop { return RuleResult.NoMatch; } } + + public class AtEndRule : IRule { + protected IRule rule; + + public AtEndRule (IRule rule) + { + this.rule = rule; + } + public RuleResult SatisfiedBy (InputData input) + { + RuleResult rr = rule.SatisfiedBy (input); + if (!input.Enumerator.MoveNext ()) + return rr; + return RuleResult.NoMatch; + } + } #endregion // the base point for building up rules @@ -451,6 +467,15 @@ namespace Mono.VisualC.Interop { public static class EnumerableSequenceExtensions { + // helper + + public static IEnumerable With (this IEnumerable current, T additionalValue) + { + foreach (var output in current) + yield return output; + yield return additionalValue; + } + // Transforms an IEnumerable into another by specific rules. public static IEnumerable Transform (this IEnumerable input, params EmitterFunc [] rules) @@ -503,6 +528,11 @@ namespace Mono.VisualC.Interop { }); } + public static IRule AtEnd (this IRule previousRules) + { + return new AtEndRule (previousRules); + } + public static EmitterFunc Emit (this IRule rule, Func result) { return delegate (InputData input, out TOut output) { diff --git a/Mono.VisualC.Interop/Util.cs b/Mono.VisualC.Interop/Util.cs index b3efc24e..baa1bbdf 100644 --- a/Mono.VisualC.Interop/Util.cs +++ b/Mono.VisualC.Interop/Util.cs @@ -13,61 +13,22 @@ namespace Mono.VisualC.Interop { return delType.GetMethod ("Invoke"); } - public static Type GetDelegateTypeForMethodInfo (ModuleBuilder mod, MethodInfo targetMethod, CallingConvention? callingConvention) - { - // TODO: Actually return the same delegate type instead of creating a new one if - // a suitable type already exists?? - string delTypeName = mod.Name + "_" + targetMethod.Name + "_VTdel"; - while (mod.GetType (delTypeName) != null) - delTypeName += "_"; - - TypeAttributes typeAttr = TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass; - TypeBuilder del = mod.DefineType (delTypeName, typeAttr, typeof(MulticastDelegate)); - - if (callingConvention.HasValue) { - ConstructorInfo ufpa = typeof (UnmanagedFunctionPointerAttribute).GetConstructor (new Type [] { typeof (CallingConvention) }); - CustomAttributeBuilder unmanagedPointer = new CustomAttributeBuilder (ufpa, new object [] { callingConvention.Value }); - del.SetCustomAttribute (unmanagedPointer); - } - - MethodAttributes ctorAttr = MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public; - ConstructorBuilder ctor = del.DefineConstructor (ctorAttr, CallingConventions.Standard, new Type[] { typeof(object), typeof(System.IntPtr) }); - ctor.SetImplementationFlags (MethodImplAttributes.Runtime | MethodImplAttributes.Managed); - - Type[] parameterTypes = GetMethodParameterTypes (targetMethod, true); - MethodAttributes methodAttr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual; - - MethodBuilder invokeMethod = del.DefineMethod ("Invoke", methodAttr, targetMethod.ReturnType, parameterTypes); - invokeMethod.SetImplementationFlags (MethodImplAttributes.Runtime | MethodImplAttributes.Managed); - - return del.CreateType (); - } - public static Type[] GetDelegateParameterTypes (Type delType) { MethodInfo invoke = GetMethodInfoForDelegate (delType); if (invoke == null) return null; - return GetMethodParameterTypes (invoke, false); + return GetMethodParameterTypes (invoke); } - public static Type[] GetMethodParameterTypes (MethodInfo method, bool forPInvoke) + public static Type[] GetMethodParameterTypes (MethodInfo method) { ParameterInfo[] parameters = method.GetParameters (); Type[] parameterTypes = new Type [parameters.Length]; - for (int i = 0; i < parameters.Length; i++) { - if (forPInvoke) { - if (parameters [i].ParameterType.Equals (typeof (CppInstancePtr))) - parameterTypes [i] = typeof (IntPtr); - else if (parameters [i].ParameterType.IsPointer) - parameterTypes [i] = parameters [i].ParameterType.GetElementType ().MakeByRefType (); - else - parameterTypes [i] = parameters [i].ParameterType; - } else + for (int i = 0; i < parameters.Length; i++) parameterTypes [i] = parameters [i].ParameterType; - } return parameterTypes; } @@ -94,8 +55,10 @@ namespace Mono.VisualC.Interop { MarshalAsAttribute existingMarshalAs = param.GetCustomAttributes (typeof (MarshalAsAttribute), false).FirstOrDefault () as MarshalAsAttribute; - if (forPInvoke && typeof (ICppObject).IsAssignableFrom (param.ParameterType) && - !param.ParameterType.Equals (typeof (CppInstancePtr)) && existingMarshalAs == null) + /* if (forPInvoke && + typeof (ICppObject).IsAssignableFrom (param.ParameterType) && + !param.ParameterType.Equals (typeof (CppInstancePtr)) && + existingMarshalAs == null) { ConstructorInfo ctor = typeof (MarshalAsAttribute).GetConstructor (new Type[] { typeof (UnmanagedType) }); object[] args = new object [] { UnmanagedType.CustomMarshaler }; @@ -105,7 +68,7 @@ namespace Mono.VisualC.Interop { marshalAsAttr = new CustomAttributeBuilder (ctor, args, fields, values); attr = attr | ParameterAttributes.HasFieldMarshal; - } else if (forPInvoke && existingMarshalAs != null) { + } else */ if (forPInvoke && existingMarshalAs != null) { // TODO: This still doesn't feel like it's working right.. ConstructorInfo ctor = typeof (MarshalAsAttribute).GetConstructor (new Type[] { typeof (UnmanagedType) }); object[] args = new object [] { existingMarshalAs.Value }; diff --git a/QtBindings/Core/QCoreApplication.cs b/QtBindings/Core/QCoreApplication.cs index d64880c5..51307ddc 100644 --- a/QtBindings/Core/QCoreApplication.cs +++ b/QtBindings/Core/QCoreApplication.cs @@ -6,6 +6,7 @@ namespace Qt.Core { public class QCoreApplication : QObject { #region Sync with qcoreapplication.h // C++ interface + [VirtualDestructor] public interface IQCoreApplication : ICppClassOverridable, Base { // ... void QCoreApplication (CppInstancePtr @this, [MangleAs ("int&")] IntPtr argc, diff --git a/QtBindings/Core/QObject.cs b/QtBindings/Core/QObject.cs index 5370bd00..b45aab66 100644 --- a/QtBindings/Core/QObject.cs +++ b/QtBindings/Core/QObject.cs @@ -6,6 +6,7 @@ namespace Qt.Core { public class QObject : ICppObject { #region Sync with qobject.h // C++ interface + [VirtualDestructor] public interface IQObject : ICppClassOverridable { // ... [Virtual] /*QMetaObject */ IntPtr metaObject(CppInstancePtr @this); diff --git a/QtBindings/Core/QString.cs b/QtBindings/Core/QString.cs index 5a945dcd..58736f0c 100644 --- a/QtBindings/Core/QString.cs +++ b/QtBindings/Core/QString.cs @@ -1,7 +1,9 @@ using System; using System.Text; using System.Runtime.InteropServices; + using Mono.VisualC.Interop; +using Mono.VisualC.Interop.ABI; namespace Qt.Core { //TODO: Will this leak? diff --git a/QtBindings/Gui/QAbstractButton.cs b/QtBindings/Gui/QAbstractButton.cs index 39ec5e77..daf68d23 100644 --- a/QtBindings/Gui/QAbstractButton.cs +++ b/QtBindings/Gui/QAbstractButton.cs @@ -5,6 +5,7 @@ namespace Qt.Gui { public class QAbstractButton : QWidget { #region Sync with qabstractbutton.h // C++ interface + [VirtualDestructor] public interface IQAbstractButton : ICppClassOverridable, Base { // ... void QAbstractButton (CppInstancePtr @this, QWidget parent); diff --git a/QtBindings/Gui/QApplication.cs b/QtBindings/Gui/QApplication.cs index d4df5418..2a71c814 100644 --- a/QtBindings/Gui/QApplication.cs +++ b/QtBindings/Gui/QApplication.cs @@ -8,6 +8,7 @@ namespace Qt.Gui { public class QApplication : QCoreApplication { #region Sync with qapplication.h // C++ interface + [VirtualDestructor] public interface IQApplication : ICppClassOverridable, Base { // ... void QApplication (CppInstancePtr @this, [MangleAs ("int&")] IntPtr argc, @@ -22,12 +23,14 @@ namespace Qt.Gui { // TODO: HACK! Yeah... I'm not calculating the right number of vtable slots somewhere... // ... add dummy methods until I figure it out... + /* [Virtual] void foo1 (CppInstancePtr @this); [Virtual] void foo2 (CppInstancePtr @this); [Virtual] void foo3 (CppInstancePtr @this); [Virtual] void foo4 (CppInstancePtr @this); [Virtual] void foo5 (CppInstancePtr @this); [Virtual] void foo6 (CppInstancePtr @this); + */ } // C++ fields private struct _QApplication { diff --git a/QtBindings/Gui/QPaintDevice.cs b/QtBindings/Gui/QPaintDevice.cs index 7e9db0d2..f36c7772 100644 --- a/QtBindings/Gui/QPaintDevice.cs +++ b/QtBindings/Gui/QPaintDevice.cs @@ -1,5 +1,6 @@ using System; using Mono.VisualC.Interop; +using Mono.VisualC.Interop.ABI; namespace Qt.Gui { public class QPaintDevice : ICppObject { diff --git a/QtBindings/Gui/QPushButton.cs b/QtBindings/Gui/QPushButton.cs index d9b84f54..d2b30fdb 100644 --- a/QtBindings/Gui/QPushButton.cs +++ b/QtBindings/Gui/QPushButton.cs @@ -6,6 +6,7 @@ namespace Qt.Gui { public class QPushButton : QAbstractButton { #region Sync with qpushbutton.h // C++ interface + [VirtualDestructor] public interface IQPushButton : ICppClassOverridable, Base { // ... void QPushButton (CppInstancePtr @this, [MangleAs ("const QString &")] ref QString text, QWidget parent); @@ -26,7 +27,7 @@ namespace Qt.Gui { impl.QPushButton (native, ref text, parent); } - public QPushButton (string text) : this (text, null) + public QPushButton (string text) : this (text, (QWidget)null) { } diff --git a/QtBindings/Gui/QWidget.cs b/QtBindings/Gui/QWidget.cs index 5ea3b37e..bd12e6bb 100644 --- a/QtBindings/Gui/QWidget.cs +++ b/QtBindings/Gui/QWidget.cs @@ -8,6 +8,7 @@ namespace Qt.Gui { public class QWidget : QObject { #region Sync with qwidget.h // C++ interface + [VirtualDestructor] public interface IQWidget : ICppClassOverridable, Base, Base { // ... void QWidget (CppInstancePtr @this, QWidget parent, /*Qt::WindowFlags */ int f); @@ -56,6 +57,7 @@ namespace Qt.Gui { [Virtual] bool focusNextPrevChild (CppInstancePtr @this, bool next); // TODO: Determine correct number of vtable slots here too... + /* [Virtual] void foo1 (CppInstancePtr @this); [Virtual] void foo2 (CppInstancePtr @this); [Virtual] void foo3 (CppInstancePtr @this); @@ -64,6 +66,7 @@ namespace Qt.Gui { [Virtual] void foo6 (CppInstancePtr @this); [Virtual] void foo7 (CppInstancePtr @this); [Virtual] void foo8 (CppInstancePtr @this); + */ } // C++ fields private struct _QWidget { diff --git a/QtBindings/Libs.cs b/QtBindings/Libs.cs index a2eaec92..7976928e 100644 --- a/QtBindings/Libs.cs +++ b/QtBindings/Libs.cs @@ -4,7 +4,8 @@ using Mono.VisualC.Interop; using Mono.VisualC.Interop.ABI; namespace Qt { - internal static class Libs { + // Will be internal; public for testing + public static class Libs { public static CppLibrary QtCore = null; public static CppLibrary QtGui = null; diff --git a/QtTest/Main.cs b/QtTest/Main.cs index eb3f5489..14622860 100644 --- a/QtTest/Main.cs +++ b/QtTest/Main.cs @@ -1,6 +1,7 @@ using System; using Qt.Gui; +using Mono.VisualC.Interop; namespace QtTest { class MainClass { @@ -10,9 +11,12 @@ namespace QtTest { using (QPushButton hello = new QPushButton ("Hello world!")) { hello.Resize (100, 30); + CppLibrary.SaveInteropAssembly (); hello.Visible = true; app.Exec (); + + } } } diff --git a/QtTest/QtTest.csproj b/QtTest/QtTest.csproj index 215fb5cf..59bd09ce 100644 --- a/QtTest/QtTest.csproj +++ b/QtTest/QtTest.csproj @@ -46,5 +46,9 @@ {66212CA6-B8C2-4307-ADDE-DAFEAAB339B9} QtBindings + + {4A864586-93C5-4DC1-8A80-F094A88506D7} + Mono.VisualC.Interop + \ No newline at end of file