Browse Source

Many fixes for MSVC abi. Fixed vtable slot calculation bug (destructors can be virtual too!) MSVC abi almost at level of Itanium.

git-svn-id: https://mono-soc-2010.googlecode.com/svn/trunk/cppinterop@77 a470b8cb-0e6f-1642-1b45-71e107334c4b
pull/1/head
alexander.corrado 16 years ago
parent
commit
b306fa8963
  1. 294
      Mono.VisualC.Interop/ABI/CppAbi.cs
  2. 6
      Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs
  3. 124
      Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs
  4. 11
      Mono.VisualC.Interop/ABI/Impl/VirtualOnlyAbi.cs
  5. 18
      Mono.VisualC.Interop/ABI/VTable.cs
  6. 12
      Mono.VisualC.Interop/ABI/VTableCOM.cs
  7. 15
      Mono.VisualC.Interop/ABI/VTableManaged.cs
  8. 2
      Mono.VisualC.Interop/AssemblyInfo.cs
  9. 32
      Mono.VisualC.Interop/Attributes.cs
  10. 2
      Mono.VisualC.Interop/CppInstancePtr.cs
  11. 14
      Mono.VisualC.Interop/CppLibrary.cs
  12. 2
      Mono.VisualC.Interop/CppType.cs
  13. 32
      Mono.VisualC.Interop/IEnumerableTransform.cs
  14. 53
      Mono.VisualC.Interop/Util.cs
  15. 1
      QtBindings/Core/QCoreApplication.cs
  16. 1
      QtBindings/Core/QObject.cs
  17. 2
      QtBindings/Core/QString.cs
  18. 1
      QtBindings/Gui/QAbstractButton.cs
  19. 3
      QtBindings/Gui/QApplication.cs
  20. 1
      QtBindings/Gui/QPaintDevice.cs
  21. 3
      QtBindings/Gui/QPushButton.cs
  22. 3
      QtBindings/Gui/QWidget.cs
  23. 3
      QtBindings/Libs.cs
  24. 4
      QtTest/Main.cs
  25. 4
      QtTest/QtTest.csproj

294
Mono.VisualC.Interop/ABI/CppAbi.cs

@ -17,9 +17,11 @@ using System.Runtime.InteropServices; @@ -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 { @@ -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:
public Iface ImplementClass<Iface> (Type wrapperType, string lib, string className)
{
return this.ImplementClass<Iface,EmptyNativeLayout> (wrapperType, lib, className);
@ -55,40 +91,33 @@ namespace Mono.VisualC.Interop.ABI { @@ -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 properties = GetProperties ();
var methods = GetMethods (interface_type);
var bases = GetBasesRecursive (interface_type);
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
);
IEnumerable<MethodInfo> baseVirtualMethods = Enumerable.Empty<MethodInfo> ();
// 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?????
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;
// 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 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 { @@ -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 { @@ -114,62 +139,67 @@ namespace Mono.VisualC.Interop.ABI {
return (Iface)Activator.CreateInstance (impl_type.CreateType (), vtable, NativeSize);
}
protected virtual IEnumerable<Delegate> GetBaseVirtualMethods (Type searchStart)
protected virtual IEnumerable<PropertyInfo> GetProperties ()
{
var bases = from baseIface in searchStart.GetInterfaces ()
where baseIface.Name.Equals ("Base`1")
from iface in baseIface.GetGenericArguments ()
select iface;
List<Delegate> virtualMethods = new List<Delegate> ();
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
);
}
foreach (var iface in bases)
protected virtual IEnumerable<MethodInfo> GetMethods (Type interfaceType)
{
virtualMethods.AddRange (GetBaseVirtualMethods (iface));
var methods = from method in iface.GetMethods ()
where Modifiers.IsVirtual (method)
// 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 GetManagedOverrideTrampoline (method, vtable_override_filter);
select method
);
virtualMethods.AddRange (methods);
return methods;
}
return virtualMethods;
protected virtual IEnumerable<MethodInfo> GetVirtualMethods (Type interfaceType)
{
var delegates = (
from method in GetMethods (interfaceType)
where IsVirtual (method)
select method
);
return delegates;
}
// These methods might be more commonly overridden for a given C++ ABI:
public virtual MethodType GetMethodType (MethodInfo imethod)
protected virtual IEnumerable<Type> GetBasesRecursive (Type searchStart)
{
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;
var immediateBases = (
from baseIface in searchStart.GetInterfaces ()
where baseIface.Name.Equals ("Base`1")
from iface in baseIface.GetGenericArguments ()
select iface
);
return MethodType.Native;
}
if (!immediateBases.Any ())
return Enumerable.Empty<Type> ();
public virtual int FieldOffsetPadding {
get { return Marshal.SizeOf (typeof (IntPtr)); }
List<Type> allBases = new List<Type> ();
foreach (var baseInterface in immediateBases) {
allBases.AddRange (GetBasesRecursive (baseInterface));
allBases.Add (baseInterface);
}
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;
}
return allBases;
}
// 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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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++)
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<Type> 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<Type> ().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.

6
Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs

@ -21,7 +21,7 @@ namespace Mono.VisualC.Interop.ABI { @@ -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 { @@ -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 ();
}

124
Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs

@ -8,23 +8,27 @@ @@ -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 { @@ -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,8 +91,99 @@ namespace Mono.VisualC.Interop.ABI { @@ -80,8 +91,99 @@ namespace Mono.VisualC.Interop.ABI {
}
// FIXME: handle const, volatile modifiers on return type
// 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<CppModifiers> 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<CppModifiers> ().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 ();
}
}

11
Mono.VisualC.Interop/ABI/Impl/VirtualOnlyAbi.cs

@ -11,9 +11,8 @@ using System; @@ -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 { @@ -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;
}
}
}

18
Mono.VisualC.Interop/ABI/VTable.cs

@ -15,20 +15,21 @@ using System.Reflection.Emit; @@ -15,20 +15,21 @@ using System.Reflection.Emit;
using System.Runtime.InteropServices;
namespace Mono.VisualC.Interop.ABI {
public delegate VTable MakeVTableDelegate (Delegate[] overrides);
public delegate VTable MakeVTableDelegate (IList<Type> 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.
// 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<Type> 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 {
@ -38,12 +39,13 @@ namespace Mono.VisualC.Interop.ABI { @@ -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<Type> delegateTypes, Delegate [] overrides)
{
this.delegate_types = delegateTypes;
this.overrides = overrides;
this.basePtr = IntPtr.Zero;
this.vtPtr = IntPtr.Zero;

12
Mono.VisualC.Interop/ABI/VTableCOM.cs

@ -18,18 +18,12 @@ using System.Runtime.InteropServices; @@ -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<Type> 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 ();

15
Mono.VisualC.Interop/ABI/VTableManaged.cs

@ -16,26 +16,19 @@ using System.Runtime.InteropServices; @@ -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<Type> 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

2
Mono.VisualC.Interop/AssemblyInfo.cs

@ -31,4 +31,4 @@ using System.Runtime.CompilerServices; @@ -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")]
[assembly: InternalsVisibleTo("__CppLibraryImplAssembly")]

32
Mono.VisualC.Interop/Attributes.cs

@ -16,10 +16,17 @@ namespace Mono.VisualC.Interop { @@ -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 { @@ -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);
}
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;

2
Mono.VisualC.Interop/CppInstancePtr.cs

@ -32,8 +32,6 @@ namespace Mono.VisualC.Interop { @@ -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<Iface> (typeof (TWrapper), string.Empty, string.Empty);
implCache.Add (typeof (Iface), impl);

14
Mono.VisualC.Interop/CppLibrary.cs

@ -28,11 +28,11 @@ namespace Mono.VisualC.Interop { @@ -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 { @@ -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<Iface> (string className)

2
Mono.VisualC.Interop/CppType.cs

@ -121,7 +121,7 @@ namespace Mono.VisualC.Interop { @@ -121,7 +121,7 @@ namespace Mono.VisualC.Interop {
{
}
public CppType (params object[] cppTypeSpec)
public CppType (params object[] cppTypeSpec) : this ()
{
ElementType = CppTypes.Unknown;
ElementTypeName = null;

32
Mono.VisualC.Interop/IEnumerableTransform.cs

@ -108,6 +108,7 @@ namespace Mono.VisualC.Interop { @@ -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 { @@ -268,7 +269,6 @@ namespace Mono.VisualC.Interop {
}
public RuleResult SatisfiedBy (InputData<TIn> 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 { @@ -280,6 +280,22 @@ namespace Mono.VisualC.Interop {
return RuleResult.NoMatch;
}
}
public class AtEndRule<TIn> : IRule<TIn> {
protected IRule<TIn> rule;
public AtEndRule (IRule<TIn> rule)
{
this.rule = rule;
}
public RuleResult SatisfiedBy (InputData<TIn> 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 { @@ -451,6 +467,15 @@ namespace Mono.VisualC.Interop {
public static class EnumerableSequenceExtensions {
// helper
public static IEnumerable<T> With<T> (this IEnumerable<T> 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<TOut> Transform<TIn, TOut> (this IEnumerable<TIn> input, params EmitterFunc<TIn, TOut> [] rules)
@ -503,6 +528,11 @@ namespace Mono.VisualC.Interop { @@ -503,6 +528,11 @@ namespace Mono.VisualC.Interop {
});
}
public static IRule<TIn> AtEnd<TIn> (this IRule<TIn> previousRules)
{
return new AtEndRule<TIn> (previousRules);
}
public static EmitterFunc<TIn, TOut> Emit<TIn, TOut> (this IRule<TIn> rule, Func<TIn, TOut> result)
{
return delegate (InputData<TIn> input, out TOut output) {

53
Mono.VisualC.Interop/Util.cs

@ -13,61 +13,22 @@ namespace Mono.VisualC.Interop { @@ -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
for (int i = 0; i < parameters.Length; i++)
parameterTypes [i] = parameters [i].ParameterType;
} else
parameterTypes [i] = parameters [i].ParameterType;
}
return parameterTypes;
}
@ -94,8 +55,10 @@ namespace Mono.VisualC.Interop { @@ -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 { @@ -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 };

1
QtBindings/Core/QCoreApplication.cs

@ -6,6 +6,7 @@ namespace Qt.Core { @@ -6,6 +6,7 @@ namespace Qt.Core {
public class QCoreApplication : QObject {
#region Sync with qcoreapplication.h
// C++ interface
[VirtualDestructor]
public interface IQCoreApplication : ICppClassOverridable<QCoreApplication>, Base<QObject.IQObject> {
// ...
void QCoreApplication (CppInstancePtr @this, [MangleAs ("int&")] IntPtr argc,

1
QtBindings/Core/QObject.cs

@ -6,6 +6,7 @@ namespace Qt.Core { @@ -6,6 +6,7 @@ namespace Qt.Core {
public class QObject : ICppObject {
#region Sync with qobject.h
// C++ interface
[VirtualDestructor]
public interface IQObject : ICppClassOverridable<QObject> {
// ...
[Virtual] /*QMetaObject */ IntPtr metaObject(CppInstancePtr @this);

2
QtBindings/Core/QString.cs

@ -1,7 +1,9 @@ @@ -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?

1
QtBindings/Gui/QAbstractButton.cs

@ -5,6 +5,7 @@ namespace Qt.Gui { @@ -5,6 +5,7 @@ namespace Qt.Gui {
public class QAbstractButton : QWidget {
#region Sync with qabstractbutton.h
// C++ interface
[VirtualDestructor]
public interface IQAbstractButton : ICppClassOverridable<QAbstractButton>, Base<QWidget.IQWidget> {
// ...
void QAbstractButton (CppInstancePtr @this, QWidget parent);

3
QtBindings/Gui/QApplication.cs

@ -8,6 +8,7 @@ namespace Qt.Gui { @@ -8,6 +8,7 @@ namespace Qt.Gui {
public class QApplication : QCoreApplication {
#region Sync with qapplication.h
// C++ interface
[VirtualDestructor]
public interface IQApplication : ICppClassOverridable<QApplication>, Base<QCoreApplication.IQCoreApplication> {
// ...
void QApplication (CppInstancePtr @this, [MangleAs ("int&")] IntPtr argc,
@ -22,12 +23,14 @@ namespace Qt.Gui { @@ -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 {

1
QtBindings/Gui/QPaintDevice.cs

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
using System;
using Mono.VisualC.Interop;
using Mono.VisualC.Interop.ABI;
namespace Qt.Gui {
public class QPaintDevice : ICppObject {

3
QtBindings/Gui/QPushButton.cs

@ -6,6 +6,7 @@ namespace Qt.Gui { @@ -6,6 +6,7 @@ namespace Qt.Gui {
public class QPushButton : QAbstractButton {
#region Sync with qpushbutton.h
// C++ interface
[VirtualDestructor]
public interface IQPushButton : ICppClassOverridable<QPushButton>, Base<QAbstractButton.IQAbstractButton> {
// ...
void QPushButton (CppInstancePtr @this, [MangleAs ("const QString &")] ref QString text, QWidget parent);
@ -26,7 +27,7 @@ namespace Qt.Gui { @@ -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)
{
}

3
QtBindings/Gui/QWidget.cs

@ -8,6 +8,7 @@ namespace Qt.Gui { @@ -8,6 +8,7 @@ namespace Qt.Gui {
public class QWidget : QObject {
#region Sync with qwidget.h
// C++ interface
[VirtualDestructor]
public interface IQWidget : ICppClassOverridable<QWidget>, Base<QObject.IQObject>, Base<QPaintDevice.IQPaintDevice> {
// ...
void QWidget (CppInstancePtr @this, QWidget parent, /*Qt::WindowFlags */ int f);
@ -56,6 +57,7 @@ namespace Qt.Gui { @@ -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 { @@ -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 {

3
QtBindings/Libs.cs

@ -4,7 +4,8 @@ using Mono.VisualC.Interop; @@ -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;

4
QtTest/Main.cs

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
using System;
using Qt.Gui;
using Mono.VisualC.Interop;
namespace QtTest {
class MainClass {
@ -10,9 +11,12 @@ namespace QtTest { @@ -10,9 +11,12 @@ namespace QtTest {
using (QPushButton hello = new QPushButton ("Hello world!")) {
hello.Resize (100, 30);
CppLibrary.SaveInteropAssembly ();
hello.Visible = true;
app.Exec ();
}
}
}

4
QtTest/QtTest.csproj

@ -46,5 +46,9 @@ @@ -46,5 +46,9 @@
<Project>{66212CA6-B8C2-4307-ADDE-DAFEAAB339B9}</Project>
<Name>QtBindings</Name>
</ProjectReference>
<ProjectReference Include="..\Mono.VisualC.Interop\Mono.VisualC.Interop.csproj">
<Project>{4A864586-93C5-4DC1-8A80-F094A88506D7}</Project>
<Name>Mono.VisualC.Interop</Name>
</ProjectReference>
</ItemGroup>
</Project>
Loading…
Cancel
Save