Browse Source

Convert spaces to tabs.

pull/1/head
Zoltan Varga 15 years ago committed by Andreia Gaita
parent
commit
c6c8291b41
  1. 847
      src/Mono.VisualC.Interop/ABI/CppAbi.cs
  2. 20
      src/Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs
  3. 21
      src/Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs
  4. 50
      src/Mono.VisualC.Interop/ABI/Impl/VirtualOnlyAbi.cs
  5. 14
      src/Mono.VisualC.Interop/ABI/MethodType.cs
  6. 230
      src/Mono.VisualC.Interop/ABI/VTable.cs
  7. 27
      src/Mono.VisualC.Interop/ABI/VTableManaged.cs
  8. 74
      src/Mono.VisualC.Interop/Attributes.cs
  9. 64
      src/Mono.VisualC.Interop/CppField.cs
  10. 237
      src/Mono.VisualC.Interop/CppInstancePtr.cs
  11. 63
      src/Mono.VisualC.Interop/CppLibrary.cs
  12. 86
      src/Mono.VisualC.Interop/CppObjectMarshaler.cs
  13. 10
      src/Mono.VisualC.Interop/CppTypeInfo.cs
  14. 30
      src/Mono.VisualC.Interop/Interfaces.cs
  15. 23
      src/Mono.VisualC.Interop/Util/DelegateTypeCache.cs
  16. 2
      src/Mono.VisualC.Interop/Util/IEnumerableTransform.cs
  17. 5
      src/Mono.VisualC.Interop/Util/MethodSignature.cs
  18. 163
      src/Mono.VisualC.Interop/Util/ReflectionHelper.cs

847
src/Mono.VisualC.Interop/ABI/CppAbi.cs

@ -19,18 +19,17 @@ using Mono.VisualC.Interop.Util;
namespace Mono.VisualC.Interop.ABI { namespace Mono.VisualC.Interop.ABI {
//FIXME: Exception handling, operator overloading etc. //FIXME: Exception handling, operator overloading etc.
//FIXME: Allow interface to override default calling convention //FIXME: Allow interface to override default calling convention
public abstract partial class CppAbi { public abstract partial class CppAbi {
protected ModuleBuilder impl_module;
protected TypeBuilder impl_type;
protected ModuleBuilder impl_module; protected Type interface_type, layout_type, wrapper_type;
protected TypeBuilder impl_type; protected string library, class_name;
protected Type interface_type, layout_type, wrapper_type; protected FieldBuilder typeinfo_field;
protected string library, class_name; protected ILGenerator ctor_il;
protected FieldBuilder typeinfo_field;
protected ILGenerator ctor_il;
protected MemberFilter vtable_override_filter = VTable.BindToSignatureAndAttribute; protected MemberFilter vtable_override_filter = VTable.BindToSignatureAndAttribute;
@ -41,19 +40,19 @@ namespace Mono.VisualC.Interop.ABI {
private static readonly MethodInfo vtable_initinstance = typeof (VTable).GetMethod ("InitInstance"); private static readonly MethodInfo vtable_initinstance = typeof (VTable).GetMethod ("InitInstance");
private static readonly MethodInfo vtable_resetinstance = typeof (VTable).GetMethod ("ResetInstance"); private static readonly MethodInfo vtable_resetinstance = typeof (VTable).GetMethod ("ResetInstance");
// These methods might be more commonly overridden for a given C++ ABI: // These methods might be more commonly overridden for a given C++ ABI:
public virtual MethodType GetMethodType (MethodInfo imethod)
{
if (imethod.IsDefined (typeof (ConstructorAttribute), false))
return MethodType.NativeCtor;
else if (imethod.Name.Equals ("Alloc"))
return MethodType.ManagedAlloc;
else if (imethod.IsDefined (typeof (DestructorAttribute), false))
return MethodType.NativeDtor;
return MethodType.Native; public virtual MethodType GetMethodType (MethodInfo imethod)
} {
if (imethod.IsDefined (typeof (ConstructorAttribute), false))
return MethodType.NativeCtor;
else if (imethod.Name.Equals ("Alloc"))
return MethodType.ManagedAlloc;
else if (imethod.IsDefined (typeof (DestructorAttribute), false))
return MethodType.NativeDtor;
return MethodType.Native;
}
// The members below must be implemented for a given C++ ABI: // The members below must be implemented for a given C++ ABI:
@ -73,38 +72,36 @@ namespace Mono.VisualC.Interop.ABI {
return this.ImplementClass<Iface,EmptyNativeLayout> (wrapperType, lib, className); return this.ImplementClass<Iface,EmptyNativeLayout> (wrapperType, lib, className);
} }
public virtual Iface ImplementClass<Iface, NLayout> (Type wrapperType, string lib, string className) public virtual Iface ImplementClass<Iface, NLayout> (Type wrapperType, string lib, string className)
where NLayout : struct where NLayout : struct
//where Iface : ICppClassInstantiatable or ICppClassOverridable //where Iface : ICppClassInstantiatable or ICppClassOverridable
{ {
this.impl_module = CppLibrary.interopModule; this.impl_module = CppLibrary.interopModule;
this.library = lib; this.library = lib;
this.class_name = className; this.class_name = className;
this.interface_type = typeof (Iface); this.interface_type = typeof (Iface);
this.layout_type = typeof (NLayout); this.layout_type = typeof (NLayout);
this.wrapper_type = wrapperType; this.wrapper_type = wrapperType;
DefineImplType ();
var properties = GetProperties ();
var methods = GetMethods ();
CppTypeInfo typeInfo = MakeTypeInfo (methods.Where (m => IsVirtual (m)));
DefineImplType ();
var properties = GetProperties ();
var methods = GetMethods ();
CppTypeInfo typeInfo = MakeTypeInfo (methods.Where (m => IsVirtual (m)));
// Implement all methods // Implement all methods
int vtableIndex = 0; int vtableIndex = 0;
foreach (var method in methods) foreach (var method in methods)
DefineMethod (method, typeInfo, ref vtableIndex); DefineMethod (method, typeInfo, ref vtableIndex);
// Implement all properties
foreach (var property in properties)
DefineProperty (property);
ctor_il.Emit (OpCodes.Ret); // Implement all properties
foreach (var property in properties)
DefineProperty (property);
ctor_il.Emit (OpCodes.Ret);
return (Iface)Activator.CreateInstance (impl_type.CreateType (), typeInfo); return (Iface)Activator.CreateInstance (impl_type.CreateType (), typeInfo);
} }
protected virtual CppTypeInfo MakeTypeInfo (IEnumerable<MethodInfo> virtualMethods) protected virtual CppTypeInfo MakeTypeInfo (IEnumerable<MethodInfo> virtualMethods)
{ {
@ -141,258 +138,253 @@ namespace Mono.VisualC.Interop.ABI {
return methods; return methods;
} }
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";
impl_type = impl_module.DefineType (implTypeName, TypeAttributes.Class | TypeAttributes.Sealed); impl_type = impl_module.DefineType (implTypeName, TypeAttributes.Class | TypeAttributes.Sealed);
impl_type.AddInterfaceImplementation (interface_type); impl_type.AddInterfaceImplementation (interface_type);
//vtable_field = impl_type.DefineField ("_vtable", typeof (VTable), FieldAttributes.InitOnly | FieldAttributes.Private); //vtable_field = impl_type.DefineField ("_vtable", typeof (VTable), FieldAttributes.InitOnly | FieldAttributes.Private);
//native_size_field = impl_type.DefineField ("_nativeSize", typeof (int), FieldAttributes.InitOnly | FieldAttributes.Private); //native_size_field = impl_type.DefineField ("_nativeSize", typeof (int), FieldAttributes.InitOnly | FieldAttributes.Private);
typeinfo_field = impl_type.DefineField ("_typeInfo", typeof (CppTypeInfo), FieldAttributes.InitOnly | FieldAttributes.Private); typeinfo_field = impl_type.DefineField ("_typeInfo", typeof (CppTypeInfo), FieldAttributes.InitOnly | FieldAttributes.Private);
ConstructorBuilder ctor = impl_type.DefineConstructor (MethodAttributes.Public, CallingConventions.Standard, ConstructorBuilder ctor = impl_type.DefineConstructor (MethodAttributes.Public, CallingConventions.Standard,
new Type[] { typeof (CppTypeInfo) }); new Type[] { typeof (CppTypeInfo) });
ctor_il = ctor.GetILGenerator (); ctor_il = ctor.GetILGenerator ();
// this._typeInfo = (CppTypeInfo passed to constructor) // this._typeInfo = (CppTypeInfo passed to constructor)
ctor_il.Emit (OpCodes.Ldarg_0); ctor_il.Emit (OpCodes.Ldarg_0);
ctor_il.Emit (OpCodes.Ldarg_1); ctor_il.Emit (OpCodes.Ldarg_1);
ctor_il.Emit (OpCodes.Stfld, typeinfo_field); ctor_il.Emit (OpCodes.Stfld, typeinfo_field);
/* /*
// this._vtable = (VTable passed to constructor) // this._vtable = (VTable passed to constructor)
ctor_il.Emit (OpCodes.Ldarg_0); ctor_il.Emit (OpCodes.Ldarg_0);
ctor_il.Emit (OpCodes.Ldarg_1); ctor_il.Emit (OpCodes.Ldarg_1);
ctor_il.Emit (OpCodes.Stfld, vtable_field); ctor_il.Emit (OpCodes.Stfld, vtable_field);
// this._nativeSize = (native size passed to constructor) // this._nativeSize = (native size passed to constructor)
ctor_il.Emit (OpCodes.Ldarg_0); ctor_il.Emit (OpCodes.Ldarg_0);
ctor_il.Emit (OpCodes.Ldarg_2); ctor_il.Emit (OpCodes.Ldarg_2);
ctor_il.Emit (OpCodes.Stfld, native_size_field); ctor_il.Emit (OpCodes.Stfld, native_size_field);
*/ */
} }
protected virtual MethodBuilder DefineMethod (MethodInfo interfaceMethod, CppTypeInfo typeInfo, ref int vtableIndex)
{
// 0. Introspect method
MethodType methodType = GetMethodType (interfaceMethod);
Type [] parameterTypes = ReflectionHelper.GetMethodParameterTypes (interfaceMethod);
// 1. Generate managed trampoline to call native method
MethodBuilder trampoline = GetMethodBuilder (interfaceMethod);
ILGenerator il = trampoline.GetILGenerator ();
if (methodType == MethodType.NoOp) {
// return NULL if method is supposed to return a value
// FIXME: this will make value types explode?
if (!interfaceMethod.ReturnType.Equals (typeof (void)))
il.Emit (OpCodes.Ldnull);
il.Emit (OpCodes.Ret);
return trampoline;
} else if (methodType == MethodType.ManagedAlloc) {
EmitManagedAlloc (il, interfaceMethod);
il.Emit (OpCodes.Ret);
return trampoline;
}
bool isStatic = IsStatic (interfaceMethod);
LocalBuilder cppInstancePtr = null;
LocalBuilder nativePtr = null;
// If we're an instance method, load up the "this" pointer
if (!isStatic)
{
if (parameterTypes.Length < 1)
throw new ArgumentException ("First argument to non-static C++ method must be IntPtr or CppInstancePtr.");
// 2. Load the native C++ instance pointer
EmitLoadInstancePtr (il, parameterTypes [0], out cppInstancePtr, out nativePtr);
// 3. Make sure our native pointer is a valid reference. If not, throw ObjectDisposedException
EmitCheckDisposed (il, nativePtr, methodType);
}
MethodInfo nativeMethod;
if (IsVirtual (interfaceMethod) && methodType != MethodType.NativeDtor)
nativeMethod = EmitPrepareVirtualCall (il, typeInfo, nativePtr, vtableIndex++);
else
nativeMethod = GetPInvokeForMethod (interfaceMethod);
switch (methodType) { protected virtual MethodBuilder DefineMethod (MethodInfo interfaceMethod, CppTypeInfo typeInfo, ref int vtableIndex)
case MethodType.NativeCtor: {
EmitConstruct (il, nativeMethod, parameterTypes, nativePtr); // 0. Introspect method
break; MethodType methodType = GetMethodType (interfaceMethod);
Type [] parameterTypes = ReflectionHelper.GetMethodParameterTypes (interfaceMethod);
// 1. Generate managed trampoline to call native method
MethodBuilder trampoline = GetMethodBuilder (interfaceMethod);
ILGenerator il = trampoline.GetILGenerator ();
if (methodType == MethodType.NoOp) {
// return NULL if method is supposed to return a value
// FIXME: this will make value types explode?
if (!interfaceMethod.ReturnType.Equals (typeof (void)))
il.Emit (OpCodes.Ldnull);
il.Emit (OpCodes.Ret);
return trampoline;
} else if (methodType == MethodType.ManagedAlloc) {
EmitManagedAlloc (il, interfaceMethod);
il.Emit (OpCodes.Ret);
return trampoline;
}
bool isStatic = IsStatic (interfaceMethod);
LocalBuilder cppInstancePtr = null;
LocalBuilder nativePtr = null;
case MethodType.NativeDtor: // If we're an instance method, load up the "this" pointer
EmitDestruct (il, nativeMethod, parameterTypes, cppInstancePtr, nativePtr); if (!isStatic)
break; {
if (parameterTypes.Length < 1)
throw new ArgumentException ("First argument to non-static C++ method must be IntPtr or CppInstancePtr.");
default: // 2. Load the native C++ instance pointer
EmitCallNative (il, nativeMethod, isStatic, parameterTypes, nativePtr); EmitLoadInstancePtr (il, parameterTypes [0], out cppInstancePtr, out nativePtr);
break;
} // 3. Make sure our native pointer is a valid reference. If not, throw ObjectDisposedException
EmitCheckDisposed (il, nativePtr, methodType);
}
MethodInfo nativeMethod;
il.Emit (OpCodes.Ret); if (IsVirtual (interfaceMethod) && methodType != MethodType.NativeDtor)
return trampoline; nativeMethod = EmitPrepareVirtualCall (il, typeInfo, nativePtr, vtableIndex++);
} else
nativeMethod = GetPInvokeForMethod (interfaceMethod);
switch (methodType) {
case MethodType.NativeCtor:
EmitConstruct (il, nativeMethod, parameterTypes, nativePtr);
break;
case MethodType.NativeDtor:
EmitDestruct (il, nativeMethod, parameterTypes, cppInstancePtr, nativePtr);
break;
default:
EmitCallNative (il, nativeMethod, isStatic, parameterTypes, nativePtr);
break;
}
protected virtual PropertyBuilder DefineProperty (PropertyInfo property) il.Emit (OpCodes.Ret);
{ return trampoline;
if (property.CanWrite) }
throw new InvalidProgramException ("Properties in C++ interface must be read-only.");
MethodInfo imethod = property.GetGetMethod (); protected virtual PropertyBuilder DefineProperty (PropertyInfo property)
string methodName = imethod.Name; {
string propName = property.Name; if (property.CanWrite)
Type retType = imethod.ReturnType; throw new InvalidProgramException ("Properties in C++ interface must be read-only.");
FieldBuilder fieldData;
// C++ interface properties are either to return the CppTypeInfo or to access C++ fields MethodInfo imethod = property.GetGetMethod ();
if (retType.IsGenericType && retType.GetGenericTypeDefinition ().Equals (typeof (CppField<>))) { string methodName = imethod.Name;
string propName = property.Name;
Type retType = imethod.ReturnType;
FieldBuilder fieldData;
// C++ interface properties are either to return the CppTypeInfo or to access C++ fields
if (retType.IsGenericType && retType.GetGenericTypeDefinition ().Equals (typeof (CppField<>))) {
// define a new field for the property // define a new field for the property
// fieldData = impl_type.DefineField ("__" + propName + "_Data", retType, FieldAttributes.InitOnly | FieldAttributes.Private); // fieldData = impl_type.DefineField ("__" + propName + "_Data", retType, FieldAttributes.InitOnly | FieldAttributes.Private);
// init our field data with a new instance of CppField // init our field data with a new instance of CppField
// first, get field offset // first, get field offset
//ctor_il.Emit (OpCodes.Ldarg_0); //ctor_il.Emit (OpCodes.Ldarg_0);
/* TODO: Code prolly should not emit hardcoded offsets n such, in case we end up saving these assemblies in the future. /* TODO: Code prolly should not emit hardcoded offsets n such, in case we end up saving these assemblies in the future.
* Something more like this perhaps? (need to figure out how to get field offset padding into this) * Something more like this perhaps? (need to figure out how to get field offset padding into this)
* ctorIL.Emit(OpCodes.Ldtoken, nativeLayout); * ctorIL.Emit(OpCodes.Ldtoken, nativeLayout);
* ctorIL.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle")); * ctorIL.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
* ctorIL.Emit(OpCodes.Ldstr, propName); * ctorIL.Emit(OpCodes.Ldstr, propName);
* ctorIL.Emit(OpCodes.Call, typeof(Marshal).GetMethod("OffsetOf")); * ctorIL.Emit(OpCodes.Call, typeof(Marshal).GetMethod("OffsetOf"));
*/ */
/* /*
int fieldOffset = ((int)Marshal.OffsetOf (layout_type, propName)) + FieldOffsetPadding; int fieldOffset = ((int)Marshal.OffsetOf (layout_type, propName)) + FieldOffsetPadding;
ctor_il.Emit (OpCodes.Ldc_I4, fieldOffset); ctor_il.Emit (OpCodes.Ldc_I4, fieldOffset);
ctor_il.Emit (OpCodes.Newobj, retType.GetConstructor (new Type[] { typeof(int) })); ctor_il.Emit (OpCodes.Newobj, retType.GetConstructor (new Type[] { typeof(int) }));
ctor_il.Emit (OpCodes.Stfld, fieldData); ctor_il.Emit (OpCodes.Stfld, fieldData);
*/ */
throw new NotImplementedException ("CppFields need to be reimplemented to use CppTypeInfo."); throw new NotImplementedException ("CppFields need to be reimplemented to use CppTypeInfo.");
} else if (retType.Equals (typeof (CppTypeInfo))) } else if (retType.Equals (typeof (CppTypeInfo)))
fieldData = typeinfo_field; fieldData = typeinfo_field;
else else
throw new InvalidProgramException ("Properties in C++ interface can only be of type CppField."); throw new InvalidProgramException ("Properties in C++ interface can only be of type CppField.");
PropertyBuilder fieldProp = impl_type.DefineProperty (propName, PropertyAttributes.None, retType, Type.EmptyTypes); PropertyBuilder fieldProp = impl_type.DefineProperty (propName, PropertyAttributes.None, retType, Type.EmptyTypes);
MethodAttributes methodAttr = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.HideBySig; MethodAttributes methodAttr = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
MethodBuilder fieldGetter = impl_type.DefineMethod (methodName, methodAttr, retType, Type.EmptyTypes); MethodBuilder fieldGetter = impl_type.DefineMethod (methodName, methodAttr, retType, Type.EmptyTypes);
ILGenerator il = fieldGetter.GetILGenerator (); ILGenerator il = fieldGetter.GetILGenerator ();
il.Emit (OpCodes.Ldarg_0); il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, fieldData); il.Emit (OpCodes.Ldfld, fieldData);
il.Emit (OpCodes.Ret); il.Emit (OpCodes.Ret);
fieldProp.SetGetMethod (fieldGetter); fieldProp.SetGetMethod (fieldGetter);
return fieldProp; return fieldProp;
} }
/** /**
* 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.
*/ */
internal virtual Delegate GetManagedOverrideTrampoline (CppTypeInfo typeInfo, int vtableIndex) internal virtual Delegate GetManagedOverrideTrampoline (CppTypeInfo typeInfo, int vtableIndex)
{ {
if (wrapper_type == null) if (wrapper_type == null)
return null; return null;
MethodInfo interfaceMethod = typeInfo.VirtualMethods [vtableIndex]; MethodInfo interfaceMethod = typeInfo.VirtualMethods [vtableIndex];
MethodInfo targetMethod = FindManagedOverrideTarget (interfaceMethod); MethodInfo targetMethod = FindManagedOverrideTarget (interfaceMethod);
if (targetMethod == null) if (targetMethod == null)
return null; return null;
Type[] parameterTypes = GetParameterTypesForPInvoke (interfaceMethod).ToArray (); Type[] parameterTypes = GetParameterTypesForPInvoke (interfaceMethod).ToArray ();
// 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.
// This does not appear to hold true, so we also disable JIT visibility checks. // 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, DynamicMethod trampolineIn = new DynamicMethod (wrapper_type.Name + "_" + interfaceMethod.Name + "_FromNative", interfaceMethod.ReturnType,
parameterTypes, typeof (CppInstancePtr).Module, true); parameterTypes, typeof (CppInstancePtr).Module, true);
ReflectionHelper.ApplyMethodParameterAttributes (interfaceMethod, trampolineIn, true); ReflectionHelper.ApplyMethodParameterAttributes (interfaceMethod, trampolineIn, true);
ILGenerator il = trampolineIn.GetILGenerator (); ILGenerator il = trampolineIn.GetILGenerator ();
// for static methods: // for static methods:
OpCode callInstruction = OpCodes.Call; OpCode callInstruction = OpCodes.Call;
int argLoadStart = 1; int argLoadStart = 1;
// for instance methods, we need an instance to call them on! // for instance methods, we need an instance to call them on!
if (!targetMethod.IsStatic) { if (!targetMethod.IsStatic) {
callInstruction = OpCodes.Callvirt; callInstruction = OpCodes.Callvirt;
//argLoadStart = 1; //argLoadStart = 1;
il.Emit (OpCodes.Ldarg_0); il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldc_I4, typeInfo.NativeSize); il.Emit (OpCodes.Ldc_I4, typeInfo.NativeSize);
MethodInfo getManagedObj = typeof (CppInstancePtr).GetMethod ("GetManaged", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod (wrapper_type); MethodInfo getManagedObj = typeof (CppInstancePtr).GetMethod ("GetManaged", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod (wrapper_type);
il.Emit (OpCodes.Call, getManagedObj); il.Emit (OpCodes.Call, getManagedObj);
} }
for (int i = argLoadStart; i < parameterTypes.Length; i++) { for (int i = argLoadStart; i < parameterTypes.Length; i++) {
il.Emit (OpCodes.Ldarg, i); il.Emit (OpCodes.Ldarg, i);
} }
il.Emit (OpCodes.Tailcall); il.Emit (OpCodes.Tailcall);
il.Emit (callInstruction, targetMethod); il.Emit (callInstruction, targetMethod);
il.Emit (OpCodes.Ret); il.Emit (OpCodes.Ret);
return trampolineIn.CreateDelegate (typeInfo.VTableDelegateTypes [vtableIndex]); return trampolineIn.CreateDelegate (typeInfo.VTableDelegateTypes [vtableIndex]);
} }
protected virtual MethodInfo FindManagedOverrideTarget (MethodInfo interfaceMethod) protected virtual MethodInfo FindManagedOverrideTarget (MethodInfo interfaceMethod)
{ {
// FIXME: Does/should this look in superclasses? // FIXME: Does/should this look in superclasses?
MemberInfo [] possibleMembers = wrapper_type.FindMembers (MemberTypes.Method, BindingFlags.Public | BindingFlags.NonPublic | MemberInfo [] possibleMembers = wrapper_type.FindMembers (MemberTypes.Method, BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.Static, vtable_override_filter, interfaceMethod); BindingFlags.Instance | BindingFlags.Static, vtable_override_filter, interfaceMethod);
if (possibleMembers.Length > 1) if (possibleMembers.Length > 1)
throw new InvalidProgramException ("More than one possible override found when binding virtual method: " + interfaceMethod.Name); throw new InvalidProgramException ("More than one possible override found when binding virtual method: " + interfaceMethod.Name);
else if (possibleMembers.Length == 0) else if (possibleMembers.Length == 0)
return null; return null;
return (MethodInfo)possibleMembers [0]; return (MethodInfo)possibleMembers [0];
} }
/** /**
* Defines a new MethodBuilder with the same signature as the passed MethodInfo * Defines a new MethodBuilder with the same signature as the passed MethodInfo
*/ */
protected virtual MethodBuilder GetMethodBuilder (MethodInfo interfaceMethod) protected virtual MethodBuilder GetMethodBuilder (MethodInfo interfaceMethod)
{ {
Type [] parameterTypes = ReflectionHelper.GetMethodParameterTypes (interfaceMethod);
Type [] parameterTypes = ReflectionHelper.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); ReflectionHelper.ApplyMethodParameterAttributes (interfaceMethod, methodBuilder, false);
ReflectionHelper.ApplyMethodParameterAttributes (interfaceMethod, methodBuilder, false); return methodBuilder;
return methodBuilder; }
}
/**
/** * Defines a new MethodBuilder that calls the specified C++ (non-virtual) method using its mangled name
* 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) {
{ string entryPoint = GetMangledMethodName (signature);
string entryPoint = GetMangledMethodName (signature); if (entryPoint == null)
if (entryPoint == null) throw new NotSupportedException ("Could not mangle method name.");
throw new NotSupportedException ("Could not mangle method name.");
Type [] parameterTypes = GetParameterTypesForPInvoke (signature).ToArray ();
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.Standard, signature.ReturnType, parameterTypes, CallingConventions.Standard, signature.ReturnType, parameterTypes,
GetCallingConvention (signature).Value, CharSet.Ansi); GetCallingConvention (signature).Value, CharSet.Ansi);
builder.SetImplementationFlags (builder.GetMethodImplementationFlags () | MethodImplAttributes.PreserveSig); builder.SetImplementationFlags (builder.GetMethodImplementationFlags () | MethodImplAttributes.PreserveSig);
ReflectionHelper.ApplyMethodParameterAttributes (signature, builder, true); ReflectionHelper.ApplyMethodParameterAttributes (signature, builder, true);
return builder; return builder;
} }
/** /**
* Emits the IL to load the correct delegate instance and/or retrieve the MethodInfo from the VTable * Emits the IL to load the correct delegate instance and/or retrieve the MethodInfo from the VTable
@ -413,73 +405,73 @@ namespace Mono.VisualC.Interop.ABI {
return ReflectionHelper.GetMethodInfoForDelegate (vtableDelegateType); return ReflectionHelper.GetMethodInfoForDelegate (vtableDelegateType);
} }
/** /**
* 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.
*/ */
protected virtual void EmitManagedAlloc (ILGenerator il, MethodInfo interfaceMethod) protected virtual void EmitManagedAlloc (ILGenerator il, MethodInfo interfaceMethod)
{ {
// this._typeInfo.NativeSize // this._typeInfo.NativeSize
il.Emit (OpCodes.Ldarg_0); il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, typeinfo_field); il.Emit (OpCodes.Ldfld, typeinfo_field);
il.Emit (OpCodes.Callvirt, typeinfo_nativesize); il.Emit (OpCodes.Callvirt, typeinfo_nativesize);
if (wrapper_type != null) { if (wrapper_type != null) {
// load managed wrapper // load managed wrapper
il.Emit (OpCodes.Ldarg_1); il.Emit (OpCodes.Ldarg_1);
il.Emit (OpCodes.Newobj, typeof (CppInstancePtr).GetConstructor (BindingFlags.Instance | BindingFlags.NonPublic, null, il.Emit (OpCodes.Newobj, typeof (CppInstancePtr).GetConstructor (BindingFlags.Instance | BindingFlags.NonPublic, null,
new Type[] { typeof (int), typeof (object) }, null)); new Type[] { typeof (int), typeof (object) }, null));
} else } else
il.Emit (OpCodes.Newobj, typeof (CppInstancePtr).GetConstructor (BindingFlags.Instance | BindingFlags.NonPublic, null, il.Emit (OpCodes.Newobj, typeof (CppInstancePtr).GetConstructor (BindingFlags.Instance | BindingFlags.NonPublic, null,
new Type[] { typeof (int) }, null)); new Type[] { typeof (int) }, null));
} }
protected virtual void EmitConstruct (ILGenerator il, MethodInfo nativeMethod, Type [] parameterTypes, protected virtual void EmitConstruct (ILGenerator il, MethodInfo nativeMethod, Type [] parameterTypes,
LocalBuilder nativePtr) LocalBuilder nativePtr)
{ {
EmitCallNative (il, nativeMethod, false, parameterTypes, nativePtr); EmitCallNative (il, nativeMethod, false, parameterTypes, nativePtr);
EmitInitVTable (il, nativePtr); EmitInitVTable (il, nativePtr);
} }
protected virtual void EmitDestruct (ILGenerator il, MethodInfo nativeMethod, Type [] parameterTypes, protected virtual void EmitDestruct (ILGenerator il, MethodInfo nativeMethod, 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 ();
il.Emit (OpCodes.Ldloca_S, cppInstancePtr); il.Emit (OpCodes.Ldloca_S, cppInstancePtr);
il.Emit (OpCodes.Brfalse_S, bail); // <- FIXME? (would this ever branch?) 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, parameterTypes, nativePtr); EmitCallNative (il, nativeMethod, false, parameterTypes, nativePtr);
il.MarkLabel (bail); il.MarkLabel (bail);
} }
/** /**
* Emits IL to call the native method. nativeMethod should be either a method obtained by * Emits IL to call the native method. nativeMethod should be either a method obtained by
* 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, Type [] parameterTypes, 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)
if (!isStatic) if (!isStatic)
{ {
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 <= parameterTypes.Length; i++) { for (int i = argLoadStart; i <= parameterTypes.Length; i++) {
il.Emit (OpCodes.Ldarg, i); il.Emit (OpCodes.Ldarg, i);
EmitSpecialParameterMarshal (il, parameterTypes [i - 1]); EmitSpecialParameterMarshal (il, parameterTypes [i - 1]);
} }
il.Emit (OpCodes.Call, nativeMethod); il.Emit (OpCodes.Call, nativeMethod);
} }
// Note: when this is modified, usually GetParameterTypesForPInvoke types should be updated too // Note: when this is modified, usually GetParameterTypesForPInvoke types should be updated too
protected virtual void EmitSpecialParameterMarshal (ILGenerator il, Type parameterType) protected virtual void EmitSpecialParameterMarshal (ILGenerator il, Type parameterType)
@ -521,131 +513,128 @@ namespace Mono.VisualC.Interop.ABI {
{ {
// this._typeInfo.VTable // this._typeInfo.VTable
il.Emit (OpCodes.Ldarg_0); il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, typeinfo_field); il.Emit (OpCodes.Ldfld, typeinfo_field);
il.Emit (OpCodes.Callvirt, typeinfo_vtable); il.Emit (OpCodes.Callvirt, typeinfo_vtable);
} }
/** /**
* 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.
*/ */
protected virtual void EmitInitVTable (ILGenerator il, LocalBuilder nativePtr) protected virtual void EmitInitVTable (ILGenerator il, LocalBuilder nativePtr)
{ {
// this._typeInfo.VTable.InitInstance (nativePtr); // this._typeInfo.VTable.InitInstance (nativePtr);
EmitLoadVTable (il); EmitLoadVTable (il);
il.Emit (OpCodes.Ldloc_S, nativePtr); il.Emit (OpCodes.Ldloc_S, nativePtr);
EmitCallVTableMethod (il, vtable_initinstance, 2, false); EmitCallVTableMethod (il, vtable_initinstance, 2, false);
} }
protected virtual void EmitResetVTable (ILGenerator il, LocalBuilder nativePtr) protected virtual void EmitResetVTable (ILGenerator il, LocalBuilder nativePtr)
{ {
// this._typeInfo.VTable.ResetInstance (nativePtr); // this._typeInfo.VTable.ResetInstance (nativePtr);
EmitLoadVTable (il); EmitLoadVTable (il);
il.Emit (OpCodes.Ldloc_S, nativePtr); il.Emit (OpCodes.Ldloc_S, nativePtr);
EmitCallVTableMethod (il, vtable_resetinstance, 2, false); EmitCallVTableMethod (il, vtable_resetinstance, 2, false);
} }
/** /**
* A utility function to emit the IL for a vtable-dependant operation. * A utility function to emit the IL for a vtable-dependant operation.
* In other words, classes with no virtual methods will not have vtables, * In other words, classes with no virtual methods will not have vtables,
* so this method emits code to check for that and either throw an exception * so this method emits code to check for that and either throw an exception
* or do nothing if no vtable exists. To use, push the arguments to the method you * or do nothing if no vtable exists. To use, push the arguments to the method you
* want to call and pass the stackHeight for the call. If no vtable exists, this method * want to call and pass the stackHeight for the call. If no vtable exists, this method
* will emit code to pop the arguments off the stack. * will emit code to pop the arguments off the stack.
*/ */
protected virtual void EmitCallVTableMethod (ILGenerator il, MethodInfo method, int stackHeight, protected virtual void EmitCallVTableMethod (ILGenerator il, MethodInfo method, int stackHeight,
bool throwOnNoVTable) bool throwOnNoVTable)
{ {
// prepare a jump; do not call vtable method if no vtable // prepare a jump; do not call vtable method if no vtable
Label noVirt = il.DefineLabel (); Label noVirt = il.DefineLabel ();
Label dontPushOrThrow = il.DefineLabel (); Label dontPushOrThrow = il.DefineLabel ();
EmitLoadVTable (il); EmitLoadVTable (il);
il.Emit (OpCodes.Brfalse_S, noVirt); // if (vtableInfo == null) goto noVirt il.Emit (OpCodes.Brfalse_S, noVirt); // if (vtableInfo == null) goto noVirt
il.Emit (OpCodes.Callvirt, method); // call method il.Emit (OpCodes.Callvirt, method); // call method
il.Emit (OpCodes.Br_S, dontPushOrThrow); // goto dontPushOrThrow il.Emit (OpCodes.Br_S, dontPushOrThrow); // goto dontPushOrThrow
il.MarkLabel (noVirt); il.MarkLabel (noVirt);
// noVirt: // noVirt:
// since there is no vtable, we did not make the method call. // since there is no vtable, we did not make the method call.
// pop arguments // pop arguments
for (int i = 0; i < stackHeight; i++) for (int i = 0; i < stackHeight; i++)
il.Emit (OpCodes.Pop); il.Emit (OpCodes.Pop);
// if the method was supposed to return a value, we must // if the method was supposed to return a value, we must
// still push something onto the stack // still push something onto the stack
// FIXME: This is a kludge. What about value types? // FIXME: This is a kludge. What about value types?
if (!method.ReturnType.Equals (typeof (void))) if (!method.ReturnType.Equals (typeof (void)))
il.Emit (OpCodes.Ldnull); il.Emit (OpCodes.Ldnull);
if (throwOnNoVTable) { if (throwOnNoVTable) {
il.Emit (OpCodes.Ldstr, "Native class has no VTable."); il.Emit (OpCodes.Ldstr, "Native class has no VTable.");
il.Emit (OpCodes.Newobj, typeof (InvalidOperationException).GetConstructor(new Type[] {typeof (string)})); il.Emit (OpCodes.Newobj, typeof (InvalidOperationException).GetConstructor(new Type[] {typeof (string)}));
il.Emit (OpCodes.Throw); il.Emit (OpCodes.Throw);
} }
il.MarkLabel (dontPushOrThrow); il.MarkLabel (dontPushOrThrow);
} }
protected virtual void EmitLoadInstancePtr (ILGenerator il, Type firstParamType, out LocalBuilder cppip, protected virtual void EmitLoadInstancePtr (ILGenerator il, Type firstParamType, out LocalBuilder cppip,
out LocalBuilder native) out LocalBuilder native)
{ {
cppip = null; cppip = null;
native = null; native = null;
il.Emit (OpCodes.Ldarg_1); il.Emit (OpCodes.Ldarg_1);
if (firstParamType.Equals (typeof (CppInstancePtr))) { if (firstParamType.Equals (typeof (CppInstancePtr))) {
cppip = il.DeclareLocal (typeof (CppInstancePtr)); cppip = il.DeclareLocal (typeof (CppInstancePtr));
native = il.DeclareLocal (typeof (IntPtr)); native = il.DeclareLocal (typeof (IntPtr));
il.Emit (OpCodes.Stloc_S, cppip); il.Emit (OpCodes.Stloc_S, cppip);
il.Emit (OpCodes.Ldloca_S, cppip); il.Emit (OpCodes.Ldloca_S, cppip);
il.Emit (OpCodes.Call, typeof (CppInstancePtr).GetProperty ("Native").GetGetMethod ()); il.Emit (OpCodes.Call, typeof (CppInstancePtr).GetProperty ("Native").GetGetMethod ());
il.Emit (OpCodes.Stloc_S, native); il.Emit (OpCodes.Stloc_S, native);
} else if (firstParamType.Equals (typeof (IntPtr))) { } else if (firstParamType.Equals (typeof (IntPtr))) {
native = il.DeclareLocal (typeof (IntPtr)); native = il.DeclareLocal (typeof (IntPtr));
il.Emit (OpCodes.Stloc_S, native); il.Emit (OpCodes.Stloc_S, native);
} else if (firstParamType.IsByRef) { } else if (firstParamType.IsByRef) {
native = il.DeclareLocal (firstParamType); native = il.DeclareLocal (firstParamType);
il.Emit (OpCodes.Stloc_S, native); il.Emit (OpCodes.Stloc_S, native);
} else } else
throw new ArgumentException ("First argument to non-static C++ method must be byref, IntPtr or CppInstancePtr."); throw new ArgumentException ("First argument to non-static C++ method must be byref, IntPtr or CppInstancePtr.");
} }
protected virtual void EmitCheckManagedAlloc (ILGenerator il, LocalBuilder cppip) protected virtual void EmitCheckManagedAlloc (ILGenerator il, LocalBuilder cppip)
{ {
// make sure we were allocated by managed code // make sure we were allocated by managed code
// if not, return // if not, return
Label managedAlloc = il.DefineLabel (); Label managedAlloc = il.DefineLabel ();
il.Emit (OpCodes.Ldloca_S, cppip); il.Emit (OpCodes.Ldloca_S, cppip);
il.Emit (OpCodes.Call, typeof (CppInstancePtr).GetProperty ("IsManagedAlloc").GetGetMethod ()); il.Emit (OpCodes.Call, typeof (CppInstancePtr).GetProperty ("IsManagedAlloc").GetGetMethod ());
il.Emit (OpCodes.Brtrue_S, managedAlloc); il.Emit (OpCodes.Brtrue_S, managedAlloc);
il.Emit (OpCodes.Ret); il.Emit (OpCodes.Ret);
il.MarkLabel (managedAlloc); il.MarkLabel (managedAlloc);
} }
/** /**
* throw ObjectDisposedException if we have a null pointer for native * throw ObjectDisposedException if we have a null pointer for native
* however, allow destructor to be called even if we're disposed (just return immediately) * however, allow destructor to be called even if we're disposed (just return immediately)
*/ */
protected virtual void EmitCheckDisposed (ILGenerator il, LocalBuilder native, MethodType methodType) protected virtual void EmitCheckDisposed (ILGenerator il, LocalBuilder native, MethodType methodType)
{ {
Label validRef = il.DefineLabel (); Label validRef = il.DefineLabel ();
il.Emit (OpCodes.Ldloc_S, native); il.Emit (OpCodes.Ldloc_S, native);
il.Emit (OpCodes.Brtrue_S, validRef); il.Emit (OpCodes.Brtrue_S, validRef);
if (methodType == MethodType.NativeDtor) { if (methodType == MethodType.NativeDtor) {
il.Emit (OpCodes.Ret); il.Emit (OpCodes.Ret);
il.MarkLabel (validRef); il.MarkLabel (validRef);
} else { } else {
il.Emit (OpCodes.Ldstr, String.Empty); il.Emit (OpCodes.Ldstr, String.Empty);
il.Emit (OpCodes.Newobj, typeof (ObjectDisposedException).GetConstructor (new Type[] { typeof(string) })); il.Emit (OpCodes.Newobj, typeof (ObjectDisposedException).GetConstructor (new Type[] { typeof(string) }));
il.Emit (OpCodes.Throw); il.Emit (OpCodes.Throw);
il.MarkLabel (validRef); il.MarkLabel (validRef);
} }
} }
}
}
} }

20
src/Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs

@ -20,8 +20,8 @@ namespace Mono.VisualC.Interop.ABI {
public class ItaniumAbi : CppAbi { public class ItaniumAbi : CppAbi {
public ItaniumAbi () public ItaniumAbi ()
{ {
} }
protected override CppTypeInfo MakeTypeInfo (IEnumerable<MethodInfo> virtualMethods) protected override CppTypeInfo MakeTypeInfo (IEnumerable<MethodInfo> virtualMethods)
{ {
@ -34,9 +34,9 @@ namespace Mono.VisualC.Interop.ABI {
} }
protected override string GetMangledMethodName (MethodInfo methodInfo) protected override string GetMangledMethodName (MethodInfo methodInfo)
{ {
string methodName = methodInfo.Name; string methodName = methodInfo.Name;
MethodType methodType = GetMethodType (methodInfo); MethodType methodType = GetMethodType (methodInfo);
ParameterInfo [] parameters = methodInfo.GetParameters (); ParameterInfo [] parameters = methodInfo.GetParameters ();
StringBuilder nm = new StringBuilder ("_ZN", 30); StringBuilder nm = new StringBuilder ("_ZN", 30);
@ -57,7 +57,7 @@ namespace Mono.VisualC.Interop.ABI {
} }
nm.Append ('E'); nm.Append ('E');
int argStart = (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');
@ -80,8 +80,8 @@ namespace Mono.VisualC.Interop.ABI {
For.AnyInputIn (CppModifiers.Pointer, CppModifiers.Array).Emit ("P"), For.AnyInputIn (CppModifiers.Pointer, CppModifiers.Array).Emit ("P"),
For.AnyInputIn (CppModifiers.Reference).Emit ("R"), For.AnyInputIn (CppModifiers.Reference).Emit ("R"),
// Itanium mangled names do not include const or volatile unless // Itanium mangled names do not include const or volatile unless
// they modify the type pointed to by pointer or reference. // they modify the type pointed to by pointer or reference.
Choose.TopOne ( Choose.TopOne (
For.AllInputsIn (CppModifiers.Volatile, CppModifiers.Const).InAnyOrder ().After (ptrOrRef).Emit ("VK"), For.AllInputsIn (CppModifiers.Volatile, CppModifiers.Const).InAnyOrder ().After (ptrOrRef).Emit ("VK"),
For.AnyInputIn(CppModifiers.Volatile).After (ptrOrRef).Emit ("V"), For.AnyInputIn(CppModifiers.Volatile).After (ptrOrRef).Emit ("V"),
@ -103,13 +103,13 @@ namespace Mono.VisualC.Interop.ABI {
case CppTypes.Struct: case CppTypes.Struct:
case CppTypes.Union: case CppTypes.Union:
case CppTypes.Enum: case CppTypes.Enum:
code.Append(mangleType.ElementTypeName.Length); code.Append(mangleType.ElementTypeName.Length);
code.Append(mangleType.ElementTypeName); code.Append(mangleType.ElementTypeName);
break; break;
} }
return code.ToString (); return code.ToString ();
} }

21
src/Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs

@ -40,10 +40,10 @@ namespace Mono.VisualC.Interop.ABI {
return CallingConvention.ThisCall; return CallingConvention.ThisCall;
} }
protected override string GetMangledMethodName (MethodInfo methodInfo) protected override string GetMangledMethodName (MethodInfo methodInfo)
{ {
string methodName = methodInfo.Name; string methodName = methodInfo.Name;
MethodType methodType = GetMethodType (methodInfo); MethodType methodType = GetMethodType (methodInfo);
ParameterInfo [] parameters = methodInfo.GetParameters (); ParameterInfo [] parameters = methodInfo.GetParameters ();
StringBuilder nm = new StringBuilder ("?", 30); StringBuilder nm = new StringBuilder ("?", 30);
@ -172,30 +172,29 @@ namespace Mono.VisualC.Interop.ABI {
break; break;
case CppTypes.Class: case CppTypes.Class:
code.Append ('V'); code.Append ('V');
code.Append(mangleType.ElementTypeName); code.Append(mangleType.ElementTypeName);
code.Append ("@@"); code.Append ("@@");
break; break;
case CppTypes.Struct: case CppTypes.Struct:
code.Append ('U'); code.Append ('U');
code.Append(mangleType.ElementTypeName); code.Append(mangleType.ElementTypeName);
code.Append ("@@"); code.Append ("@@");
break; break;
case CppTypes.Union: case CppTypes.Union:
code.Append ('T'); code.Append ('T');
code.Append(mangleType.ElementTypeName); code.Append(mangleType.ElementTypeName);
code.Append ("@@"); code.Append ("@@");
break; break;
case CppTypes.Enum: case CppTypes.Enum:
code.Append ("W4"); code.Append ("W4");
code.Append(mangleType.ElementTypeName); code.Append(mangleType.ElementTypeName);
code.Append ("@@"); code.Append ("@@");
break; break;
} }
return code.ToString (); return code.ToString ();
} }
} }
} }

50
src/Mono.VisualC.Interop/ABI/Impl/VirtualOnlyAbi.cs

@ -14,32 +14,32 @@ using System.Runtime.InteropServices;
namespace Mono.VisualC.Interop.ABI { namespace Mono.VisualC.Interop.ABI {
public class VirtualOnlyAbi : CppAbi { public class VirtualOnlyAbi : CppAbi {
public VirtualOnlyAbi (MemberFilter vtableOverrideFilter) public VirtualOnlyAbi (MemberFilter vtableOverrideFilter)
{ {
this.vtable_override_filter = vtableOverrideFilter; this.vtable_override_filter = vtableOverrideFilter;
} }
public VirtualOnlyAbi () { } public VirtualOnlyAbi () { }
public override MethodType GetMethodType (MethodInfo imethod) public override MethodType GetMethodType (MethodInfo imethod)
{ {
MethodType defaultType = base.GetMethodType (imethod); MethodType defaultType = base.GetMethodType (imethod);
if (defaultType == MethodType.NativeCtor || defaultType == MethodType.NativeDtor) if (defaultType == MethodType.NativeCtor || defaultType == MethodType.NativeDtor)
return MethodType.NoOp; return MethodType.NoOp;
return defaultType; return defaultType;
} }
protected override string GetMangledMethodName (MethodInfo methodInfo) protected override string GetMangledMethodName (MethodInfo methodInfo)
{ {
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? GetCallingConvention (MethodInfo methodInfo) public override CallingConvention? GetCallingConvention (MethodInfo methodInfo)
{ {
// Use platform default // Use platform default
return null; return null;
} }
} }
} }

14
src/Mono.VisualC.Interop/ABI/MethodType.cs

@ -1,10 +1,10 @@
using System; using System;
namespace Mono.VisualC.Interop { namespace Mono.VisualC.Interop {
public enum MethodType { public enum MethodType {
NoOp, NoOp,
Native, Native,
NativeCtor, NativeCtor,
NativeDtor, NativeDtor,
ManagedAlloc ManagedAlloc
} }
} }

230
src/Mono.VisualC.Interop/ABI/VTable.cs

@ -15,140 +15,138 @@ 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 (CppTypeInfo metadata); public delegate VTable MakeVTableDelegate (CppTypeInfo metadata);
// TODO: RTTI .. support virtual inheritance // TODO: RTTI .. support virtual inheritance
public abstract class VTable : IDisposable { public abstract class VTable : IDisposable {
public static MakeVTableDelegate DefaultImplementation = VTableManaged.Implementation;
public static MakeVTableDelegate DefaultImplementation = VTableManaged.Implementation;
protected CppTypeInfo typeInfo; protected CppTypeInfo typeInfo;
protected IntPtr basePtr, vtPtr; protected IntPtr basePtr, vtPtr;
public virtual int EntryCount { public virtual int EntryCount {
get { return typeInfo.VirtualMethods.Count; } get { return typeInfo.VirtualMethods.Count; }
} }
public virtual int EntrySize { public virtual int EntrySize {
get { return Marshal.SizeOf (typeof (IntPtr)); } get { return Marshal.SizeOf (typeof (IntPtr)); }
} }
public abstract T GetVirtualCallDelegate<T> (IntPtr native, int vtableIndex) where T : class; /*Delegate*/ public abstract T GetVirtualCallDelegate<T> (IntPtr native, int vtableIndex) where T : class; /*Delegate*/
// Subclasses should allocate vtPtr and then call WriteOverrides // Subclasses should allocate vtPtr and then call WriteOverrides
public VTable (CppTypeInfo typeInfo) public VTable (CppTypeInfo typeInfo)
{ {
this.typeInfo = typeInfo; this.typeInfo = typeInfo;
} }
protected virtual void WriteOverrides () protected virtual void WriteOverrides ()
{ {
IntPtr vtEntryPtr; IntPtr vtEntryPtr;
int currentOffset = typeInfo.VTableTopPadding; int currentOffset = typeInfo.VTableTopPadding;
for (int i = 0; i < EntryCount; i++) { for (int i = 0; i < EntryCount; i++) {
Delegate currentOverride = typeInfo.VTableOverrides [i]; Delegate currentOverride = typeInfo.VTableOverrides [i];
if (currentOverride != null) // managed override if (currentOverride != null) // managed override
vtEntryPtr = Marshal.GetFunctionPointerForDelegate (currentOverride); vtEntryPtr = Marshal.GetFunctionPointerForDelegate (currentOverride);
else else
vtEntryPtr = IntPtr.Zero; vtEntryPtr = IntPtr.Zero;
Marshal.WriteIntPtr (vtPtr, currentOffset, vtEntryPtr); Marshal.WriteIntPtr (vtPtr, currentOffset, vtEntryPtr);
currentOffset += EntrySize; currentOffset += EntrySize;
} }
} }
// FIXME: Make this method unsafe.. it would probably be much faster // FIXME: Make this method unsafe.. it would probably be much faster
public virtual void InitInstance (IntPtr instance) public virtual void InitInstance (IntPtr instance)
{ {
if (basePtr == IntPtr.Zero) { if (basePtr == IntPtr.Zero) {
basePtr = Marshal.ReadIntPtr (instance); basePtr = Marshal.ReadIntPtr (instance);
if ((basePtr != IntPtr.Zero) && (basePtr != vtPtr)) { if ((basePtr != IntPtr.Zero) && (basePtr != vtPtr)) {
// FIXME: This could probably be a more efficient memcpy // FIXME: This could probably be a more efficient memcpy
for(int i = 0; i < typeInfo.VTableTopPadding; i++) for(int i = 0; i < typeInfo.VTableTopPadding; i++)
Marshal.WriteByte(vtPtr, i, Marshal.ReadByte(basePtr, i)); Marshal.WriteByte(vtPtr, i, Marshal.ReadByte(basePtr, i));
int currentOffset = typeInfo.VTableTopPadding;
for (int i = 0; i < EntryCount; i++) {
if (Marshal.ReadIntPtr (vtPtr, currentOffset) == IntPtr.Zero) int currentOffset = typeInfo.VTableTopPadding;
Marshal.WriteIntPtr (vtPtr, currentOffset, Marshal.ReadIntPtr (basePtr, currentOffset)); for (int i = 0; i < EntryCount; i++) {
if (Marshal.ReadIntPtr (vtPtr, currentOffset) == IntPtr.Zero)
Marshal.WriteIntPtr (vtPtr, currentOffset, Marshal.ReadIntPtr (basePtr, currentOffset));
currentOffset += EntrySize; currentOffset += EntrySize;
} }
// FIXME: This could probably be a more efficient memcpy // FIXME: This could probably be a more efficient memcpy
for(int i = 0; i < typeInfo.VTableBottomPadding; i++) for(int i = 0; i < typeInfo.VTableBottomPadding; i++)
Marshal.WriteByte(vtPtr, currentOffset + i, Marshal.ReadByte(basePtr, currentOffset + i)); Marshal.WriteByte(vtPtr, currentOffset + i, Marshal.ReadByte(basePtr, currentOffset + i));
}
}
Marshal.WriteIntPtr (instance, vtPtr);
}
public virtual void ResetInstance (IntPtr instance)
{
Marshal.WriteIntPtr (instance, basePtr);
}
public IntPtr Pointer {
get { return vtPtr; }
}
protected virtual void Dispose (bool disposing)
{
if (vtPtr != IntPtr.Zero) {
Marshal.FreeHGlobal (vtPtr);
vtPtr = IntPtr.Zero;
}
}
// TODO: This WON'T usually be called because VTables are associated with classes
// (not instances) and managed C++ class wrappers are staticly held?
public void Dispose ()
{
Dispose (true);
GC.SuppressFinalize (this);
}
~VTable ()
{
Dispose (false);
}
public static bool BindToSignatureAndAttribute (MemberInfo member, object obj)
{
bool result = BindToSignature (member, obj);
if (member.GetCustomAttributes (typeof (OverrideNativeAttribute), true).Length != 1)
return false;
return result;
}
public static bool BindToSignature (MemberInfo member, object obj)
{
MethodInfo imethod = (MethodInfo) obj;
MethodInfo candidate = (MethodInfo) member;
if (!candidate.Name.Equals (imethod.Name))
return false;
ParameterInfo[] invokeParams = imethod.GetParameters ();
ParameterInfo[] methodParams = candidate.GetParameters ();
if (invokeParams.Length == methodParams.Length) {
for (int i = 0; i < invokeParams.Length; i++) {
if (!invokeParams [i].ParameterType.IsAssignableFrom (methodParams [i].ParameterType))
return false;
} }
} } else if (invokeParams.Length == methodParams.Length + 1) {
for (int i = 1; i < invokeParams.Length; i++) {
Marshal.WriteIntPtr (instance, vtPtr); if (!invokeParams [i].ParameterType.IsAssignableFrom (methodParams [i - 1].ParameterType))
} return false;
}
public virtual void ResetInstance (IntPtr instance) } else
{ return false;
Marshal.WriteIntPtr (instance, basePtr);
} return true;
}
public IntPtr Pointer { }
get { return vtPtr; }
}
protected virtual void Dispose (bool disposing)
{
if (vtPtr != IntPtr.Zero) {
Marshal.FreeHGlobal (vtPtr);
vtPtr = IntPtr.Zero;
}
}
// TODO: This WON'T usually be called because VTables are associated with classes
// (not instances) and managed C++ class wrappers are staticly held?
public void Dispose ()
{
Dispose (true);
GC.SuppressFinalize (this);
}
~VTable ()
{
Dispose (false);
}
public static bool BindToSignatureAndAttribute (MemberInfo member, object obj)
{
bool result = BindToSignature (member, obj);
if (member.GetCustomAttributes (typeof (OverrideNativeAttribute), true).Length != 1)
return false;
return result;
}
public static bool BindToSignature (MemberInfo member, object obj)
{
MethodInfo imethod = (MethodInfo) obj;
MethodInfo candidate = (MethodInfo) member;
if (!candidate.Name.Equals (imethod.Name))
return false;
ParameterInfo[] invokeParams = imethod.GetParameters ();
ParameterInfo[] methodParams = candidate.GetParameters ();
if (invokeParams.Length == methodParams.Length) {
for (int i = 0; i < invokeParams.Length; i++) {
if (!invokeParams [i].ParameterType.IsAssignableFrom (methodParams [i].ParameterType))
return false;
}
} else if (invokeParams.Length == methodParams.Length + 1) {
for (int i = 1; i < invokeParams.Length; i++) {
if (!invokeParams [i].ParameterType.IsAssignableFrom (methodParams [i - 1].ParameterType))
return false;
}
} else
return false;
return true;
}
}
} }

27
src/Mono.VisualC.Interop/ABI/VTableManaged.cs

@ -19,15 +19,15 @@ using Mono.VisualC.Interop.Util;
namespace Mono.VisualC.Interop.ABI { namespace Mono.VisualC.Interop.ABI {
public class VTableManaged : VTable { public class VTableManaged : VTable {
public static MakeVTableDelegate Implementation = metadata => { return new VTableManaged (metadata); }; public static MakeVTableDelegate Implementation = metadata => { return new VTableManaged (metadata); };
private VTableManaged (CppTypeInfo metadata) : base (metadata) private VTableManaged (CppTypeInfo metadata) : base (metadata)
{ {
this.vtPtr = Marshal.AllocHGlobal ((EntryCount * EntrySize) + typeInfo.VTableTopPadding + typeInfo.VTableBottomPadding); this.vtPtr = Marshal.AllocHGlobal ((EntryCount * EntrySize) + typeInfo.VTableTopPadding + typeInfo.VTableBottomPadding);
WriteOverrides (); WriteOverrides ();
} }
public override T GetVirtualCallDelegate<T> (IntPtr native, int index) public override T GetVirtualCallDelegate<T> (IntPtr native, int index)
{ {
IntPtr vtable = Marshal.ReadIntPtr (native); IntPtr vtable = Marshal.ReadIntPtr (native);
if (vtable == vtPtr) // do not return managed overrides if (vtable == vtPtr) // do not return managed overrides
vtable = basePtr; vtable = basePtr;
@ -42,14 +42,13 @@ namespace Mono.VisualC.Interop.ABI {
} }
/* /*
protected static Type GetNativeLayoutType(MethodInfo thisMethod) { protected static Type GetNativeLayoutType(MethodInfo thisMethod) {
ParameterInfo[] parameters = thisMethod.GetParameters(); ParameterInfo[] parameters = thisMethod.GetParameters();
if (parameters.Length < 1) return null; if (parameters.Length < 1) return null;
Type nativeLayoutType = parameters[0].ParameterType.GetElementType();
return nativeLayoutType;
}
*/
Type nativeLayoutType = parameters[0].ParameterType.GetElementType();
return nativeLayoutType;
}
*/
} }

74
src/Mono.VisualC.Interop/Attributes.cs

@ -22,11 +22,11 @@ namespace Mono.VisualC.Interop {
public class DestructorAttribute : Attribute {} public class DestructorAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Method)] [AttributeUsage (AttributeTargets.Method)]
public class VirtualAttribute : Attribute {} public class VirtualAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Method)] [AttributeUsage (AttributeTargets.Method)]
public class StaticAttribute : Attribute {} public class StaticAttribute : Attribute {}
// used for the const "this" - for example: int value () const; // used for the const "this" - for example: int value () const;
// use MangleAsAttribute for const parameters // use MangleAsAttribute for const parameters
@ -35,28 +35,28 @@ namespace Mono.VisualC.Interop {
// FIXME: Will we ever be calling private methods? // 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 {}
[AttributeUsage (AttributeTargets.Parameter | AttributeTargets.ReturnValue)] [AttributeUsage (AttributeTargets.Parameter | AttributeTargets.ReturnValue)]
public class MangleAsAttribute : Attribute { public class MangleAsAttribute : Attribute {
public CppType MangleType { get; private set; } public CppType MangleType { get; private set; }
public MangleAsAttribute (CppType mangleType) public MangleAsAttribute (CppType mangleType)
{ {
this.MangleType = mangleType; this.MangleType = mangleType;
} }
public MangleAsAttribute (string mangleTypeStr) public MangleAsAttribute (string mangleTypeStr)
{ {
this.MangleType = new CppType (mangleTypeStr); this.MangleType = new CppType (mangleTypeStr);
} }
public MangleAsAttribute (params object [] cppTypeSpec) public MangleAsAttribute (params object [] cppTypeSpec)
{ {
this.MangleType = new CppType (cppTypeSpec); this.MangleType = new CppType (cppTypeSpec);
} }
} }
// for testing: // for testing:
[AttributeUsage (AttributeTargets.Method)] [AttributeUsage (AttributeTargets.Method)]
@ -73,8 +73,8 @@ namespace Mono.VisualC.Interop {
#endregion #endregion
#region Wrapper method attributes #region Wrapper method attributes
[AttributeUsage (AttributeTargets.Method)] [AttributeUsage (AttributeTargets.Method)]
public class OverrideNativeAttribute : Attribute {} public class OverrideNativeAttribute : Attribute {}
#endregion #endregion
} }
@ -83,14 +83,14 @@ using Mono.VisualC.Interop;
public partial class CppAbi { public partial class CppAbi {
public virtual bool IsVirtual (MethodInfo method) public virtual bool IsVirtual (MethodInfo method)
{ {
return method.IsDefined (typeof (VirtualAttribute), false); return method.IsDefined (typeof (VirtualAttribute), false);
} }
public virtual bool IsStatic (MethodInfo method) public virtual bool IsStatic (MethodInfo method)
{ {
return method.IsDefined (typeof (StaticAttribute), false); return method.IsDefined (typeof (StaticAttribute), false);
} }
public virtual bool IsConst (MethodInfo method) public virtual bool IsConst (MethodInfo method)
{ {
return method.IsDefined (typeof (ConstAttribute), false); return method.IsDefined (typeof (ConstAttribute), false);
@ -104,10 +104,10 @@ using Mono.VisualC.Interop;
return method.IsDefined (typeof (ProtectedAttribute), false); return method.IsDefined (typeof (ProtectedAttribute), false);
} }
public virtual CppType GetMangleType (ICustomAttributeProvider icap, Type managedType) public virtual CppType GetMangleType (ICustomAttributeProvider icap, Type managedType)
{ {
CppType mangleType = new CppType (); CppType mangleType = new CppType ();
MangleAsAttribute maa = (MangleAsAttribute)icap.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;
@ -119,9 +119,9 @@ using Mono.VisualC.Interop;
// 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;
return mangleType; return mangleType;
} }
} }
} }

64
src/Mono.VisualC.Interop/CppField.cs

@ -11,39 +11,39 @@ using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Mono.VisualC.Interop { namespace Mono.VisualC.Interop {
public class CppField<T> { public class CppField<T> {
private int fieldOffset; private int fieldOffset;
public CppField (int fieldOffset) public CppField (int fieldOffset)
{ {
this.fieldOffset = fieldOffset; this.fieldOffset = fieldOffset;
} }
public T this [CppInstancePtr ip] { public T this [CppInstancePtr ip] {
get { get {
Type retType = typeof (T); Type retType = typeof (T);
object retVal; object retVal;
if (retType.Equals (typeof (Byte))) if (retType.Equals (typeof (Byte)))
retVal = Marshal.ReadByte (ip.Native, fieldOffset); retVal = Marshal.ReadByte (ip.Native, fieldOffset);
else if (retType.Equals (typeof (Int16))) else if (retType.Equals (typeof (Int16)))
retVal = Marshal.ReadInt16 (ip.Native, fieldOffset); retVal = Marshal.ReadInt16 (ip.Native, fieldOffset);
else if (retType.Equals (typeof (Int32))) else if (retType.Equals (typeof (Int32)))
retVal = Marshal.ReadInt32 (ip.Native, fieldOffset); retVal = Marshal.ReadInt32 (ip.Native, fieldOffset);
else throw new NotImplementedException ("Cannot read C++ fields of type " + retType.Name); else throw new NotImplementedException ("Cannot read C++ fields of type " + retType.Name);
return (T)retVal; return (T)retVal;
} }
set { set {
Type setType = typeof (T); Type setType = typeof (T);
object setVal = value; object setVal = value;
if (setType.Equals (typeof (Byte))) if (setType.Equals (typeof (Byte)))
Marshal.WriteByte (ip.Native, fieldOffset, (byte)setVal); Marshal.WriteByte (ip.Native, fieldOffset, (byte)setVal);
else if (setType.Equals (typeof (Int16))) else if (setType.Equals (typeof (Int16)))
Marshal.WriteInt16 (ip.Native, fieldOffset, (Int16)setVal); Marshal.WriteInt16 (ip.Native, fieldOffset, (Int16)setVal);
else if (setType.Equals (typeof (Int32))) else if (setType.Equals (typeof (Int32)))
Marshal.WriteInt32 (ip.Native, fieldOffset, (Int32)setVal); Marshal.WriteInt32 (ip.Native, fieldOffset, (Int32)setVal);
else throw new NotImplementedException ("Cannot write C++ fields of type " + setType.Name); else throw new NotImplementedException ("Cannot write C++ fields of type " + setType.Name);
} }
} }
} }
} }

237
src/Mono.VisualC.Interop/CppInstancePtr.cs

@ -16,134 +16,133 @@ using System.Diagnostics;
using Mono.VisualC.Interop.ABI; using Mono.VisualC.Interop.ABI;
namespace Mono.VisualC.Interop { namespace Mono.VisualC.Interop {
public struct CppInstancePtr : ICppObject { public struct CppInstancePtr : ICppObject {
private IntPtr ptr; private IntPtr ptr;
private bool manage_memory; private bool manage_memory;
private static Dictionary<Type,object> implCache = null; private static Dictionary<Type,object> implCache = null;
// TODO: the managed instance argument may only be NULL if all methods in TWrapper // TODO: the managed instance argument may only be NULL if all methods in TWrapper
// that correspond to the virtual methods in Iface are static. // that correspond to the virtual methods in Iface are static.
public static CppInstancePtr ForManagedObject<Iface,TWrapper> (TWrapper managed) public static CppInstancePtr ForManagedObject<Iface,TWrapper> (TWrapper managed)
where Iface : ICppClassOverridable<TWrapper> where Iface : ICppClassOverridable<TWrapper>
{ {
object cachedImpl; object cachedImpl;
Iface impl; Iface impl;
if (implCache == null) if (implCache == null)
implCache = new Dictionary<Type,object> (); implCache = new Dictionary<Type,object> ();
if (!implCache.TryGetValue (typeof (Iface), out cachedImpl)) if (!implCache.TryGetValue (typeof (Iface), out cachedImpl))
{ {
VirtualOnlyAbi virtualABI = new VirtualOnlyAbi (VTable.BindToSignature); VirtualOnlyAbi virtualABI = new VirtualOnlyAbi (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);
} }
else else
impl = (Iface)cachedImpl; impl = (Iface)cachedImpl;
CppInstancePtr instance = impl.Alloc (managed); CppInstancePtr instance = impl.Alloc (managed);
impl.TypeInfo.VTable.InitInstance ((IntPtr)instance); impl.TypeInfo.VTable.InitInstance ((IntPtr)instance);
return instance; return instance;
} }
// Alloc a new C++ instance // Alloc a new C++ instance
internal CppInstancePtr (int nativeSize, object managedWrapper) internal CppInstancePtr (int nativeSize, object managedWrapper)
{ {
// Under the hood, we're secretly subclassing this C++ class to store a // Under the hood, we're secretly subclassing this C++ class to store a
// handle to the managed wrapper. // handle to the managed wrapper.
int allocSize = nativeSize + Marshal.SizeOf (typeof (IntPtr)); int allocSize = nativeSize + Marshal.SizeOf (typeof (IntPtr));
ptr = Marshal.AllocHGlobal (allocSize); ptr = Marshal.AllocHGlobal (allocSize);
// zero memory for sanity // zero memory for sanity
byte[] zeroArray = new byte [allocSize]; byte[] zeroArray = new byte [allocSize];
Marshal.Copy (zeroArray, 0, ptr, allocSize); Marshal.Copy (zeroArray, 0, ptr, allocSize);
IntPtr handlePtr = GetGCHandle (managedWrapper); IntPtr handlePtr = GetGCHandle (managedWrapper);
Marshal.WriteIntPtr (ptr, nativeSize, handlePtr); Marshal.WriteIntPtr (ptr, nativeSize, handlePtr);
manage_memory = true; manage_memory = true;
} }
// Alloc a new C++ instance when there is no managed wrapper. // Alloc a new C++ instance when there is no managed wrapper.
internal CppInstancePtr (int nativeSize) internal CppInstancePtr (int nativeSize)
{ {
ptr = Marshal.AllocHGlobal (nativeSize); ptr = Marshal.AllocHGlobal (nativeSize);
manage_memory = true; manage_memory = true;
} }
// Get a CppInstancePtr for an existing C++ instance from an IntPtr // Get a CppInstancePtr for an existing C++ instance from an IntPtr
public CppInstancePtr (IntPtr native) public CppInstancePtr (IntPtr native)
{ {
if (native == IntPtr.Zero) if (native == IntPtr.Zero)
throw new ArgumentOutOfRangeException ("native cannot be null pointer"); throw new ArgumentOutOfRangeException ("native cannot be null pointer");
ptr = native; ptr = native;
manage_memory = false; manage_memory = false;
} }
// Provide casts to/from IntPtr: // Provide casts to/from IntPtr:
public static implicit operator CppInstancePtr (IntPtr native) public static implicit operator CppInstancePtr (IntPtr native)
{ {
return new CppInstancePtr (native); return new CppInstancePtr (native);
} }
// cast from CppInstancePtr -> IntPtr is explicit because we lose information // cast from CppInstancePtr -> IntPtr is explicit because we lose information
public static explicit operator IntPtr (CppInstancePtr ip) public static explicit operator IntPtr (CppInstancePtr ip)
{ {
return ip.Native; return ip.Native;
} }
public IntPtr Native { public IntPtr Native {
get { get {
if (ptr == IntPtr.Zero) if (ptr == IntPtr.Zero)
throw new ObjectDisposedException ("CppInstancePtr"); throw new ObjectDisposedException ("CppInstancePtr");
return ptr; return ptr;
} }
} }
CppInstancePtr ICppObject.Native { CppInstancePtr ICppObject.Native {
get { return this; } get { return this; }
} }
public int NativeSize { public int NativeSize {
get { get {
throw new NotImplementedException (); throw new NotImplementedException ();
} }
} }
public bool IsManagedAlloc { public bool IsManagedAlloc {
get { return manage_memory; } get { return manage_memory; }
} }
internal static IntPtr GetGCHandle (object managedWrapper) internal static IntPtr GetGCHandle (object managedWrapper)
{ {
// TODO: Dispose() should probably be called at some point on this GCHandle. // TODO: Dispose() should probably be called at some point on this GCHandle.
GCHandle handle = GCHandle.Alloc (managedWrapper, GCHandleType.Normal); GCHandle handle = GCHandle.Alloc (managedWrapper, GCHandleType.Normal);
return GCHandle.ToIntPtr (handle); return GCHandle.ToIntPtr (handle);
} }
// WARNING! This method is not safe. DO NOT call // WARNING! This method is not safe. DO NOT call
// if we do not KNOW that this instance is managed. // if we do not KNOW that this instance is managed.
internal static T GetManaged<T> (IntPtr native, int nativeSize) where T : class internal static T GetManaged<T> (IntPtr native, int nativeSize) where T : class
{ {
IntPtr handlePtr = Marshal.ReadIntPtr (native, nativeSize);
IntPtr handlePtr = Marshal.ReadIntPtr (native, nativeSize); GCHandle handle = GCHandle.FromIntPtr (handlePtr);
GCHandle handle = GCHandle.FromIntPtr (handlePtr);
return handle.Target as T;
return handle.Target as T; }
}
// TODO: Free GCHandle?
// TODO: Free GCHandle? public void Dispose ()
public void Dispose () {
{ if (manage_memory && ptr != IntPtr.Zero)
if (manage_memory && ptr != IntPtr.Zero) Marshal.FreeHGlobal (ptr);
Marshal.FreeHGlobal (ptr);
ptr = IntPtr.Zero;
ptr = IntPtr.Zero; manage_memory = false;
manage_memory = false; }
} }
}
} }

63
src/Mono.VisualC.Interop/CppLibrary.cs

@ -21,23 +21,22 @@ using Mono.VisualC.Interop.ABI;
namespace Mono.VisualC.Interop { namespace Mono.VisualC.Interop {
public sealed class CppLibrary { public sealed class CppLibrary {
internal static AssemblyBuilder interopAssembly; internal static AssemblyBuilder interopAssembly;
internal static ModuleBuilder interopModule; internal static ModuleBuilder interopModule;
public CppAbi Abi { get; private set; } public CppAbi Abi { get; private set; }
public string Name { get; private set; } public string Name { get; private set; }
static CppLibrary () static CppLibrary ()
{ {
AssemblyName assemblyName = new AssemblyName ("__CppLibraryImplAssembly"); AssemblyName assemblyName = new AssemblyName ("__CppLibraryImplAssembly");
string moduleName = "CppLibraryImplAssembly.dll"; string moduleName = "CppLibraryImplAssembly.dll";
interopAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly (assemblyName, AssemblyBuilderAccess.RunAndSave); interopAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly (assemblyName, AssemblyBuilderAccess.RunAndSave);
interopModule = interopAssembly.DefineDynamicModule (moduleName, moduleName, true); interopModule = interopAssembly.DefineDynamicModule (moduleName, moduleName, true);
} }
public CppLibrary (string name) public CppLibrary (string name)
{ {
if (name == null) if (name == null)
throw new ArgumentNullException ("Name cannot be NULL."); throw new ArgumentNullException ("Name cannot be NULL.");
@ -48,14 +47,13 @@ namespace Mono.VisualC.Interop {
} }
public CppLibrary (string name, CppAbi abi) public CppLibrary (string name, CppAbi abi)
{ {
if (name == null) if (name == null)
throw new ArgumentNullException ("Name cannot be NULL."); throw new ArgumentNullException ("Name cannot be NULL.");
if (abi == null) if (abi == null)
throw new ArgumentNullException ("Abi cannot be NULL."); throw new ArgumentNullException ("Abi cannot be NULL.");
this.Name = name; this.Name = name;
this.Abi = abi; this.Abi = abi;
} }
@ -65,38 +63,35 @@ namespace Mono.VisualC.Interop {
interopAssembly.Save ("CppLibraryImplAssembly.dll"); 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)
where Iface : ICppClass where Iface : ICppClass
{ {
return Abi.ImplementClass<Iface> (null, Name, className);
return Abi.ImplementClass<Iface> (null, Name, className); }
}
// For instantiating or working with a class that may have fields // For instantiating or working with a class that may have fields
// but where overriding virtual methods in managed code is not necessary // but where overriding virtual methods in managed code is not necessary
public Iface GetClass<Iface,NativeLayout> (string className) public Iface GetClass<Iface,NativeLayout> (string className)
where Iface : ICppClassInstantiatable where Iface : ICppClassInstantiatable
where NativeLayout : struct where NativeLayout : struct
{ {
return Abi.ImplementClass<Iface, NativeLayout> (null, Name, className); return Abi.ImplementClass<Iface, NativeLayout> (null, Name, className);
} }
/* The most powerful override. Allows the following from managed code: /* The most powerful override. Allows the following from managed code:
* + Instantiation * + Instantiation
* + Field access * + Field access
* + Virtual method overriding * + Virtual method overriding
*/ */
public Iface GetClass<Iface,NativeLayout,Managed> (string className) public Iface GetClass<Iface,NativeLayout,Managed> (string className)
where Iface : ICppClassOverridable<Managed> where Iface : ICppClassOverridable<Managed>
where NativeLayout : struct where NativeLayout : struct
where Managed : ICppObject where Managed : ICppObject
{ {
return Abi.ImplementClass<Iface, NativeLayout> (typeof (Managed), Name, className); return Abi.ImplementClass<Iface, NativeLayout> (typeof (Managed), Name, className);
} }
} }
} }

86
src/Mono.VisualC.Interop/CppObjectMarshaler.cs

@ -2,48 +2,48 @@ using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Mono.VisualC.Interop { namespace Mono.VisualC.Interop {
public class CppObjectMarshaler : ICustomMarshaler { public class CppObjectMarshaler : ICustomMarshaler {
private static CppObjectMarshaler marshaler = null; private static CppObjectMarshaler marshaler = null;
private CppObjectMarshaler () { private CppObjectMarshaler () {
} }
public IntPtr MarshalManagedToNative (object managedObj) public IntPtr MarshalManagedToNative (object managedObj)
{ {
if (managedObj == null) if (managedObj == null)
return IntPtr.Zero; return IntPtr.Zero;
ICppObject cppObject = managedObj as ICppObject; ICppObject cppObject = managedObj as ICppObject;
if (cppObject == null) if (cppObject == null)
throw new ArgumentException ("Object to marshal must implement ICppObject"); throw new ArgumentException ("Object to marshal must implement ICppObject");
return (IntPtr)cppObject.Native; return (IntPtr)cppObject.Native;
} }
public object MarshalNativeToManaged (IntPtr pNativeData) public object MarshalNativeToManaged (IntPtr pNativeData)
{ {
throw new NotImplementedException (); throw new NotImplementedException ();
} }
public void CleanUpManagedData (object ManagedObj) public void CleanUpManagedData (object ManagedObj)
{ {
} }
public void CleanUpNativeData (IntPtr pNativeData) public void CleanUpNativeData (IntPtr pNativeData)
{ {
} }
public int GetNativeDataSize () public int GetNativeDataSize ()
{ {
return -1; return -1;
} }
public static ICustomMarshaler GetInstance(string cookie) public static ICustomMarshaler GetInstance(string cookie)
{ {
if(marshaler == null) if(marshaler == null)
marshaler = new CppObjectMarshaler (); marshaler = new CppObjectMarshaler ();
return marshaler; return marshaler;
} }
} }
} }

10
src/Mono.VisualC.Interop/CppTypeInfo.cs

@ -146,17 +146,17 @@ namespace Mono.VisualC.Interop {
} }
public virtual int NativeSize { public virtual int NativeSize {
get { get {
CompleteType (); CompleteType ();
return native_size + FieldOffsetPadding; return native_size + FieldOffsetPadding;
} }
} }
// the extra padding to allocate at the top of the class before the fields begin // the extra padding to allocate at the top of the class before the fields begin
// (by default, just the vtable pointer) // (by default, just the vtable pointer)
public virtual int FieldOffsetPadding { public virtual int FieldOffsetPadding {
get { return field_offset_padding + (VirtualMethods.Any ()? Marshal.SizeOf (typeof (IntPtr)) : 0); } get { return field_offset_padding + (VirtualMethods.Any ()? Marshal.SizeOf (typeof (IntPtr)) : 0); }
} }
// the padding in the data pointed to by the vtable pointer before the list of function pointers starts // the padding in the data pointed to by the vtable pointer before the list of function pointers starts
public virtual int VTableTopPadding { public virtual int VTableTopPadding {

30
src/Mono.VisualC.Interop/Interfaces.cs

@ -12,23 +12,23 @@ using Mono.VisualC.Interop.ABI;
namespace Mono.VisualC.Interop { namespace Mono.VisualC.Interop {
public interface ICppObject : IDisposable { public interface ICppObject : IDisposable {
CppInstancePtr Native { get; } CppInstancePtr Native { get; }
} }
public interface ICppClass { public interface ICppClass {
CppTypeInfo TypeInfo { get; } CppTypeInfo TypeInfo { get; }
} }
// This should go without saying, but the C++ class must have a constructor // This should go without saying, but the C++ class must have a constructor
// if it is to be instantiatable. // if it is to be instantiatable.
public interface ICppClassInstantiatable : ICppClass { public interface ICppClassInstantiatable : ICppClass {
CppInstancePtr Alloc (); CppInstancePtr Alloc ();
} }
// It is recommended that managed wrappers implement ICppObject, but // It is recommended that managed wrappers implement ICppObject, but
// I'm not making it required so that any arbitrary object can be exposed to // I'm not making it required so that any arbitrary object can be exposed to
// C++ via CppInstancePtr.ForManagedObject. // C++ via CppInstancePtr.ForManagedObject.
public interface ICppClassOverridable<T> : ICppClass /* where T : ICppObject */ { public interface ICppClassOverridable<T> : ICppClass /* where T : ICppObject */ {
CppInstancePtr Alloc (T managed); CppInstancePtr Alloc (T managed);
} }
} }

23
src/Mono.VisualC.Interop/Util/DelegateTypeCache.cs

@ -20,7 +20,6 @@ namespace Mono.VisualC.Interop.Util {
private static Dictionary<DelegateSignature, Type> type_cache; private static Dictionary<DelegateSignature, Type> type_cache;
public static Type GetDelegateType (MethodInfo signature, CallingConvention? callingConvention) public static Type GetDelegateType (MethodInfo signature, CallingConvention? callingConvention)
{ {
return GetDelegateType (ReflectionHelper.GetMethodParameterTypes (signature), signature.ReturnType, callingConvention); return GetDelegateType (ReflectionHelper.GetMethodParameterTypes (signature), signature.ReturnType, callingConvention);
@ -45,10 +44,10 @@ namespace Mono.VisualC.Interop.Util {
private static Type CreateDelegateType (DelegateSignature signature) private static Type CreateDelegateType (DelegateSignature signature)
{ {
string delTypeName = signature.UniqueName; string delTypeName = signature.UniqueName;
TypeAttributes typeAttr = TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass; TypeAttributes typeAttr = TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass;
TypeBuilder del = CppLibrary.interopModule.DefineType (delTypeName, typeAttr, typeof(MulticastDelegate)); TypeBuilder del = CppLibrary.interopModule.DefineType (delTypeName, typeAttr, typeof(MulticastDelegate));
if (signature.CallingConvention.HasValue) { if (signature.CallingConvention.HasValue) {
ConstructorInfo ufpa = typeof (UnmanagedFunctionPointerAttribute).GetConstructor (new Type [] { typeof (CallingConvention) }); ConstructorInfo ufpa = typeof (UnmanagedFunctionPointerAttribute).GetConstructor (new Type [] { typeof (CallingConvention) });
@ -56,17 +55,17 @@ namespace Mono.VisualC.Interop.Util {
del.SetCustomAttribute (unmanagedPointer); del.SetCustomAttribute (unmanagedPointer);
} }
MethodAttributes ctorAttr = MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public; MethodAttributes ctorAttr = MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public;
ConstructorBuilder ctor = del.DefineConstructor (ctorAttr, CallingConventions.Standard, new Type[] { typeof(object), typeof(System.IntPtr) }); ConstructorBuilder ctor = del.DefineConstructor (ctorAttr, CallingConventions.Standard, new Type[] { typeof(object), typeof(System.IntPtr) });
ctor.SetImplementationFlags (MethodImplAttributes.Runtime | MethodImplAttributes.Managed); ctor.SetImplementationFlags (MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
Type [] parameterTypes = signature.ParameterTypes.ToArray (); Type [] parameterTypes = signature.ParameterTypes.ToArray ();
MethodAttributes methodAttr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual; MethodAttributes methodAttr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual;
MethodBuilder invokeMethod = del.DefineMethod ("Invoke", methodAttr, signature.ReturnType, parameterTypes); MethodBuilder invokeMethod = del.DefineMethod ("Invoke", methodAttr, signature.ReturnType, parameterTypes);
invokeMethod.SetImplementationFlags (MethodImplAttributes.Runtime | MethodImplAttributes.Managed); invokeMethod.SetImplementationFlags (MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
return del.CreateType (); return del.CreateType ();
} }
} }

2
src/Mono.VisualC.Interop/Util/IEnumerableTransform.cs

@ -154,7 +154,7 @@ namespace Mono.VisualC.Interop.Util {
list.Clear (); list.Clear ();
list.AddRange (items); list.AddRange (items);
list.AddRange (temp); list.AddRange (temp);
} }
public static void AddFirst<T> (this List<T> list, T item) public static void AddFirst<T> (this List<T> list, T item)
{ {
list.Insert (0, item); list.Insert (0, item);

5
src/Mono.VisualC.Interop/Util/MethodSignature.cs

@ -54,12 +54,11 @@ namespace Mono.VisualC.Interop.Util {
DelegateSignature other = (DelegateSignature)obj; DelegateSignature other = (DelegateSignature)obj;
return CallingConvention == other.CallingConvention && return CallingConvention == other.CallingConvention &&
((ParameterTypes == null && other.ParameterTypes == null) || ((ParameterTypes == null && other.ParameterTypes == null) ||
ParameterTypes.SequenceEqual (other.ParameterTypes)) && ParameterTypes.SequenceEqual (other.ParameterTypes)) &&
ReturnType.Equals (other.ReturnType); ReturnType.Equals (other.ReturnType);
} }
public override int GetHashCode () public override int GetHashCode ()
{ {
unchecked { unchecked {

163
src/Mono.VisualC.Interop/Util/ReflectionHelper.cs

@ -15,86 +15,85 @@ using System.Reflection;
using System.Reflection.Emit; using System.Reflection.Emit;
namespace Mono.VisualC.Interop.Util { namespace Mono.VisualC.Interop.Util {
internal static class ReflectionHelper { internal static class ReflectionHelper {
public static MethodInfo GetMethodInfoForDelegate (Type delType) public static MethodInfo GetMethodInfoForDelegate (Type delType)
{ {
return delType.GetMethod ("Invoke"); return delType.GetMethod ("Invoke");
} }
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); return GetMethodParameterTypes (invoke);
} }
public static Type[] GetMethodParameterTypes (MethodInfo method) 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++)
parameterTypes [i] = parameters [i].ParameterType; parameterTypes [i] = parameters [i].ParameterType;
return parameterTypes; return parameterTypes;
} }
public static void ApplyMethodParameterAttributes (MethodInfo source, MethodBuilder target, bool forPInvoke) public static void ApplyMethodParameterAttributes (MethodInfo source, MethodBuilder target, bool forPInvoke)
{ {
ParameterInfo[] parameters = source.GetParameters (); ParameterInfo[] parameters = source.GetParameters ();
foreach (var param in parameters) foreach (var param in parameters)
ApplyAttributes (param, target.DefineParameter, forPInvoke); ApplyAttributes (param, target.DefineParameter, forPInvoke);
} }
public static void ApplyMethodParameterAttributes (MethodInfo source, DynamicMethod target, bool forPInvoke) public static void ApplyMethodParameterAttributes (MethodInfo source, DynamicMethod target, bool forPInvoke)
{ {
ParameterInfo[] parameters = source.GetParameters (); ParameterInfo[] parameters = source.GetParameters ();
foreach (var param in parameters) foreach (var param in parameters)
ApplyAttributes (param, target.DefineParameter, forPInvoke); ApplyAttributes (param, target.DefineParameter, forPInvoke);
} }
public static ParameterBuilder ApplyAttributes (ParameterInfo param, Func<int,ParameterAttributes,string,ParameterBuilder> makePB, bool forPInvoke) public static ParameterBuilder ApplyAttributes (ParameterInfo param, Func<int,ParameterAttributes,string,ParameterBuilder> makePB, bool forPInvoke)
{ {
ParameterAttributes attr = param.Attributes; ParameterAttributes attr = param.Attributes;
CustomAttributeBuilder marshalAsAttr = null; CustomAttributeBuilder marshalAsAttr = null;
MarshalAsAttribute existingMarshalAs = param.GetCustomAttributes (typeof (MarshalAsAttribute), MarshalAsAttribute existingMarshalAs = param.GetCustomAttributes (typeof (MarshalAsAttribute),
false).FirstOrDefault () as MarshalAsAttribute; false).FirstOrDefault () as MarshalAsAttribute;
/* if (forPInvoke && /* if (forPInvoke &&
typeof (ICppObject).IsAssignableFrom (param.ParameterType) && typeof (ICppObject).IsAssignableFrom (param.ParameterType) &&
!param.ParameterType.Equals (typeof (CppInstancePtr)) && !param.ParameterType.Equals (typeof (CppInstancePtr)) &&
existingMarshalAs == null) 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 };
FieldInfo[] fields = new FieldInfo [] { typeof (MarshalAsAttribute).GetField("MarshalTypeRef") }; FieldInfo[] fields = new FieldInfo [] { typeof (MarshalAsAttribute).GetField("MarshalTypeRef") };
object[] values = new object [] { typeof (CppObjectMarshaler) }; object[] values = new object [] { typeof (CppObjectMarshaler) };
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) { // FIXME: This still doesn't feel like it's working right.. especially for virtual functions
// FIXME: This still doesn't feel like it's working right.. especially for virtual functions 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 };
var fields = from field in typeof (MarshalAsAttribute).GetFields ()
var fields = from field in typeof (MarshalAsAttribute).GetFields () where field.GetValue (existingMarshalAs) != null
where field.GetValue (existingMarshalAs) != null select field;
select field;
var values = from field in fields select field.GetValue (existingMarshalAs);
var values = from field in fields select field.GetValue (existingMarshalAs);
marshalAsAttr = new CustomAttributeBuilder (ctor, args, fields.ToArray (), values.ToArray ());
marshalAsAttr = new CustomAttributeBuilder (ctor, args, fields.ToArray (), values.ToArray ()); attr = attr | ParameterAttributes.HasFieldMarshal;
attr = attr | ParameterAttributes.HasFieldMarshal; }
}
ParameterBuilder pb = makePB (param.Position, attr, param.Name);
ParameterBuilder pb = makePB (param.Position, attr, param.Name); if (marshalAsAttr != null) pb.SetCustomAttribute (marshalAsAttr);
if (marshalAsAttr != null) pb.SetCustomAttribute (marshalAsAttr); return pb;
return pb; }
} }
}
} }

Loading…
Cancel
Save