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. 330
      Mono.VisualC.Interop/ABI/CppAbi.cs
  2. 6
      Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs
  3. 128
      Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs
  4. 11
      Mono.VisualC.Interop/ABI/Impl/VirtualOnlyAbi.cs
  5. 20
      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. 34
      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

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

@ -17,9 +17,11 @@ using System.Runtime.InteropServices;
namespace Mono.VisualC.Interop.ABI { namespace Mono.VisualC.Interop.ABI {
//TODO: Exception handling, operator overloading etc. //FIXME: Exception handling, operator overloading etc.
//TODO: Allow interface to override default calling convention //FIXME: Allow interface to override default calling convention
public abstract class CppAbi { //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 ModuleBuilder impl_module;
protected TypeBuilder impl_type; protected TypeBuilder impl_type;
@ -31,12 +33,46 @@ namespace Mono.VisualC.Interop.ABI {
protected FieldBuilder vtable_field, native_size_field; protected FieldBuilder vtable_field, native_size_field;
protected ILGenerator ctor_il; protected ILGenerator ctor_il;
// default settings that subclasses can override: // Default settings that subclasses can override:
protected MakeVTableDelegate make_vtable_method = VTable.DefaultImplementation; protected MakeVTableDelegate make_vtable_method = VTable.DefaultImplementation;
protected MemberFilter vtable_override_filter = VTable.BindToSignatureAndAttribute; 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<Iface> (Type wrapperType, string lib, string className) public Iface ImplementClass<Iface> (Type wrapperType, string lib, string className)
{ {
return this.ImplementClass<Iface,EmptyNativeLayout> (wrapperType, lib, className); return this.ImplementClass<Iface,EmptyNativeLayout> (wrapperType, lib, className);
@ -55,40 +91,33 @@ namespace Mono.VisualC.Interop.ABI {
DefineImplType (); DefineImplType ();
var properties = ( // get all properties defined on the interface var properties = GetProperties ();
from property in interface_type.GetProperties () var methods = GetMethods (interface_type);
select property var bases = GetBasesRecursive (interface_type);
).Union ( // ... as well as those defined on inherited interfaces
from iface in interface_type.GetInterfaces () IEnumerable<MethodInfo> baseVirtualMethods = Enumerable.Empty<MethodInfo> ();
from property in iface.GetProperties ()
select property 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 methods = ( // get all methods defined on inherited interfaces first
from iface in interface_type.GetInterfaces () var vtableSlots = from method in baseVirtualMethods.Concat (GetVirtualMethods (interface_type))
from method in iface.GetMethods () let delegateType = DefineVTableDelegate (method)
select method select new { DelegateType = delegateType,
).Union ( // ... as well as those defined on this interface Override = GetManagedOverrideTrampoline (method, delegateType, vtable_override_filter)
from method in interface_type.GetMethods () };
orderby method.MetadataToken
select method var virtualDtorSlots = from iface in bases.With (interface_type)
); where iface.IsDefined (typeof (VirtualDestructorAttribute), false)
from i in new int [] { 0, 1 }
// TODO: If a method in a base class interface is defined again in a child class select new { DelegateType = (Type)null, Override = (Delegate)null };
// interface with exactly the same signature, it will prolly share a vtable slot?????
vtableSlots = vtableSlots.Concat (virtualDtorSlots);
// 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)
);
// ONLY make vtable if there are virtual methods // ONLY make vtable if there are virtual methods
if (virtualMethods.Any ()) if (vtableSlots.Any ())
vtable = make_vtable_method (virtualMethods.ToArray ()); vtable = make_vtable_method (vtableSlots.Select (s => s.DelegateType).ToList (),
vtableSlots.Select (s => s.Override).ToArray ());
else else
vtable = null; vtable = null;
@ -96,13 +125,9 @@ namespace Mono.VisualC.Interop.ABI {
// Implement all methods // Implement all methods
foreach (var method in 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); DefineMethod (method, vtableIndex);
if (Modifiers.IsVirtual (method)) if (IsVirtual (method))
vtableIndex++; vtableIndex++;
} }
@ -114,62 +139,67 @@ namespace Mono.VisualC.Interop.ABI {
return (Iface)Activator.CreateInstance (impl_type.CreateType (), vtable, NativeSize); return (Iface)Activator.CreateInstance (impl_type.CreateType (), vtable, NativeSize);
} }
protected virtual IEnumerable<Delegate> GetBaseVirtualMethods (Type searchStart) protected virtual IEnumerable<PropertyInfo> 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<MethodInfo> 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<MethodInfo> GetVirtualMethods (Type interfaceType)
{
var delegates = (
from method in GetMethods (interfaceType)
where IsVirtual (method)
select method
);
return delegates;
}
protected virtual IEnumerable<Type> GetBasesRecursive (Type searchStart)
{ {
var bases = from baseIface in searchStart.GetInterfaces () var immediateBases = (
where baseIface.Name.Equals ("Base`1") from baseIface in searchStart.GetInterfaces ()
from iface in baseIface.GetGenericArguments () where baseIface.Name.Equals ("Base`1")
select iface; from iface in baseIface.GetGenericArguments ()
select iface
List<Delegate> virtualMethods = new List<Delegate> (); );
foreach (var iface in bases) if (!immediateBases.Any ())
{ return Enumerable.Empty<Type> ();
virtualMethods.AddRange (GetBaseVirtualMethods (iface));
List<Type> allBases = new List<Type> ();
var methods = from method in iface.GetMethods () foreach (var baseInterface in immediateBases) {
where Modifiers.IsVirtual (method) allBases.AddRange (GetBasesRecursive (baseInterface));
orderby method.MetadataToken allBases.Add (baseInterface);
select GetManagedOverrideTrampoline (method, vtable_override_filter); }
virtualMethods.AddRange (methods); return allBases;
}
return virtualMethods;
} }
// 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 () protected virtual void DefineImplType ()
{ {
string implTypeName = interface_type.Name + "_" + layout_type.Name + "_" + this.GetType ().Name + "_Impl"; string implTypeName = interface_type.Name + "_" + layout_type.Name + "_" + this.GetType ().Name + "_Impl";
@ -198,7 +228,7 @@ namespace Mono.VisualC.Interop.ABI {
{ {
// 0. Introspect method // 0. Introspect method
MethodType methodType = GetMethodType (interfaceMethod); MethodType methodType = GetMethodType (interfaceMethod);
Type[] parameterTypes = Util.GetMethodParameterTypes (interfaceMethod, false); Type[] parameterTypes = Util.GetMethodParameterTypes (interfaceMethod);
// 1. Generate managed trampoline to call native method // 1. Generate managed trampoline to call native method
MethodBuilder trampoline = GetMethodBuilder (interfaceMethod); MethodBuilder trampoline = GetMethodBuilder (interfaceMethod);
@ -207,7 +237,7 @@ namespace Mono.VisualC.Interop.ABI {
if (methodType == MethodType.NoOp) { if (methodType == MethodType.NoOp) {
// return NULL if method is supposed to return a value // 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))) if (!interfaceMethod.ReturnType.Equals (typeof (void)))
il.Emit (OpCodes.Ldnull); il.Emit (OpCodes.Ldnull);
il.Emit (OpCodes.Ret); il.Emit (OpCodes.Ret);
@ -223,7 +253,7 @@ namespace Mono.VisualC.Interop.ABI {
LocalBuilder nativePtr = null; LocalBuilder nativePtr = null;
// If we're not a static method, do the following ... // If we're not a static method, do the following ...
if (!Modifiers.IsStatic (interfaceMethod)) if (!IsStatic (interfaceMethod))
{ {
isStatic = false; isStatic = false;
if (parameterTypes.Length < 1) if (parameterTypes.Length < 1)
@ -237,23 +267,28 @@ namespace Mono.VisualC.Interop.ABI {
} }
MethodInfo nativeMethod; MethodInfo nativeMethod;
if (Modifiers.IsVirtual (interfaceMethod)) bool isVirtual;
if (IsVirtual (interfaceMethod)) {
isVirtual = true;
nativeMethod = vtable.PrepareVirtualCall (interfaceMethod, GetCallingConvention (interfaceMethod), nativeMethod = vtable.PrepareVirtualCall (interfaceMethod, GetCallingConvention (interfaceMethod),
il, nativePtr, vtable_field, index); il, nativePtr, vtable_field, index);
else } else {
isVirtual = false;
nativeMethod = GetPInvokeForMethod (interfaceMethod); nativeMethod = GetPInvokeForMethod (interfaceMethod);
}
switch (methodType) { switch (methodType) {
case MethodType.NativeCtor: case MethodType.NativeCtor:
EmitConstruct (il, nativeMethod, parameterTypes.Length, nativePtr); EmitConstruct (il, nativeMethod, parameterTypes, nativePtr);
break; break;
case MethodType.NativeDtor: case MethodType.NativeDtor:
EmitDestruct (il, nativeMethod, parameterTypes.Length, cppInstancePtr, nativePtr); EmitDestruct (il, nativeMethod, isVirtual, parameterTypes, cppInstancePtr, nativePtr);
break; break;
default: // regular native method default: // regular native method
EmitCallNative (il, nativeMethod, isStatic, parameterTypes.Length, nativePtr); EmitCallNative (il, nativeMethod, isStatic, parameterTypes, nativePtr);
break; 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 * 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. * 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) if (wrapper_type == null)
return null; return null;
@ -329,8 +364,7 @@ namespace Mono.VisualC.Interop.ABI {
if (targetMethod == null) if (targetMethod == null)
return null; return null;
Type delegateType = Util.GetDelegateTypeForMethodInfo (impl_module, interfaceMethod, GetCallingConvention (interfaceMethod)); Type[] parameterTypes = GetParameterTypesForPInvoke (interfaceMethod).ToArray ();
Type[] parameterTypes = Util.GetMethodParameterTypes (interfaceMethod, true);
// TODO: According to http://msdn.microsoft.com/en-us/library/w16z8yc4.aspx // 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. // 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) 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, MethodBuilder methodBuilder = impl_type.DefineMethod (interfaceMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual,
interfaceMethod.ReturnType, parameterTypes); interfaceMethod.ReturnType, parameterTypes);
Util.ApplyMethodParameterAttributes (interfaceMethod, methodBuilder, false); Util.ApplyMethodParameterAttributes (interfaceMethod, methodBuilder, false);
@ -401,17 +435,48 @@ namespace Mono.VisualC.Interop.ABI {
if (entryPoint == null) if (entryPoint == null)
throw new NotSupportedException ("Could not mangle method name."); 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, MethodBuilder builder = impl_type.DefinePInvokeMethod ("__$" + signature.Name + "_Impl", library, entryPoint,
MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.PinvokeImpl, MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.PinvokeImpl,
CallingConventions.Any, signature.ReturnType, parameterTypes, CallingConventions.Standard, signature.ReturnType, parameterTypes,
GetCallingConvention (signature), CharSet.Ansi); GetCallingConvention (signature).Value, CharSet.Ansi);
builder.SetImplementationFlags (builder.GetMethodImplementationFlags () | MethodImplAttributes.PreserveSig); builder.SetImplementationFlags (builder.GetMethodImplementationFlags () | MethodImplAttributes.PreserveSig);
Util.ApplyMethodParameterAttributes (signature, builder, true); Util.ApplyMethodParameterAttributes (signature, builder, true);
return builder; 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. * Emits IL to allocate the memory for a new instance of the C++ class.
* To complete method, emit OpCodes.Ret. * To complete method, emit OpCodes.Ret.
@ -441,29 +506,37 @@ namespace Mono.VisualC.Interop.ABI {
new Type[] { typeof (int) }, null)); 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) LocalBuilder nativePtr)
{ {
EmitCallNative (il, nativeMethod, false, parameterCount, nativePtr); EmitCallNative (il, nativeMethod, false, parameterTypes, nativePtr);
EmitInitVTable (il, 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) LocalBuilder cppInstancePtr, LocalBuilder nativePtr)
{ {
// bail if we weren't alloc'd by managed code // bail if we weren't alloc'd by managed code
Label bail = il.DefineLabel (); Label bail = il.DefineLabel ();
Label retNormal = il.DefineLabel ();
il.Emit (OpCodes.Ldloca_S, cppInstancePtr); 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.Ldloca_S, cppInstancePtr);
il.Emit (OpCodes.Call, typeof (CppInstancePtr).GetProperty ("IsManagedAlloc").GetGetMethod ()); il.Emit (OpCodes.Call, typeof (CppInstancePtr).GetProperty ("IsManagedAlloc").GetGetMethod ());
il.Emit (OpCodes.Brfalse_S, bail); il.Emit (OpCodes.Brfalse_S, bail);
EmitResetVTable (il, nativePtr); 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); 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. * GetPInvokeForMethod or the MethodInfo of a vtable method.
* To complete method, emit OpCodes.Ret. * 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) LocalBuilder nativePtr)
{ {
int argLoadStart = 1; // For static methods, just strip off arg0 (.net this pointer) 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 argLoadStart = 2; // For instance methods, strip off CppInstancePtr and pass the corresponding IntPtr
il.Emit (OpCodes.Ldloc_S, nativePtr); il.Emit (OpCodes.Ldloc_S, nativePtr);
} }
for (int i = argLoadStart; i <= parameterCount; i++) for (int i = argLoadStart; i <= parameterTypes.Length; i++) {
il.Emit (OpCodes.Ldarg, i); EmitSpecialParameterMarshal (il, parameterTypes [i - 1]);
il.Emit (OpCodes.Ldarg, i);
}
il.Emit (OpCodes.Call, nativeMethod); 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). * 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. * 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 {
{ {
} }
public override CallingConvention GetCallingConvention (MethodInfo methodInfo) public override CallingConvention? GetCallingConvention (MethodInfo methodInfo)
{ {
return CallingConvention.Cdecl; return CallingConvention.Cdecl;
} }
@ -50,13 +50,13 @@ namespace Mono.VisualC.Interop.ABI {
} }
nm.Append ('E'); 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) if (parameters.Length == argStart) // no args (other than C++ "this" object)
nm.Append ('v'); nm.Append ('v');
else else
for (int i = argStart; i < parameters.Length; i++) 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 (); return nm.ToString ();
} }

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

@ -8,23 +8,27 @@
// //
using System; using System;
using System.Linq;
using System.Text; using System.Text;
using System.Reflection; using System.Reflection;
using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Mono.VisualC.Interop; using Mono.VisualC.Interop;
namespace Mono.VisualC.Interop.ABI { namespace Mono.VisualC.Interop.ABI {
// FIXME: No 64-bit support
public class MsvcAbi : CppAbi { public class MsvcAbi : CppAbi {
public MsvcAbi () 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; return CallingConvention.Cdecl;
else else
return CallingConvention.ThisCall; return CallingConvention.ThisCall;
@ -38,30 +42,37 @@ namespace Mono.VisualC.Interop.ABI {
StringBuilder nm = new StringBuilder ("?", 30); 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, // 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. // 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 // function modifiers are a matrix of consecutive uppercase letters
// depending on access type and virtual (far)/static (far)/far modifiers // depending on access type and virtual (far)/static (far)/far modifiers
// first, access type // first, access type
char funcModifier = 'Q'; // (public) char funcModifier = 'Q'; // (public)
if (Modifiers.IsProtected (methodInfo)) if (IsProtected (methodInfo))
funcModifier = 'I'; funcModifier = 'I';
else if (Modifiers.IsPrivate (methodInfo)) else if (IsPrivate (methodInfo)) // (probably don't need this)
funcModifier = 'A'; funcModifier = 'A';
// now, offset based on other modifiers // now, offset based on other modifiers
if (Modifiers.IsStatic (methodInfo)) if (IsStatic (methodInfo))
funcModifier += 2; funcModifier += (char)2;
else if (Modifiers.IsVirtual (methodInfo)) // (do we need this?) else if (IsVirtual (methodInfo) || IsVirtualDtor (methodInfo))
funcModifier += 4; funcModifier += (char)4;
nm.Append (funcModifier); nm.Append (funcModifier);
// FIXME: deal with storage classes for "this" i.e. the "const" in -> int foo () const; // 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'); nm.Append ('A');
switch (GetCallingConvention (methodInfo)) { switch (GetCallingConvention (methodInfo)) {
@ -80,9 +91,100 @@ namespace Mono.VisualC.Interop.ABI {
} }
// FIXME: handle const, volatile modifiers on return type // 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<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;
using System.Reflection; using System.Reflection;
using System.Reflection.Emit; using System.Reflection.Emit;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Mono.VisualC.Interop.ABI;
namespace Mono.VisualC.Interop { namespace Mono.VisualC.Interop.ABI {
public class VirtualOnlyAbi : CppAbi { 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."); throw new NotSupportedException ("Name mangling is not supported by this class. All C++ interface methods must be declared virtual.");
} }
public override CallingConvention DefaultCallingConvention { public override CallingConvention? GetCallingConvention (MethodInfo methodInfo)
get { {
throw new NotSupportedException ("This class does not support this property."); // Use platform default
} return null;
} }
} }
} }

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

@ -15,21 +15,22 @@ using System.Reflection.Emit;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Mono.VisualC.Interop.ABI { 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 // TODO: RTTI .. support virtual inheritance
public abstract class VTable : IDisposable { 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; public static MakeVTableDelegate DefaultImplementation = VTableManaged.Implementation;
protected IntPtr basePtr, vtPtr; protected IntPtr basePtr, vtPtr;
// This is a bit of a misnomer since the Length of the array will be equal // FIXME: Either make this a lazy list that only generates the delegate type if
// to the number of entries in the vtable; entries that aren't overridden // it is needed, and/or cache generated delegate types (see FIXME in CppAbi::DefineVTableDelegate)
// will be NULL. protected IList<Type> delegate_types;
protected Delegate[] overrides;
// 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 { public virtual int EntryCount {
get { return overrides.Length; } get { return overrides.Length; }
@ -38,12 +39,13 @@ namespace Mono.VisualC.Interop.ABI {
get { return Marshal.SizeOf (typeof (IntPtr)); } 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); LocalBuilder nativePtr, FieldInfo vtableField, int vtableIndex);
// Subclasses must allocate vtPtr! // Subclasses must allocate vtPtr!
public VTable (Delegate[] overrides) public VTable (IList<Type> delegateTypes, Delegate [] overrides)
{ {
this.delegate_types = delegateTypes;
this.overrides = overrides; this.overrides = overrides;
this.basePtr = IntPtr.Zero; this.basePtr = IntPtr.Zero;
this.vtPtr = IntPtr.Zero; this.vtPtr = IntPtr.Zero;

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

@ -18,18 +18,12 @@ using System.Runtime.InteropServices;
namespace Mono.VisualC.Interop.ABI { namespace Mono.VisualC.Interop.ABI {
public class VTableCOM : VTable { public class VTableCOM : VTable {
public static MakeVTableDelegate Implementation = (entries) => { return new VTableCOM (entries); }; public static MakeVTableDelegate Implementation = (types, overrides) => { return new VTableCOM (types, overrides); };
private VTableCOM (Delegate[] entries) : base(entries) 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) LocalBuilder nativePtr, FieldInfo vtableField, int vtableIndex)
{ {
throw new System.NotImplementedException (); throw new System.NotImplementedException ();

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

@ -16,26 +16,19 @@ using System.Runtime.InteropServices;
namespace Mono.VisualC.Interop.ABI { namespace Mono.VisualC.Interop.ABI {
public class VTableManaged : VTable { public class VTableManaged : VTable {
private ModuleBuilder implModule;
public static MakeVTableDelegate Implementation = (entries) => { return new VTableManaged (entries); }; public static MakeVTableDelegate Implementation = (types, overrides) => { return new VTableManaged (types, overrides); };
private VTableManaged (Delegate[] entries) : base(entries) private VTableManaged (IList<Type> types, Delegate [] overrides) : base(types, overrides)
{ {
this.implModule = CppLibrary.interopModule;
this.vtPtr = Marshal.AllocHGlobal (EntryCount * EntrySize); this.vtPtr = Marshal.AllocHGlobal (EntryCount * EntrySize);
WriteOverrides (0); 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) LocalBuilder nativePtr, FieldInfo vtableField, int vtableIndex)
{ {
Type delegateType; Type delegateType = delegate_types [vtableIndex];
if (overrides [vtableIndex] != null)
delegateType = overrides [vtableIndex].GetType ();
else
delegateType = Util.GetDelegateTypeForMethodInfo (implModule, target, callingConvention);
MethodInfo getDelegate = typeof (VTableManaged).GetMethod ("GetDelegateForNative").MakeGenericMethod (delegateType); MethodInfo getDelegate = typeof (VTableManaged).GetMethod ("GetDelegateForNative").MakeGenericMethod (delegateType);
// load this._vtable // load this._vtable

2
Mono.VisualC.Interop/AssemblyInfo.cs

@ -31,4 +31,4 @@ using System.Runtime.CompilerServices;
[assembly: CLSCompliant(true)] [assembly: CLSCompliant(true)]
// TODO: This will not work if we ever support saving these assemblies // TODO: This will not work if we ever support saving these assemblies
[assembly: InternalsVisibleTo("__CPPLibraryImplAssembly")] [assembly: InternalsVisibleTo("__CppLibraryImplAssembly")]

34
Mono.VisualC.Interop/Attributes.cs

@ -16,10 +16,17 @@ namespace Mono.VisualC.Interop {
#region Interface method attributes #region Interface method attributes
[AttributeUsage (AttributeTargets.Method)] [AttributeUsage (AttributeTargets.Method)]
public class VirtualAttribute : Attribute {} public class VirtualAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Interface)]
public class VirtualDestructorAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Method)] [AttributeUsage (AttributeTargets.Method)]
public class StaticAttribute : Attribute {} public class StaticAttribute : Attribute {}
// FIXME: Will we ever be calling private methods?
[AttributeUsage (AttributeTargets.Method)] [AttributeUsage (AttributeTargets.Method)]
public class PrivateAttribute : Attribute {} public class PrivateAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Method)] [AttributeUsage (AttributeTargets.Method)]
public class ProtectedAttribute : Attribute {} public class ProtectedAttribute : Attribute {}
@ -44,37 +51,46 @@ namespace Mono.VisualC.Interop {
[AttributeUsage (AttributeTargets.Method)] [AttributeUsage (AttributeTargets.Method)]
public class OverrideNativeAttribute : Attribute {} 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); return method.IsDefined (typeof (StaticAttribute), false);
} }
public static bool IsPrivate (MethodInfo method) public virtual bool IsPrivate (MethodInfo method)
{ {
return method.IsDefined (typeof (PrivateAttribute), false); return method.IsDefined (typeof (PrivateAttribute), false);
} }
public static bool IsProtected (MethodInfo method) public virtual bool IsProtected (MethodInfo method)
{ {
return method.IsDefined (typeof (ProtectedAttribute), false); return method.IsDefined (typeof (ProtectedAttribute), false);
} }
public static CppType GetMangleType (ParameterInfo param) public virtual CppType GetMangleType (ICustomAttributeProvider icap, Type managedType)
{ {
CppType mangleType = new CppType (); 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) if (maa != null)
mangleType = maa.MangleType; mangleType = maa.MangleType;
// this means that either no MangleAsAttribute was defined, or // this means that either no MangleAsAttribute was defined, or
// only CppModifiers were applied .. apply CppType from managed parameter type // only CppModifiers were applied .. apply CppType from managed parameter type
if (mangleType.ElementType == CppTypes.Unknown && mangleType.ElementTypeName == null) 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) else if (mangleType.ElementType == CppTypes.Unknown)
// FIXME: otherwise, we just assume it's CppTypes.Class for now. // FIXME: otherwise, we just assume it's CppTypes.Class for now.
mangleType.ElementType = CppTypes.Class; mangleType.ElementType = CppTypes.Class;

2
Mono.VisualC.Interop/CppInstancePtr.cs

@ -32,8 +32,6 @@ namespace Mono.VisualC.Interop {
if (!implCache.TryGetValue (typeof (Iface), out cachedImpl)) 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); VirtualOnlyAbi virtualABI = new VirtualOnlyAbi (VTableManaged.Implementation, VTable.BindToSignature);
impl = virtualABI.ImplementClass<Iface> (typeof (TWrapper), string.Empty, string.Empty); impl = virtualABI.ImplementClass<Iface> (typeof (TWrapper), string.Empty, string.Empty);
implCache.Add (typeof (Iface), impl); implCache.Add (typeof (Iface), impl);

14
Mono.VisualC.Interop/CppLibrary.cs

@ -28,11 +28,11 @@ namespace Mono.VisualC.Interop {
static CppLibrary () static CppLibrary ()
{ {
AssemblyName assemblyName = new AssemblyName ("__CPPLibraryImplAssembly"); AssemblyName assemblyName = new AssemblyName ("__CppLibraryImplAssembly");
string moduleName = "__CPPLibraryImplModule"; string moduleName = "CppLibraryImplAssembly.dll";
interopAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly (assemblyName, AssemblyBuilderAccess.Run); interopAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly (assemblyName, AssemblyBuilderAccess.RunAndSave);
interopModule = interopAssembly.DefineDynamicModule (moduleName); interopModule = interopAssembly.DefineDynamicModule (moduleName, moduleName, true);
} }
public CppLibrary (string name, CppAbi abi) public CppLibrary (string name, CppAbi abi)
@ -55,6 +55,12 @@ namespace Mono.VisualC.Interop {
get { return abi; } 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 // For working with a class that you are not instantiating
// from managed code and where access to fields is not necessary // from managed code and where access to fields is not necessary
public Iface GetClass<Iface> (string className) public Iface GetClass<Iface> (string className)

2
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; ElementType = CppTypes.Unknown;
ElementTypeName = null; ElementTypeName = null;

32
Mono.VisualC.Interop/IEnumerableTransform.cs

@ -108,6 +108,7 @@ namespace Mono.VisualC.Interop {
return RuleResult.MatchEmit; return RuleResult.MatchEmit;
satisfied = previousRule.SatisfiedBy (input) != RuleResult.NoMatch; satisfied = previousRule.SatisfiedBy (input) != RuleResult.NoMatch;
return RuleResult.NoMatch; return RuleResult.NoMatch;
} }
} }
@ -268,7 +269,6 @@ namespace Mono.VisualC.Interop {
} }
public RuleResult SatisfiedBy (InputData<TIn> input) public RuleResult SatisfiedBy (InputData<TIn> input)
{ {
bool satisfied = false;
foreach (var rule in rules) { foreach (var rule in rules) {
RuleResult result = rule.SatisfiedBy (input.NewContext ()); RuleResult result = rule.SatisfiedBy (input.NewContext ());
if (result != RuleResult.NoMatch) { if (result != RuleResult.NoMatch) {
@ -280,6 +280,22 @@ namespace Mono.VisualC.Interop {
return RuleResult.NoMatch; 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 #endregion
// the base point for building up rules // the base point for building up rules
@ -451,6 +467,15 @@ namespace Mono.VisualC.Interop {
public static class EnumerableSequenceExtensions { 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. // Transforms an IEnumerable into another by specific rules.
public static IEnumerable<TOut> Transform<TIn, TOut> (this IEnumerable<TIn> input, params EmitterFunc<TIn, TOut> [] 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 {
}); });
} }
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) public static EmitterFunc<TIn, TOut> Emit<TIn, TOut> (this IRule<TIn> rule, Func<TIn, TOut> result)
{ {
return delegate (InputData<TIn> input, out TOut output) { return delegate (InputData<TIn> input, out TOut output) {

53
Mono.VisualC.Interop/Util.cs

@ -13,61 +13,22 @@ namespace Mono.VisualC.Interop {
return delType.GetMethod ("Invoke"); 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) public static Type[] GetDelegateParameterTypes (Type delType)
{ {
MethodInfo invoke = GetMethodInfoForDelegate (delType); MethodInfo invoke = GetMethodInfoForDelegate (delType);
if (invoke == null) if (invoke == null)
return 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 (); ParameterInfo[] parameters = method.GetParameters ();
Type[] parameterTypes = new Type [parameters.Length]; Type[] parameterTypes = new Type [parameters.Length];
for (int i = 0; i < parameters.Length; i++) { 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
parameterTypes [i] = parameters [i].ParameterType; parameterTypes [i] = parameters [i].ParameterType;
}
return parameterTypes; return parameterTypes;
} }
@ -94,8 +55,10 @@ namespace Mono.VisualC.Interop {
MarshalAsAttribute existingMarshalAs = param.GetCustomAttributes (typeof (MarshalAsAttribute), MarshalAsAttribute existingMarshalAs = param.GetCustomAttributes (typeof (MarshalAsAttribute),
false).FirstOrDefault () as MarshalAsAttribute; false).FirstOrDefault () as MarshalAsAttribute;
if (forPInvoke && typeof (ICppObject).IsAssignableFrom (param.ParameterType) && /* if (forPInvoke &&
!param.ParameterType.Equals (typeof (CppInstancePtr)) && existingMarshalAs == null) typeof (ICppObject).IsAssignableFrom (param.ParameterType) &&
!param.ParameterType.Equals (typeof (CppInstancePtr)) &&
existingMarshalAs == null)
{ {
ConstructorInfo ctor = typeof (MarshalAsAttribute).GetConstructor (new Type[] { typeof (UnmanagedType) }); ConstructorInfo ctor = typeof (MarshalAsAttribute).GetConstructor (new Type[] { typeof (UnmanagedType) });
object[] args = new object [] { UnmanagedType.CustomMarshaler }; object[] args = new object [] { UnmanagedType.CustomMarshaler };
@ -105,7 +68,7 @@ namespace Mono.VisualC.Interop {
marshalAsAttr = new CustomAttributeBuilder (ctor, args, fields, values); marshalAsAttr = new CustomAttributeBuilder (ctor, args, fields, values);
attr = attr | ParameterAttributes.HasFieldMarshal; 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.. // TODO: This still doesn't feel like it's working right..
ConstructorInfo ctor = typeof (MarshalAsAttribute).GetConstructor (new Type[] { typeof (UnmanagedType) }); ConstructorInfo ctor = typeof (MarshalAsAttribute).GetConstructor (new Type[] { typeof (UnmanagedType) });
object[] args = new object [] { existingMarshalAs.Value }; object[] args = new object [] { existingMarshalAs.Value };

1
QtBindings/Core/QCoreApplication.cs

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

1
QtBindings/Core/QObject.cs

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

2
QtBindings/Core/QString.cs

@ -1,7 +1,9 @@
using System; using System;
using System.Text; using System.Text;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Mono.VisualC.Interop; using Mono.VisualC.Interop;
using Mono.VisualC.Interop.ABI;
namespace Qt.Core { namespace Qt.Core {
//TODO: Will this leak? //TODO: Will this leak?

1
QtBindings/Gui/QAbstractButton.cs

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

3
QtBindings/Gui/QApplication.cs

@ -8,6 +8,7 @@ namespace Qt.Gui {
public class QApplication : QCoreApplication { public class QApplication : QCoreApplication {
#region Sync with qapplication.h #region Sync with qapplication.h
// C++ interface // C++ interface
[VirtualDestructor]
public interface IQApplication : ICppClassOverridable<QApplication>, Base<QCoreApplication.IQCoreApplication> { public interface IQApplication : ICppClassOverridable<QApplication>, Base<QCoreApplication.IQCoreApplication> {
// ... // ...
void QApplication (CppInstancePtr @this, [MangleAs ("int&")] IntPtr argc, 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... // TODO: HACK! Yeah... I'm not calculating the right number of vtable slots somewhere...
// ... add dummy methods until I figure it out... // ... add dummy methods until I figure it out...
/*
[Virtual] void foo1 (CppInstancePtr @this); [Virtual] void foo1 (CppInstancePtr @this);
[Virtual] void foo2 (CppInstancePtr @this); [Virtual] void foo2 (CppInstancePtr @this);
[Virtual] void foo3 (CppInstancePtr @this); [Virtual] void foo3 (CppInstancePtr @this);
[Virtual] void foo4 (CppInstancePtr @this); [Virtual] void foo4 (CppInstancePtr @this);
[Virtual] void foo5 (CppInstancePtr @this); [Virtual] void foo5 (CppInstancePtr @this);
[Virtual] void foo6 (CppInstancePtr @this); [Virtual] void foo6 (CppInstancePtr @this);
*/
} }
// C++ fields // C++ fields
private struct _QApplication { private struct _QApplication {

1
QtBindings/Gui/QPaintDevice.cs

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

3
QtBindings/Gui/QPushButton.cs

@ -6,6 +6,7 @@ namespace Qt.Gui {
public class QPushButton : QAbstractButton { public class QPushButton : QAbstractButton {
#region Sync with qpushbutton.h #region Sync with qpushbutton.h
// C++ interface // C++ interface
[VirtualDestructor]
public interface IQPushButton : ICppClassOverridable<QPushButton>, Base<QAbstractButton.IQAbstractButton> { public interface IQPushButton : ICppClassOverridable<QPushButton>, Base<QAbstractButton.IQAbstractButton> {
// ... // ...
void QPushButton (CppInstancePtr @this, [MangleAs ("const QString &")] ref QString text, QWidget parent); 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); 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 {
public class QWidget : QObject { public class QWidget : QObject {
#region Sync with qwidget.h #region Sync with qwidget.h
// C++ interface // C++ interface
[VirtualDestructor]
public interface IQWidget : ICppClassOverridable<QWidget>, Base<QObject.IQObject>, Base<QPaintDevice.IQPaintDevice> { public interface IQWidget : ICppClassOverridable<QWidget>, Base<QObject.IQObject>, Base<QPaintDevice.IQPaintDevice> {
// ... // ...
void QWidget (CppInstancePtr @this, QWidget parent, /*Qt::WindowFlags */ int f); void QWidget (CppInstancePtr @this, QWidget parent, /*Qt::WindowFlags */ int f);
@ -56,6 +57,7 @@ namespace Qt.Gui {
[Virtual] bool focusNextPrevChild (CppInstancePtr @this, bool next); [Virtual] bool focusNextPrevChild (CppInstancePtr @this, bool next);
// TODO: Determine correct number of vtable slots here too... // TODO: Determine correct number of vtable slots here too...
/*
[Virtual] void foo1 (CppInstancePtr @this); [Virtual] void foo1 (CppInstancePtr @this);
[Virtual] void foo2 (CppInstancePtr @this); [Virtual] void foo2 (CppInstancePtr @this);
[Virtual] void foo3 (CppInstancePtr @this); [Virtual] void foo3 (CppInstancePtr @this);
@ -64,6 +66,7 @@ namespace Qt.Gui {
[Virtual] void foo6 (CppInstancePtr @this); [Virtual] void foo6 (CppInstancePtr @this);
[Virtual] void foo7 (CppInstancePtr @this); [Virtual] void foo7 (CppInstancePtr @this);
[Virtual] void foo8 (CppInstancePtr @this); [Virtual] void foo8 (CppInstancePtr @this);
*/
} }
// C++ fields // C++ fields
private struct _QWidget { private struct _QWidget {

3
QtBindings/Libs.cs

@ -4,7 +4,8 @@ using Mono.VisualC.Interop;
using Mono.VisualC.Interop.ABI; using Mono.VisualC.Interop.ABI;
namespace Qt { namespace Qt {
internal static class Libs { // Will be internal; public for testing
public static class Libs {
public static CppLibrary QtCore = null; public static CppLibrary QtCore = null;
public static CppLibrary QtGui = null; public static CppLibrary QtGui = null;

4
QtTest/Main.cs

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

4
QtTest/QtTest.csproj

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