From bbf5789cab37c35b36866d8096b489cc623ff5e2 Mon Sep 17 00:00:00 2001 From: Zoltan Varga Date: Mon, 28 Feb 2011 17:51:41 +0100 Subject: [PATCH] Rewrite pinvoke marshalling to fix support for passing classes by ref/by value, and returning classes by value. Add support for inline methods. Fix some minor bugs. --- src/Mono.VisualC.Interop/ABI/CppAbi.cs | 302 ++++++++++++++---- .../ABI/Impl/ItaniumAbi.cs | 100 +++++- .../ABI/Impl/ItaniumTypeInfo.cs | 3 + src/Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs | 3 +- src/Mono.VisualC.Interop/CppTypeInfo.cs | 3 +- 5 files changed, 341 insertions(+), 70 deletions(-) diff --git a/src/Mono.VisualC.Interop/ABI/CppAbi.cs b/src/Mono.VisualC.Interop/ABI/CppAbi.cs index a12970b9..1629e7df 100644 --- a/src/Mono.VisualC.Interop/ABI/CppAbi.cs +++ b/src/Mono.VisualC.Interop/ABI/CppAbi.cs @@ -14,11 +14,38 @@ using System.Reflection.Emit; using System.Collections.Generic; using System.Runtime.InteropServices; +using System.Diagnostics; using Mono.VisualC.Interop.Util; namespace Mono.VisualC.Interop.ABI { + // + // Marshalling to be done for a single parameter + // + public enum ParameterMarshal { + Default = 0, + ClassByRef = 1, + ClassByVal = 2 + } + + // + // Describes the signature of the pinvoke wrapper of a c++ method, along with + // marshalling information + // + public class PInvokeSignature { + // The original c# method this signature was generated from + public MethodInfo OrigMethod; + public List ParameterTypes { get; set; } + public List ParameterMarshallers { get; set; } + public Type ReturnType { get; set; } + // Whenever to return a class value + public bool ReturnClass { get; set; } + // Whenever to return a class value by passing a hidden first argument + // Used by the itanium c++ abi + public bool ReturnByAddr { get; set; } + } + //FIXME: Exception handling, operator overloading etc. //FIXME: Allow interface to override default calling convention public abstract partial class CppAbi { @@ -87,7 +114,7 @@ namespace Mono.VisualC.Interop.ABI { var properties = GetProperties (); var methods = GetMethods (); - CppTypeInfo typeInfo = MakeTypeInfo (methods.Where (m => IsVirtual (m))); + CppTypeInfo typeInfo = MakeTypeInfo (methods, methods.Where (m => IsVirtual (m))); // Implement all methods int vtableIndex = 0; @@ -103,7 +130,7 @@ namespace Mono.VisualC.Interop.ABI { return (Iface)Activator.CreateInstance (impl_type.CreateType (), typeInfo); } - protected virtual CppTypeInfo MakeTypeInfo (IEnumerable virtualMethods) + protected virtual CppTypeInfo MakeTypeInfo (IEnumerable methods, IEnumerable virtualMethods) { return new CppTypeInfo (this, virtualMethods, layout_type); } @@ -197,6 +224,8 @@ namespace Mono.VisualC.Interop.ABI { bool isStatic = IsStatic (interfaceMethod); LocalBuilder cppInstancePtr = null; LocalBuilder nativePtr = null; + LocalBuilder retVal = null; + LocalBuilder retArg = null; // If we're an instance method, load up the "this" pointer if (!isStatic) @@ -213,23 +242,75 @@ namespace Mono.VisualC.Interop.ABI { MethodInfo nativeMethod; + var psig = GetPInvokeSignature (typeInfo, interfaceMethod); + + if (psig.ReturnClass) { + Debug.Assert (wrapper_type != null); + retVal = il.DeclareLocal (wrapper_type); + // Construct the manager wrapper object + var ctor = wrapper_type.GetConstructor (BindingFlags.Instance | BindingFlags.NonPublic, null, new Type [] { typeof (CppLibrary) }, null); + Debug.Assert (ctor != null); + il.Emit (OpCodes.Ldnull); + il.Emit (OpCodes.Newobj, ctor); + il.Emit (OpCodes.Stloc, retVal); + + psig.ReturnType = layout_type; + } + + if (psig.ReturnByAddr) { + // + // When using the Itanium c++ abi, some classes are returned by passing a + // hidden first argument. + // + // Put the address of the native return memory into a local + retArg = il.DeclareLocal (typeof (IntPtr)); + il.Emit (OpCodes.Ldloc, retVal); + EmitLoadNativePtr (il); + il.Emit (OpCodes.Stloc, retArg); + psig.ReturnType = typeof (void); + } + if (IsVirtual (interfaceMethod) && methodType != MethodType.NativeDtor) nativeMethod = EmitPrepareVirtualCall (il, typeInfo, nativePtr, vtableIndex++); else - nativeMethod = GetPInvokeForMethod (interfaceMethod); + nativeMethod = GetPInvokeForMethod (interfaceMethod, psig); switch (methodType) { case MethodType.NativeCtor: - EmitConstruct (il, nativeMethod, parameterTypes, nativePtr); + EmitConstruct (il, nativeMethod, psig, nativePtr); break; + case MethodType.NativeDtor: - EmitDestruct (il, nativeMethod, parameterTypes, cppInstancePtr, nativePtr); + EmitDestruct (il, nativeMethod, psig, cppInstancePtr, nativePtr); break; + default: - EmitCallNative (il, nativeMethod, isStatic, parameterTypes, nativePtr); + EmitNativeCall (il, nativeMethod, isStatic, psig, nativePtr, retArg); break; } + if (psig.ReturnClass) { + if (!psig.ReturnByAddr) { + // + // The method return a struct in native format which is on the stack, + // have to copy into the native memory belonging to our object + // + + // Save the method return value + var rval = il.DeclareLocal (layout_type); + il.Emit (OpCodes.Stloc, rval); + // Load the ptr to the native memory (dest) + il.Emit (OpCodes.Ldloc, retVal); + EmitLoadNativePtr (il); + // Load the address of the method return value (src) + il.Emit (OpCodes.Ldloca, rval); + // Copy + il.Emit (OpCodes.Cpobj, layout_type); + } + + il.Emit (OpCodes.Ldloc, retVal); + } + il.Emit (OpCodes.Ret); return trampoline; } @@ -303,13 +384,13 @@ namespace Mono.VisualC.Interop.ABI { if (targetMethod == null) return null; - Type[] parameterTypes = GetParameterTypesForPInvoke (interfaceMethod).ToArray (); + var psig = GetPInvokeSignature (typeInfo, interfaceMethod); // 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. // This does not appear to hold true, so we also disable JIT visibility checks. - DynamicMethod trampolineIn = new DynamicMethod (wrapper_type.Name + "_" + interfaceMethod.Name + "_FromNative", interfaceMethod.ReturnType, - parameterTypes, typeof (CppInstancePtr).Module, true); + DynamicMethod trampolineIn = new DynamicMethod (wrapper_type.Name + "_" + interfaceMethod.Name + "_FromNative", psig.ReturnType, + psig.ParameterTypes.ToArray (), typeof (CppInstancePtr).Module, true); ReflectionHelper.ApplyMethodParameterAttributes (interfaceMethod, trampolineIn, true); ILGenerator il = trampolineIn.GetILGenerator (); @@ -330,7 +411,7 @@ namespace Mono.VisualC.Interop.ABI { il.Emit (OpCodes.Call, getManagedObj); } - for (int i = argLoadStart; i < parameterTypes.Length; i++) { + for (int i = argLoadStart; i < psig.ParameterTypes.Count; i++) { il.Emit (OpCodes.Ldarg, i); } il.Emit (OpCodes.Tailcall); @@ -363,24 +444,29 @@ namespace Mono.VisualC.Interop.ABI { MethodBuilder methodBuilder = impl_type.DefineMethod (interfaceMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual, interfaceMethod.ReturnType, parameterTypes); ReflectionHelper.ApplyMethodParameterAttributes (interfaceMethod, methodBuilder, false); + return methodBuilder; } /** * Defines a new MethodBuilder that calls the specified C++ (non-virtual) method using its mangled name */ - protected virtual MethodBuilder GetPInvokeForMethod (MethodInfo signature) + protected virtual MethodBuilder GetPInvokeForMethod (MethodInfo signature, PInvokeSignature psig) { string entryPoint = GetMangledMethodName (signature); if (entryPoint == null) throw new NotSupportedException ("Could not mangle method name."); - Type [] parameterTypes = GetParameterTypesForPInvoke (signature).ToArray (); + string lib; + if (IsInline (signature)) + lib = library + "-inline"; + else + lib = library; - MethodBuilder builder = impl_type.DefinePInvokeMethod ("__$" + signature.Name + "_Impl", library, entryPoint, - MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.PinvokeImpl, - CallingConventions.Standard, signature.ReturnType, parameterTypes, - GetCallingConvention (signature).Value, CharSet.Ansi); + MethodBuilder builder = impl_type.DefinePInvokeMethod ("__$" + signature.Name + "_Impl", lib, entryPoint, + MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.PinvokeImpl, + CallingConventions.Standard, psig.ReturnType, psig.ParameterTypes.ToArray (), + GetCallingConvention (signature).Value, CharSet.Ansi); builder.SetImplementationFlags (builder.GetMethodImplementationFlags () | MethodImplAttributes.PreserveSig); ReflectionHelper.ApplyMethodParameterAttributes (signature, builder, true); return builder; @@ -419,24 +505,22 @@ namespace Mono.VisualC.Interop.ABI { if (wrapper_type != null) { // load managed wrapper il.Emit (OpCodes.Ldarg_1); - il.Emit (OpCodes.Newobj, typeof (CppInstancePtr).GetConstructor (BindingFlags.Instance | BindingFlags.NonPublic, null, - new Type[] { typeof (int), typeof (object) }, null)); + il.Emit (OpCodes.Newobj, typeof (CppInstancePtr).GetConstructor (BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof (int), typeof (object) }, null)); } else - il.Emit (OpCodes.Newobj, typeof (CppInstancePtr).GetConstructor (BindingFlags.Instance | BindingFlags.NonPublic, null, - new Type[] { typeof (int) }, null)); + il.Emit (OpCodes.Newobj, typeof (CppInstancePtr).GetConstructor (BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof (int) }, null)); } - protected virtual void EmitConstruct (ILGenerator il, MethodInfo nativeMethod, Type [] parameterTypes, + protected virtual void EmitConstruct (ILGenerator il, MethodInfo nativeMethod, + PInvokeSignature psig, LocalBuilder nativePtr) { - EmitCallNative (il, nativeMethod, false, parameterTypes, nativePtr); - // - // FIXME: Why is this needed ? When using the itanium abi, the c++ ctor - // initalizes it. Maybe msvc needs it ? + EmitNativeCall (il, nativeMethod, false, psig, nativePtr, null); + // FIXME: Why is this needed ? The c++ ctor initializes it //EmitInitVTable (il, nativePtr); } - protected virtual void EmitDestruct (ILGenerator il, MethodInfo nativeMethod, Type [] parameterTypes, + protected virtual void EmitDestruct (ILGenerator il, MethodInfo nativeMethod, + PInvokeSignature psig, LocalBuilder cppInstancePtr, LocalBuilder nativePtr) { // bail if we weren't alloc'd by managed code @@ -449,7 +533,7 @@ namespace Mono.VisualC.Interop.ABI { il.Emit (OpCodes.Brfalse_S, bail); EmitResetVTable (il, nativePtr); - EmitCallNative (il, nativeMethod, false, parameterTypes, nativePtr); + EmitNativeCall (il, nativeMethod, false, psig, nativePtr, null); il.MarkLabel (bail); } @@ -459,54 +543,142 @@ 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, Type [] parameterTypes, - LocalBuilder nativePtr) + protected virtual void EmitNativeCall (ILGenerator il, MethodInfo nativeMethod, + bool isStatic, PInvokeSignature psig, + LocalBuilder nativePtr, LocalBuilder retArg) { - int argLoadStart = 1; // For static methods, just strip off arg0 (.net this pointer) - if (!isStatic) - { - argLoadStart = 2; // For instance methods, strip off CppInstancePtr and pass the corresponding IntPtr - il.Emit (OpCodes.Ldloc_S, nativePtr); + // + // The managed signature looks like this: + // (<.net this>, @this (if not static), + // The native signature looks like this: + // (, @this, ) + // + // The managed argument index, skip .net this + int aindex = 1; + + // Do conversions + + LocalBuilder[] args = new LocalBuilder [psig.ParameterTypes.Count]; + aindex = 1; + for (int pindex = 0; pindex < psig.ParameterTypes.Count; pindex++) { + if (!isStatic && pindex == 0) { + // For instance methods, strip off CppInstancePtr and pass the corresponding IntPtr + args [pindex] = nativePtr; + aindex ++; + continue; + } + + Type ptype = psig.ParameterTypes [pindex]; + switch (psig.ParameterMarshallers [pindex]) { + case ParameterMarshal.Default: + // FIXME: Why is this needed ? + // auto marshal bool to C++ bool type (0 = false , 1 = true ) + if (ptype.Equals (typeof (bool))) { + args [pindex] = il.DeclareLocal (typeof (bool)); + Label isTrue = il.DefineLabel (); + Label done = il.DefineLabel (); + il.Emit (OpCodes.Ldarg, aindex); + il.Emit (OpCodes.Brtrue_S, isTrue); + il.Emit (OpCodes.Ldc_I4_0); + il.Emit (OpCodes.Br_S, done); + il.MarkLabel (isTrue); + il.Emit (OpCodes.Ldc_I4_1); + il.MarkLabel (done); + il.Emit (OpCodes.Stloc, args [pindex]); + //il.Emit (OpCodes.Conv_I1); + } + break; + case ParameterMarshal.ClassByRef: { + args [pindex] = il.DeclareLocal (typeof (IntPtr)); + // Pass the native pointer of the class + // Null check + Label isNull = il.DefineLabel (); + Label contLabel = il.DefineLabel (); + il.Emit (OpCodes.Ldarg, aindex); + il.Emit (OpCodes.Brfalse_S, isNull); + // Non-null case + il.Emit (OpCodes.Ldarg, aindex); + EmitLoadNativePtr (il); + // FIXME: Dispose check + il.Emit (OpCodes.Br_S, contLabel); + // Null case + il.MarkLabel (isNull); + il.Emit (OpCodes.Ldnull); + il.Emit (OpCodes.Conv_I); + // Common case + il.MarkLabel (contLabel); + il.Emit (OpCodes.Stloc, args [pindex]); + break; + } + case ParameterMarshal.ClassByVal: { + // Pass a copy of the native memory of the class + args [pindex] = il.DeclareLocal (ptype); + Label normalLabel = il.DefineLabel (); + il.Emit (OpCodes.Ldarg, aindex); + il.Emit (OpCodes.Brtrue_S, normalLabel); + // Null case + il.Emit (OpCodes.Ldstr, "Cannot pass null object of type '" + ptype.DeclaringType + "' to c++ by value"); + il.Emit (OpCodes.Newobj, typeof (ArgumentException).GetConstructor (new Type[] { typeof(string) })); + il.Emit (OpCodes.Throw); + // Non-null case + il.MarkLabel (normalLabel); + // Dest + il.Emit (OpCodes.Ldloca, args [pindex]); + // Load the native ptr of the object (src) + il.Emit (OpCodes.Ldarg, aindex); + EmitLoadNativePtr (il); + // FIXME: Dispose check + // Copy + il.Emit (OpCodes.Cpobj, ptype); + break; + } + default: + throw new NotImplementedException (); + } + + aindex ++; } - for (int i = argLoadStart; i <= parameterTypes.Length; i++) { - il.Emit (OpCodes.Ldarg, i); - EmitSpecialParameterMarshal (il, parameterTypes [i - 1]); + + // Pass arguments + + aindex = 1; + int pindexStart = 0; + + if (retArg != null) { + pindexStart ++; + il.Emit (OpCodes.Ldloc, retArg); } - il.Emit (OpCodes.Call, nativeMethod); - } + for (int pindex = pindexStart; pindex < psig.ParameterTypes.Count; pindex++) { + // The first argument is the .net this argument + if (args [pindex] != null) + il.Emit (OpCodes.Ldloc, args [pindex]); + else + il.Emit (OpCodes.Ldarg, aindex); - // 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 ) - if (parameterType.Equals (typeof (bool))) { - Label isTrue = il.DefineLabel (); - Label done = il.DefineLabel (); - il.Emit (OpCodes.Brtrue_S, isTrue); - il.Emit (OpCodes.Ldc_I4_0); - il.Emit (OpCodes.Br_S, done); - il.MarkLabel (isTrue); - il.Emit (OpCodes.Ldc_I4_1); - il.MarkLabel (done); - //il.Emit (OpCodes.Conv_I1); + aindex ++; } - // auto marshal ICppObject + + // Make the call + + il.Emit (OpCodes.Call, nativeMethod); } - public virtual IEnumerable GetParameterTypesForPInvoke (MethodInfo method) - { + public virtual PInvokeSignature GetPInvokeSignature (CppTypeInfo typeInfo, MethodInfo method) { var originalTypes = ReflectionHelper.GetMethodParameterTypes (method); var pinvokeTypes = originalTypes.Transform ( For.AnyInputIn (typeof (bool)).Emit (typeof (byte)), // CppInstancePtr implements ICppObject - For.InputsWhere ((Type t) => typeof (ICppObject).IsAssignableFrom (t)).Emit (typeof (IntPtr)), + For.InputsWhere ((Type t) => typeof (ICppObject).IsAssignableFrom (t)).Emit (typeof (IntPtr)), For.UnmatchedInput ().Emit (t => t) ); - return pinvokeTypes; + + Type returnType = method.ReturnType; + + return new PInvokeSignature { OrigMethod = method, ParameterTypes = pinvokeTypes.ToList (), ReturnType = returnType }; } /** @@ -584,7 +756,7 @@ namespace Mono.VisualC.Interop.ABI { } protected virtual void EmitLoadInstancePtr (ILGenerator il, Type firstParamType, out LocalBuilder cppip, - out LocalBuilder native) + out LocalBuilder native) { cppip = null; native = null; @@ -607,6 +779,17 @@ namespace Mono.VisualC.Interop.ABI { throw new ArgumentException ("First argument to non-static C++ method must be byref, IntPtr or CppInstancePtr."); } + // Emit obj.Native.Native + // On enter, the stack should contain a reference to a CppInstancePtr + // On exit, it contains an IntPtr + void EmitLoadNativePtr (ILGenerator il) { + LocalBuilder cppip = il.DeclareLocal (typeof (CppInstancePtr)); + il.Emit (OpCodes.Call, typeof (ICppObject).GetMethod ("get_Native")); + il.Emit (OpCodes.Stloc_S, cppip); + il.Emit (OpCodes.Ldloca_S, cppip); + il.Emit (OpCodes.Call, typeof (CppInstancePtr).GetProperty ("Native").GetGetMethod ()); + } + protected virtual void EmitCheckManagedAlloc (ILGenerator il, LocalBuilder cppip) { // make sure we were allocated by managed code @@ -639,5 +822,4 @@ namespace Mono.VisualC.Interop.ABI { } } } - } diff --git a/src/Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs b/src/Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs index f24c5da7..9fd09e1e 100644 --- a/src/Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs +++ b/src/Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs @@ -23,9 +23,19 @@ namespace Mono.VisualC.Interop.ABI { { } - protected override CppTypeInfo MakeTypeInfo (IEnumerable virtualMethods) + protected override CppTypeInfo MakeTypeInfo (IEnumerable methods, IEnumerable virtualMethods) { - return new ItaniumTypeInfo (this, virtualMethods, layout_type); + bool hasExplicitCopyCtor = false; + bool hasExplicitDtor = false; + + foreach (var m in methods) { + if (m.IsDefined (typeof (CopyConstructorAttribute), false) && !m.IsDefined (typeof (ArtificialAttribute), false)) + hasExplicitCopyCtor = true; + if (m.IsDefined (typeof (DestructorAttribute), false) && !m.IsDefined (typeof (ArtificialAttribute), false)) + hasExplicitDtor = true; + } + + return new ItaniumTypeInfo (this, virtualMethods, layout_type) { HasExplicitCopyCtor = hasExplicitCopyCtor, HasExplicitDtor = hasExplicitDtor }; } public override CallingConvention? GetCallingConvention (MethodInfo methodInfo) @@ -35,12 +45,17 @@ namespace Mono.VisualC.Interop.ABI { protected override string GetMangledMethodName (MethodInfo methodInfo) { + var compressMap = new Dictionary (); + string methodName = methodInfo.Name; MethodType methodType = GetMethodType (methodInfo); ParameterInfo [] parameters = methodInfo.GetParameters (); StringBuilder nm = new StringBuilder ("_ZN", 30); nm.Append (class_name.Length).Append (class_name); + compressMap [class_name] = compressMap.Count; + + // FIXME: Implement compression completely switch (methodType) { case MethodType.NativeCtor: @@ -63,12 +78,16 @@ namespace Mono.VisualC.Interop.ABI { nm.Append ('v'); else for (int i = argStart; i < parameters.Length; i++) - nm.Append (GetTypeCode (GetMangleType (parameters [i], parameters [i].ParameterType))); + nm.Append (GetTypeCode (GetMangleType (parameters [i], parameters [i].ParameterType), compressMap)); return nm.ToString (); } - public virtual string GetTypeCode (CppType mangleType) + public virtual string GetTypeCode (CppType mangleType) { + return GetTypeCode (mangleType, new Dictionary ()); + } + + string GetTypeCode (CppType mangleType, Dictionary compressMap) { CppTypes element = mangleType.ElementType; IEnumerable modifiers = mangleType.Modifiers; @@ -102,16 +121,81 @@ namespace Mono.VisualC.Interop.ABI { case CppTypes.Class: case CppTypes.Struct: case CppTypes.Union: - case CppTypes.Enum: - code.Append(mangleType.ElementTypeName.Length); - code.Append(mangleType.ElementTypeName); + case CppTypes.Enum: { + int cid; + if (compressMap.TryGetValue (mangleType.ElementTypeName, out cid)) { + if (cid == 0) + code.Append ("S_"); + else + throw new NotImplementedException (); + } else { + code.Append(mangleType.ElementTypeName.Length); + code.Append(mangleType.ElementTypeName); + } break; - + } } return code.ToString (); } + public override PInvokeSignature GetPInvokeSignature (CppTypeInfo typeInfo, MethodInfo method) { + Type returnType = method.ReturnType; + + bool retClass = false; + bool retByAddr = false; + + if (typeof (ICppObject).IsAssignableFrom (returnType)) { + retClass = true; + if ((typeInfo as ItaniumTypeInfo).HasExplicitCopyCtor || + (typeInfo as ItaniumTypeInfo).HasExplicitDtor) { + // Section 3.1.4: + // Classes with non-default copy ctors/destructors are returned using a + // hidden argument + retByAddr = true; + } + } + + ParameterInfo[] parameters = method.GetParameters (); + + var ptypes = new List (); + var pmarshal = new List (); + // FIXME: Handle ByVal attributes + foreach (var pi in parameters) { + Type t = pi.ParameterType; + Type ptype = t; + ParameterMarshal m = ParameterMarshal.Default; + + if (t == typeof (bool)) { + ptype = typeof (byte); + } else if (typeof (ICppObject).IsAssignableFrom (t) && t != typeof (CppInstancePtr)) { + if (pi.IsDefined (typeof (ByValAttribute), false)) { + m = ParameterMarshal.ClassByVal; + // Can't use an interface/cattr since the native layout type is private + // Pass it as a type argument to I ? + var f = t.GetField ("native_layout", BindingFlags.Static|BindingFlags.NonPublic); + if (f == null || f.FieldType != typeof (Type)) + throw new NotImplementedException ("Type '" + t + "' needs to have a 'native_layout' field before it can be passed by value."); + ptype = (Type)f.GetValue (null); + } else { + ptype = typeof (IntPtr); + m = ParameterMarshal.ClassByRef; + } + } else if (typeof (ICppObject).IsAssignableFrom (t)) { + // CppInstancePtr implements ICppObject + ptype = typeof (IntPtr); + } + ptypes.Add (ptype); + pmarshal.Add (m); + } + + if (retByAddr) { + ptypes.Insert (0, typeof (IntPtr)); + pmarshal.Insert (0, ParameterMarshal.Default); + } + + return new PInvokeSignature { OrigMethod = method, ParameterTypes = ptypes, ParameterMarshallers = pmarshal, ReturnType = returnType, ReturnClass = retClass, ReturnByAddr = retByAddr }; + } } diff --git a/src/Mono.VisualC.Interop/ABI/Impl/ItaniumTypeInfo.cs b/src/Mono.VisualC.Interop/ABI/Impl/ItaniumTypeInfo.cs index 0d49970f..d3bbbffc 100644 --- a/src/Mono.VisualC.Interop/ABI/Impl/ItaniumTypeInfo.cs +++ b/src/Mono.VisualC.Interop/ABI/Impl/ItaniumTypeInfo.cs @@ -26,6 +26,9 @@ namespace Mono.VisualC.Interop.ABI { get { return hasVirtualDtor; } } + public bool HasExplicitCopyCtor { get; set; } + public bool HasExplicitDtor { get; set; } + public override void AddBase (CppTypeInfo baseType) { if (TypeComplete) diff --git a/src/Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs b/src/Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs index 714f381f..c0b31dac 100644 --- a/src/Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs +++ b/src/Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs @@ -25,7 +25,7 @@ namespace Mono.VisualC.Interop.ABI { { } - protected override CppTypeInfo MakeTypeInfo (IEnumerable virtualMethods) + protected override CppTypeInfo MakeTypeInfo (IEnumerable methods, IEnumerable virtualMethods) { return new MsvcTypeInfo (this, virtualMethods, layout_type); } @@ -190,6 +190,7 @@ namespace Mono.VisualC.Interop.ABI { code.Append(mangleType.ElementTypeName); code.Append ("@@"); break; + } return code.ToString (); diff --git a/src/Mono.VisualC.Interop/CppTypeInfo.cs b/src/Mono.VisualC.Interop/CppTypeInfo.cs index f23dd34c..7819d975 100644 --- a/src/Mono.VisualC.Interop/CppTypeInfo.cs +++ b/src/Mono.VisualC.Interop/CppTypeInfo.cs @@ -179,7 +179,8 @@ namespace Mono.VisualC.Interop { public virtual DelegateSignature GetVTableDelegateSignature (int index) { MethodInfo method = VirtualMethods [index]; - return new DelegateSignature () { ParameterTypes = Abi.GetParameterTypesForPInvoke (method), + var psig = Abi.GetPInvokeSignature (this, method); + return new DelegateSignature () { ParameterTypes = psig.ParameterTypes, ReturnType = method.ReturnType, CallingConvention = Abi.GetCallingConvention (method) }; }