/// <summary> /// Returns true if this type has a common representation in both managed and unmanaged memory /// and does not require special handling by the interop marshaler. /// </summary> public static bool IsBlittableType(TypeDesc type) { if (!type.IsDefType) { return(false); } TypeDesc baseType = type.BaseType; bool hasNonTrivialParent = baseType != null && !baseType.IsWellKnownType(WellKnownType.Object) && !baseType.IsWellKnownType(WellKnownType.ValueType); if (hasNonTrivialParent && !IsBlittableType(baseType)) { return(false); } var mdType = (MetadataType)type; if (!mdType.IsSequentialLayout && !mdType.IsExplicitLayout) { return(false); } foreach (FieldDesc field in type.GetFields()) { if (field.IsStatic) { continue; } if (!field.FieldType.IsValueType) { // Types with fields of non-value types cannot be blittable // This check prevents possible infinite recursion where GetMarshallerKind would call back to IsBlittable e.g. for // the case of classes with pointer members to the class itself. return(false); } MarshallerKind marshallerKind = MarshalHelpers.GetMarshallerKind( field.FieldType, field.GetMarshalAsDescriptor(), isReturn: false, isAnsi: mdType.PInvokeStringFormat == PInvokeStringFormat.AnsiClass, MarshallerType.Field, elementMarshallerKind: out var _); if (marshallerKind != MarshallerKind.Enum && marshallerKind != MarshallerKind.BlittableValue && marshallerKind != MarshallerKind.BlittableStruct && marshallerKind != MarshallerKind.UnicodeChar) { return(false); } } return(true); }
public static Marshaller[] GetMarshallersForMethod(MethodDesc targetMethod) { Debug.Assert(targetMethod.IsPInvoke); return(GetMarshallers( targetMethod.Signature, targetMethod.GetPInvokeMethodMetadata().Flags, targetMethod.GetParameterMetadata(), MarshalHelpers.IsRuntimeMarshallingEnabled(((MetadataType)targetMethod.OwningType).Module))); }
/// <summary> /// Returns true if this is a type that doesn't require marshalling. /// </summary> public static bool IsBlittableType(TypeDesc type) { type = type.UnderlyingType; if (type.IsValueType) { if (type.IsPrimitive) { // All primitive types except char and bool are blittable TypeFlags category = type.Category; if (category == TypeFlags.Boolean || category == TypeFlags.Char) { return(false); } return(true); } foreach (FieldDesc field in type.GetFields()) { if (field.IsStatic) { continue; } TypeDesc fieldType = field.FieldType; // TODO: we should also reject fields that specify custom marshalling if (!MarshalHelpers.IsBlittableType(fieldType)) { // This field can still be blittable if it's a Char and marshals as Unicode var owningType = field.OwningType as MetadataType; if (owningType == null) { return(false); } if (fieldType.Category != TypeFlags.Char || owningType.PInvokeStringFormat == PInvokeStringFormat.AnsiClass) { return(false); } } } return(true); } if (type.IsPointer || type.IsFunctionPointer) { return(true); } return(false); }
/// <summary> /// Returns true if this type has a common representation in both managed and unmanaged memory /// and does not require special handling by the interop marshaler. /// </summary> public static bool IsBlittableType(TypeDesc type) { if (!type.IsDefType) { return(false); } DefType baseType = type.BaseType; bool hasNonTrivialParent = baseType != null && !baseType.IsWellKnownType(WellKnownType.Object) && !baseType.IsWellKnownType(WellKnownType.ValueType); // Type is blittable only if parent is also blittable and is not empty. if (hasNonTrivialParent && (!IsBlittableType(baseType) || baseType.IsZeroSizedReferenceType)) { return(false); } var mdType = (MetadataType)type; if (!mdType.IsSequentialLayout && !mdType.IsExplicitLayout) { return(false); } foreach (FieldDesc field in type.GetFields()) { if (field.IsStatic) { continue; } MarshallerKind marshallerKind = MarshalHelpers.GetMarshallerKind( field.FieldType, parameterIndex: null, customModifierData: null, field.GetMarshalAsDescriptor(), isReturn: false, isAnsi: mdType.PInvokeStringFormat == PInvokeStringFormat.AnsiClass, MarshallerType.Field, elementMarshallerKind: out var _); if (marshallerKind != MarshallerKind.Enum && marshallerKind != MarshallerKind.BlittableValue && marshallerKind != MarshallerKind.BlittableStruct && marshallerKind != MarshallerKind.UnicodeChar) { return(false); } } return(true); }
/// <summary> /// Returns true if this type has a common representation in both managed and unmanaged memory /// and does not require special handling by the interop marshaler. /// </summary> public static bool IsBlittableType(TypeDesc type) { if (!type.IsDefType) { return(false); } TypeDesc baseType = type.BaseType; bool hasNonTrivialParent = baseType != null && !baseType.IsWellKnownType(WellKnownType.Object) && !baseType.IsWellKnownType(WellKnownType.ValueType); if (hasNonTrivialParent && !IsBlittableType(baseType)) { return(false); } var mdType = (MetadataType)type; if (!mdType.IsSequentialLayout && !mdType.IsExplicitLayout) { return(false); } foreach (FieldDesc field in type.GetFields()) { if (field.IsStatic) { continue; } MarshallerKind marshallerKind = MarshalHelpers.GetMarshallerKind( field.FieldType, field.GetMarshalAsDescriptor(), isReturn: false, isAnsi: mdType.PInvokeStringFormat == PInvokeStringFormat.AnsiClass, MarshallerType.Field, elementMarshallerKind: out var _); if (marshallerKind != MarshallerKind.Enum && marshallerKind != MarshallerKind.BlittableValue && marshallerKind != MarshallerKind.BlittableStruct && marshallerKind != MarshallerKind.UnicodeChar) { return(false); } } return(true); }
internal static TypeDesc GetNativeStructFieldType(TypeDesc type, MarshalAsDescriptor marshalAs, InteropStateManager interopStateManager, bool isAnsi) { MarshallerKind elementMarshallerKind; MarshallerKind marshallerKind = MarshalHelpers.GetMarshallerKind(type, marshalAs, false, /* isReturn */ isAnsi, /* isAnsi */ MarshallerType.Field, out elementMarshallerKind); return(GetNativeTypeFromMarshallerKind(type, marshallerKind, elementMarshallerKind, interopStateManager, marshalAs)); }
internal static TypeDesc GetNativeMethodParameterType(TypeDesc type, MarshalAsDescriptor marshalAs, InteropStateManager interopStateManager, bool isReturn, bool isAnsi) { MarshallerKind elementMarshallerKind; MarshallerKind marshallerKind = MarshalHelpers.GetMarshallerKind(type, marshalAs, isReturn, isAnsi, MarshallerType.Argument, out elementMarshallerKind); return(GetNativeTypeFromMarshallerKind(type, marshallerKind, elementMarshallerKind, interopStateManager, marshalAs)); }
private void CalculateFields() { bool isSequential = ManagedStructType.IsSequentialLayout; MarshalAsDescriptor[] marshalAsDescriptors = ManagedStructType.GetFieldMarshalAsDescriptors(); bool isAnsi = ((MetadataType)ManagedStructType).PInvokeStringFormat == PInvokeStringFormat.AnsiClass; int numFields = 0; foreach (FieldDesc field in ManagedStructType.GetFields()) { if (field.IsStatic) { continue; } numFields++; } _fields = new NativeStructField[numFields]; int index = 0; foreach (FieldDesc field in ManagedStructType.GetFields()) { if (field.IsStatic) { continue; } var managedType = field.FieldType; TypeDesc nativeType; try { nativeType = MarshalHelpers.GetNativeStructFieldType(managedType, marshalAsDescriptors[index], _interopStateManager, isAnsi); } catch (NotSupportedException) { // if marshalling is not supported for this type the generated stubs will emit appropriate // error message. We just set native type to be same as managedtype nativeType = managedType; _hasInvalidLayout = true; } _fields[index++] = new NativeStructField(nativeType, this, field); } }
public static bool IsMarshallingRequired(MethodDesc targetMethod) { Debug.Assert(targetMethod.IsPInvoke); if (targetMethod.IsUnmanagedCallersOnly) { return(true); } PInvokeMetadata metadata = targetMethod.GetPInvokeMethodMetadata(); PInvokeFlags flags = metadata.Flags; if (flags.SetLastError) { return(true); } if (!flags.PreserveSig) { return(true); } if (MarshalHelpers.ShouldCheckForPendingException(targetMethod.Context.Target, metadata)) { return(true); } var marshallers = GetMarshallersForMethod(targetMethod); for (int i = 0; i < marshallers.Length; i++) { if (marshallers[i].IsMarshallingRequired()) { return(true); } } return(false); }
private static MarshallerKind GetArrayElementMarshallerKind( ArrayType arrayType, MarshalAsDescriptor marshalAs, bool isAnsi) { TypeDesc elementType = arrayType.ElementType; NativeTypeKind nativeType = NativeTypeKind.Invalid; TypeSystemContext context = arrayType.Context; if (marshalAs != null) { nativeType = (NativeTypeKind)marshalAs.ArraySubType; } if (elementType.IsPrimitive) { switch (elementType.Category) { case TypeFlags.Char: switch (nativeType) { case NativeTypeKind.I1: case NativeTypeKind.U1: return(MarshallerKind.AnsiChar); case NativeTypeKind.I2: case NativeTypeKind.U2: return(MarshallerKind.UnicodeChar); default: if (isAnsi) { return(MarshallerKind.AnsiChar); } else { return(MarshallerKind.UnicodeChar); } } case TypeFlags.Boolean: switch (nativeType) { case NativeTypeKind.Boolean: return(MarshallerKind.Bool); case NativeTypeKind.I1: case NativeTypeKind.U1: return(MarshallerKind.CBool); case NativeTypeKind.Invalid: default: return(MarshallerKind.Bool); } case TypeFlags.IntPtr: case TypeFlags.UIntPtr: return(MarshallerKind.BlittableValue); case TypeFlags.Void: return(MarshallerKind.Invalid); case TypeFlags.SByte: case TypeFlags.Int16: case TypeFlags.Int32: case TypeFlags.Int64: case TypeFlags.Byte: case TypeFlags.UInt16: case TypeFlags.UInt32: case TypeFlags.UInt64: case TypeFlags.Single: case TypeFlags.Double: return(MarshallerKind.BlittableValue); default: return(MarshallerKind.Invalid); } } else if (elementType.IsValueType) { if (elementType.IsEnum) { return(MarshallerKind.Enum); } if (InteropTypes.IsSystemDecimal(context, elementType)) { switch (nativeType) { case NativeTypeKind.Invalid: case NativeTypeKind.Struct: return(MarshallerKind.Decimal); case NativeTypeKind.LPStruct: return(MarshallerKind.BlittableStructPtr); default: return(MarshallerKind.Invalid); } } else if (InteropTypes.IsSystemGuid(context, elementType)) { switch (nativeType) { case NativeTypeKind.Invalid: case NativeTypeKind.Struct: return(MarshallerKind.BlittableValue); case NativeTypeKind.LPStruct: return(MarshallerKind.BlittableStructPtr); default: return(MarshallerKind.Invalid); } } else if (InteropTypes.IsSystemDateTime(context, elementType)) { if (nativeType == NativeTypeKind.Invalid || nativeType == NativeTypeKind.Struct) { return(MarshallerKind.OleDateTime); } else { return(MarshallerKind.Invalid); } } else if (InteropTypes.IsHandleRef(context, elementType)) { if (nativeType == NativeTypeKind.Invalid) { return(MarshallerKind.HandleRef); } else { return(MarshallerKind.Invalid); } } else { if (MarshalHelpers.IsBlittableType(elementType)) { switch (nativeType) { case NativeTypeKind.Invalid: case NativeTypeKind.Struct: return(MarshallerKind.BlittableStruct); default: return(MarshallerKind.Invalid); } } else { // TODO: Differentiate between struct and Union, we only need to support struct not union here return(MarshallerKind.Struct); } } } else if (elementType.IsPointer || elementType.IsFunctionPointer) { if (nativeType == NativeTypeKind.Invalid) { return(MarshallerKind.BlittableValue); } else { return(MarshallerKind.Invalid); } } else if (elementType.IsString) { switch (nativeType) { case NativeTypeKind.Invalid: if (isAnsi) { return(MarshallerKind.AnsiString); } else { return(MarshallerKind.UnicodeString); } case NativeTypeKind.LPStr: return(MarshallerKind.AnsiString); case NativeTypeKind.LPWStr: return(MarshallerKind.UnicodeString); default: return(MarshallerKind.Invalid); } } // else if (elementType.IsObject) // { // if (nativeType == NativeTypeKind.Invalid) // return MarshallerKind.Variant; // else // return MarshallerKind.Invalid; // } else { return(MarshallerKind.Invalid); } }
internal static MarshallerKind GetMarshallerKind( TypeDesc type, MarshalAsDescriptor marshalAs, bool isReturn, bool isAnsi, MarshallerType marshallerType, out MarshallerKind elementMarshallerKind) { if (type.IsByRef) { type = type.GetParameterType(); } TypeSystemContext context = type.Context; NativeTypeKind nativeType = NativeTypeKind.Invalid; bool isField = marshallerType == MarshallerType.Field; if (marshalAs != null) { nativeType = (NativeTypeKind)marshalAs.Type; } elementMarshallerKind = MarshallerKind.Invalid; // // Determine MarshalerKind // // This mostly resembles desktop CLR and .NET Native code as we need to match their behavior // if (type.IsPrimitive) { switch (type.Category) { case TypeFlags.Void: return(MarshallerKind.VoidReturn); case TypeFlags.Boolean: switch (nativeType) { case NativeTypeKind.Invalid: case NativeTypeKind.Boolean: return(MarshallerKind.Bool); case NativeTypeKind.U1: case NativeTypeKind.I1: return(MarshallerKind.CBool); default: return(MarshallerKind.Invalid); } case TypeFlags.Char: switch (nativeType) { case NativeTypeKind.I1: case NativeTypeKind.U1: return(MarshallerKind.AnsiChar); case NativeTypeKind.I2: case NativeTypeKind.U2: return(MarshallerKind.UnicodeChar); case NativeTypeKind.Invalid: if (isAnsi) { return(MarshallerKind.AnsiChar); } else { return(MarshallerKind.UnicodeChar); } default: return(MarshallerKind.Invalid); } case TypeFlags.SByte: case TypeFlags.Byte: if (nativeType == NativeTypeKind.I1 || nativeType == NativeTypeKind.U1 || nativeType == NativeTypeKind.Invalid) { return(MarshallerKind.BlittableValue); } else { return(MarshallerKind.Invalid); } case TypeFlags.Int16: case TypeFlags.UInt16: if (nativeType == NativeTypeKind.I2 || nativeType == NativeTypeKind.U2 || nativeType == NativeTypeKind.Invalid) { return(MarshallerKind.BlittableValue); } else { return(MarshallerKind.Invalid); } case TypeFlags.Int32: case TypeFlags.UInt32: if (nativeType == NativeTypeKind.I4 || nativeType == NativeTypeKind.U4 || nativeType == NativeTypeKind.Invalid) { return(MarshallerKind.BlittableValue); } else { return(MarshallerKind.Invalid); } case TypeFlags.Int64: case TypeFlags.UInt64: if (nativeType == NativeTypeKind.I8 || nativeType == NativeTypeKind.U8 || nativeType == NativeTypeKind.Invalid) { return(MarshallerKind.BlittableValue); } else { return(MarshallerKind.Invalid); } case TypeFlags.IntPtr: case TypeFlags.UIntPtr: if (nativeType == NativeTypeKind.Invalid) { return(MarshallerKind.BlittableValue); } else { return(MarshallerKind.Invalid); } case TypeFlags.Single: if (nativeType == NativeTypeKind.R4 || nativeType == NativeTypeKind.Invalid) { return(MarshallerKind.BlittableValue); } else { return(MarshallerKind.Invalid); } case TypeFlags.Double: if (nativeType == NativeTypeKind.R8 || nativeType == NativeTypeKind.Invalid) { return(MarshallerKind.BlittableValue); } else { return(MarshallerKind.Invalid); } default: return(MarshallerKind.Invalid); } } else if (type.IsValueType) { if (type.IsEnum) { return(MarshallerKind.Enum); } if (InteropTypes.IsSystemDateTime(context, type)) { if (nativeType == NativeTypeKind.Invalid || nativeType == NativeTypeKind.Struct) { return(MarshallerKind.OleDateTime); } else { return(MarshallerKind.Invalid); } } else if (InteropTypes.IsHandleRef(context, type)) { if (nativeType == NativeTypeKind.Invalid) { return(MarshallerKind.HandleRef); } else { return(MarshallerKind.Invalid); } } switch (nativeType) { case NativeTypeKind.Invalid: case NativeTypeKind.Struct: if (InteropTypes.IsSystemDecimal(context, type)) { return(MarshallerKind.Decimal); } break; case NativeTypeKind.LPStruct: if (InteropTypes.IsSystemGuid(context, type) || InteropTypes.IsSystemDecimal(context, type)) { if (isField || isReturn) { return(MarshallerKind.Invalid); } else { return(MarshallerKind.BlittableStructPtr); } } break; default: return(MarshallerKind.Invalid); } if (type is MetadataType) { MetadataType metadataType = (MetadataType)type; // the struct type need to be either sequential or explicit. If it is // auto layout we will throw exception. if (!metadataType.IsSequentialLayout && !metadataType.IsExplicitLayout) { throw new InvalidProgramException("The specified structure " + metadataType.Name + " has invalid StructLayout information. It must be either Sequential or Explicit."); } } if (MarshalHelpers.IsBlittableType(type)) { return(MarshallerKind.BlittableStruct); } else { return(MarshallerKind.Struct); } } else if (type.IsSzArray) { if (nativeType == NativeTypeKind.Invalid) { nativeType = NativeTypeKind.Array; } switch (nativeType) { case NativeTypeKind.Array: { if (isField || isReturn) { return(MarshallerKind.Invalid); } var arrayType = (ArrayType)type; elementMarshallerKind = GetArrayElementMarshallerKind( arrayType, marshalAs, isAnsi); // If element is invalid type, the array itself is invalid if (elementMarshallerKind == MarshallerKind.Invalid) { return(MarshallerKind.Invalid); } if (elementMarshallerKind == MarshallerKind.AnsiChar) { return(MarshallerKind.AnsiCharArray); } else if (elementMarshallerKind == MarshallerKind.UnicodeChar || // Arrays of unicode char should be marshalled as blittable arrays elementMarshallerKind == MarshallerKind.Enum || elementMarshallerKind == MarshallerKind.BlittableValue) { return(MarshallerKind.BlittableArray); } else { return(MarshallerKind.Array); } } case NativeTypeKind.ByValArray: // fix sized array { var arrayType = (ArrayType)type; elementMarshallerKind = GetArrayElementMarshallerKind( arrayType, marshalAs, isAnsi); // If element is invalid type, the array itself is invalid if (elementMarshallerKind == MarshallerKind.Invalid) { return(MarshallerKind.Invalid); } if (elementMarshallerKind == MarshallerKind.AnsiChar) { return(MarshallerKind.ByValAnsiCharArray); } else { return(MarshallerKind.ByValArray); } } default: return(MarshallerKind.Invalid); } } else if (type.IsPointer || type.IsFunctionPointer) { if (nativeType == NativeTypeKind.Invalid) { return(MarshallerKind.BlittableValue); } else { return(MarshallerKind.Invalid); } } else if (type.IsDelegate) { if (nativeType == NativeTypeKind.Invalid || nativeType == NativeTypeKind.Func) { return(MarshallerKind.FunctionPointer); } else { return(MarshallerKind.Invalid); } } else if (type.IsString) { switch (nativeType) { case NativeTypeKind.LPWStr: return(MarshallerKind.UnicodeString); case NativeTypeKind.LPStr: return(MarshallerKind.AnsiString); case NativeTypeKind.LPTStr: return(MarshallerKind.UnicodeString); case NativeTypeKind.ByValTStr: if (isAnsi) { elementMarshallerKind = MarshallerKind.AnsiChar; return(MarshallerKind.ByValAnsiString); } else { elementMarshallerKind = MarshallerKind.UnicodeChar; return(MarshallerKind.ByValUnicodeString); } case NativeTypeKind.Invalid: if (isAnsi) { return(MarshallerKind.AnsiString); } else { return(MarshallerKind.UnicodeString); } default: return(MarshallerKind.Invalid); } } // else if (type.IsObject) // { // if (nativeType == NativeTypeKind.Invalid) // return MarshallerKind.Variant; // else // return MarshallerKind.Invalid; // } else if (InteropTypes.IsStringBuilder(context, type)) { switch (nativeType) { case NativeTypeKind.Invalid: if (isAnsi) { return(MarshallerKind.AnsiStringBuilder); } else { return(MarshallerKind.UnicodeStringBuilder); } case NativeTypeKind.LPStr: return(MarshallerKind.AnsiStringBuilder); case NativeTypeKind.LPWStr: return(MarshallerKind.UnicodeStringBuilder); default: return(MarshallerKind.Invalid); } } else if (InteropTypes.IsSafeHandle(context, type)) { if (nativeType == NativeTypeKind.Invalid) { return(MarshallerKind.SafeHandle); } else { return(MarshallerKind.Invalid); } } else if (InteropTypes.IsCriticalHandle(context, type)) { if (nativeType == NativeTypeKind.Invalid) { return(MarshallerKind.CriticalHandle); } else { return(MarshallerKind.Invalid); } } else { return(MarshallerKind.Invalid); } }
private static MarshallerKind GetArrayElementMarshallerKind( ArrayType arrayType, TypeDesc elementType, MarshalAsDescriptor marshalAs, PInvokeMethodData methodData, bool isField) { bool isAnsi = (methodData.GetCharSet() & PInvokeAttributes.CharSetAnsi) == PInvokeAttributes.CharSetAnsi; NativeType nativeType = NativeType.Invalid; if (marshalAs != null) { nativeType = (NativeType)marshalAs.ArraySubType; } if (elementType.IsPrimitive) { switch (elementType.Category) { case TypeFlags.Char: switch (nativeType) { case NativeType.I1: case NativeType.U1: return(MarshallerKind.AnsiChar); case NativeType.I2: case NativeType.U2: return(MarshallerKind.UnicodeChar); default: if (isAnsi) { return(MarshallerKind.AnsiChar); } else { return(MarshallerKind.UnicodeChar); } } case TypeFlags.Boolean: switch (nativeType) { case NativeType.Boolean: return(MarshallerKind.Bool); case NativeType.I1: case NativeType.U1: return(MarshallerKind.CBool); case NativeType.Invalid: default: return(MarshallerKind.Bool); } case TypeFlags.IntPtr: case TypeFlags.UIntPtr: return(MarshallerKind.BlittableValue); case TypeFlags.Void: return(MarshallerKind.Invalid); case TypeFlags.SByte: case TypeFlags.Int16: case TypeFlags.Int32: case TypeFlags.Int64: case TypeFlags.Byte: case TypeFlags.UInt16: case TypeFlags.UInt32: case TypeFlags.UInt64: case TypeFlags.Single: case TypeFlags.Double: return(MarshallerKind.BlittableValue); default: return(MarshallerKind.Invalid); } } else if (elementType.IsValueType) { if (elementType.IsEnum) { return(MarshallerKind.Enum); } if (methodData.IsSystemDecimal(elementType)) { switch (nativeType) { case NativeType.Invalid: case NativeType.Struct: return(MarshallerKind.Decimal); case NativeType.LPStruct: return(MarshallerKind.BlittableStructPtr); default: return(MarshallerKind.Invalid); } } else if (methodData.IsSystemGuid(elementType)) { switch (nativeType) { case NativeType.Invalid: case NativeType.Struct: return(MarshallerKind.BlittableValue); case NativeType.LPStruct: return(MarshallerKind.BlittableStructPtr); default: return(MarshallerKind.Invalid); } } else if (methodData.IsSystemDateTime(elementType)) { if (nativeType == NativeType.Invalid || nativeType == NativeType.Struct) { return(MarshallerKind.OleDateTime); } else { return(MarshallerKind.Invalid); } } /* * TODO: Bring HandleRef to CoreLib * https://github.com/dotnet/corert/issues/2570 * * else if (methodData.IsHandleRef(elementType)) * { * return MarshallerKind.HandleRef; * } */ else { if (MarshalHelpers.IsBlittableType(elementType)) { switch (nativeType) { case NativeType.Invalid: case NativeType.Struct: return(MarshallerKind.BlittableStruct); default: return(MarshallerKind.Invalid); } } else { // TODO: Differentiate between struct and Union, we only need to support struct not union here return(MarshallerKind.Struct); } } } else // !valueType { if (elementType.IsString) { switch (nativeType) { case NativeType.Invalid: if (isAnsi) { return(MarshallerKind.AnsiString); } else { return(MarshallerKind.UnicodeString); } case NativeType.LPStr: return(MarshallerKind.AnsiString); case NativeType.LPWStr: return(MarshallerKind.UnicodeString); default: return(MarshallerKind.Invalid); } } if (elementType.IsObject) { if (nativeType == NativeType.Invalid) { return(MarshallerKind.Variant); } else { return(MarshallerKind.Invalid); } } if (elementType.IsSzArray) { return(MarshallerKind.Invalid); } if (elementType.IsPointer) { return(MarshallerKind.Invalid); } if (methodData.IsSafeHandle(elementType)) { return(MarshallerKind.Invalid); } /* * TODO: Bring CriticalHandle to CoreLib * https://github.com/dotnet/corert/issues/2570 * * if (methodData.IsCriticalHandle(elementType)) * { * return MarshallerKind.Invalid; * } */ } return(MarshallerKind.Invalid); }
private static MarshallerKind GetMarshallerKind( TypeDesc type, ParameterMetadata parameterData, PInvokeMethodData methodData, bool isField) { if (type.IsByRef) { var byRefType = (ByRefType)type; type = byRefType.ParameterType; } NativeType nativeType = NativeType.Invalid; bool isReturn = parameterData.Return; MarshalAsDescriptor marshalAs = parameterData.MarshalAsDescriptor; if (marshalAs != null) { nativeType = (NativeType)marshalAs.Type; } bool isAnsi = (methodData.GetCharSet() & PInvokeAttributes.CharSetAnsi) == PInvokeAttributes.CharSetAnsi; // // Determine MarshalerKind // // This mostly resembles desktop CLR and .NET Native code as we need to match their behavior // if (type.IsPrimitive) { switch (type.Category) { case TypeFlags.Void: return(MarshallerKind.VoidReturn); case TypeFlags.Boolean: switch (nativeType) { case NativeType.Invalid: case NativeType.Boolean: return(MarshallerKind.Bool); case NativeType.U1: case NativeType.I1: return(MarshallerKind.CBool); default: return(MarshallerKind.Invalid); } case TypeFlags.Char: switch (nativeType) { case NativeType.I1: case NativeType.U1: return(MarshallerKind.AnsiChar); case NativeType.I2: case NativeType.U2: return(MarshallerKind.UnicodeChar); case NativeType.Invalid: if (isAnsi) { return(MarshallerKind.AnsiChar); } else { return(MarshallerKind.UnicodeChar); } default: return(MarshallerKind.Invalid); } case TypeFlags.SByte: case TypeFlags.Byte: if (nativeType == NativeType.I1 || nativeType == NativeType.U1 || nativeType == NativeType.Invalid) { return(MarshallerKind.BlittableValue); } else { return(MarshallerKind.Invalid); } case TypeFlags.Int16: case TypeFlags.UInt16: if (nativeType == NativeType.I2 || nativeType == NativeType.U2 || nativeType == NativeType.Invalid) { return(MarshallerKind.BlittableValue); } else { return(MarshallerKind.Invalid); } case TypeFlags.Int32: case TypeFlags.UInt32: if (nativeType == NativeType.I4 || nativeType == NativeType.U4 || nativeType == NativeType.Invalid) { return(MarshallerKind.BlittableValue); } else { return(MarshallerKind.Invalid); } case TypeFlags.Int64: case TypeFlags.UInt64: if (nativeType == NativeType.I8 || nativeType == NativeType.U8 || nativeType == NativeType.Invalid) { return(MarshallerKind.BlittableValue); } else { return(MarshallerKind.Invalid); } case TypeFlags.IntPtr: case TypeFlags.UIntPtr: if (nativeType == NativeType.Invalid) { return(MarshallerKind.BlittableValue); } else { return(MarshallerKind.Invalid); } case TypeFlags.Single: if (nativeType == NativeType.R4 || nativeType == NativeType.Invalid) { return(MarshallerKind.BlittableValue); } else { return(MarshallerKind.Invalid); } case TypeFlags.Double: if (nativeType == NativeType.R8 || nativeType == NativeType.Invalid) { return(MarshallerKind.BlittableValue); } else { return(MarshallerKind.Invalid); } default: return(MarshallerKind.Invalid); } } else if (type.IsValueType) { if (type.IsEnum) { return(MarshallerKind.Enum); } if (methodData.IsSystemDateTime(type)) { if (nativeType == NativeType.Invalid || nativeType == NativeType.Struct) { return(MarshallerKind.OleDateTime); } else { return(MarshallerKind.Invalid); } } /* * TODO: Bring HandleRef to CoreLib * https://github.com/dotnet/corert/issues/2570 * * else if (methodData.IsHandleRef(type)) * { * if (nativeType == NativeType.Invalid) * return MarshallerKind.HandleRef; * else * return MarshallerKind.Invalid; * } */ switch (nativeType) { case NativeType.Invalid: case NativeType.Struct: if (methodData.IsSystemDecimal(type)) { return(MarshallerKind.Decimal); } break; case NativeType.LPStruct: if (methodData.IsSystemGuid(type) || methodData.IsSystemDecimal(type)) { if (isField || isReturn) { return(MarshallerKind.Invalid); } else { return(MarshallerKind.BlittableStructPtr); } } break; default: return(MarshallerKind.Invalid); } if (MarshalHelpers.IsBlittableType(type)) { return(MarshallerKind.BlittableStruct); } else { return(MarshallerKind.Struct); } } else // !ValueType { if (type.Category == TypeFlags.Class) { if (type.IsString) { switch (nativeType) { case NativeType.LPWStr: return(MarshallerKind.UnicodeString); case NativeType.LPStr: return(MarshallerKind.AnsiString); case NativeType.Invalid: if (isAnsi) { return(MarshallerKind.AnsiString); } else { return(MarshallerKind.UnicodeString); } default: return(MarshallerKind.Invalid); } } else if (type.IsDelegate) { if (nativeType == NativeType.Invalid || nativeType == NativeType.Func) { return(MarshallerKind.FunctionPointer); } else { return(MarshallerKind.Invalid); } } else if (type.IsObject) { if (nativeType == NativeType.Invalid) { return(MarshallerKind.Variant); } else { return(MarshallerKind.Invalid); } } else if (methodData.IsStringBuilder(type)) { switch (nativeType) { case NativeType.Invalid: if (isAnsi) { return(MarshallerKind.AnsiStringBuilder); } else { return(MarshallerKind.UnicodeStringBuilder); } case NativeType.LPStr: return(MarshallerKind.AnsiStringBuilder); case NativeType.LPWStr: return(MarshallerKind.UnicodeStringBuilder); default: return(MarshallerKind.Invalid); } } else if (methodData.IsSafeHandle(type)) { if (nativeType == NativeType.Invalid) { return(MarshallerKind.SafeHandle); } else { return(MarshallerKind.Invalid); } } /* * TODO: Bring CriticalHandle to CoreLib * https://github.com/dotnet/corert/issues/2570 * * else if (methodData.IsCriticalHandle(type)) * { * if (nativeType != NativeType.Invalid || isField) * { * return MarshallerKind.Invalid; * } * else * { * return MarshallerKind.CriticalHandle; * } * } */ return(MarshallerKind.Invalid); } else if (methodData.IsSystemArray(type)) { return(MarshallerKind.Invalid); } else if (type.IsSzArray) { MarshallerKind elementMarshallerKind; if (nativeType == NativeType.Invalid) { nativeType = NativeType.Array; } switch (nativeType) { case NativeType.Array: { if (isField || isReturn) { return(MarshallerKind.Invalid); } var arrayType = (ArrayType)type; elementMarshallerKind = GetArrayElementMarshallerKind( arrayType, arrayType.ElementType, marshalAs, methodData, isField); // If element is invalid type, the array itself is invalid if (elementMarshallerKind == MarshallerKind.Invalid) { return(MarshallerKind.Invalid); } if (elementMarshallerKind == MarshallerKind.AnsiChar) { return(MarshallerKind.AnsiCharArray); } else if (elementMarshallerKind == MarshallerKind.UnicodeChar) { // Arrays of unicode char should be marshalled as blittable arrays return(MarshallerKind.BlittableArray); } else { return(MarshallerKind.Array); } } case NativeType.ByValArray: // fix sized array { var arrayType = (ArrayType)type; elementMarshallerKind = GetArrayElementMarshallerKind( arrayType, arrayType.ElementType, marshalAs, methodData, isField); // If element is invalid type, the array itself is invalid if (elementMarshallerKind == MarshallerKind.Invalid) { return(MarshallerKind.Invalid); } if (elementMarshallerKind == MarshallerKind.AnsiChar) { return(MarshallerKind.ByValAnsiCharArray); } else { return(MarshallerKind.ByValArray); } } default: return(MarshallerKind.Invalid); } } else if (type.Category == TypeFlags.Pointer) { // // @TODO - add checks for the pointee type in case the pointee type is not blittable // C# already does this and will emit compilation errors (can't declare pointers to // managed type). // if (nativeType == NativeType.Invalid) { return(MarshallerKind.BlittableValue); } else { return(MarshallerKind.Invalid); } } } return(MarshallerKind.Invalid); }
private static MarshallerKind GetMarshallerKind(TypeDesc type, MarshalAsDescriptor marshalAs, PInvokeMethodData PInvokeMethodData, bool isReturn) { if (isReturn) { if (type.IsVoid) { return(MarshallerKind.VoidReturn); } if (MarshalHelpers.IsBlittableType(type)) { return(MarshallerKind.BlittableValue); } if (type.Category == TypeFlags.Boolean) { return(MarshallerKind.Bool); } if (PInvokeMethodData.IsSafeHandle(type)) { return(MarshallerKind.SafeHandle); } throw new NotSupportedException(); } if (MarshalHelpers.IsBlittableType(type)) { return(MarshallerKind.BlittableValue); } TypeSystemContext context = PInvokeMethodData.Context; if (type.IsSzArray) { var arrayType = (ArrayType)type; if (MarshalHelpers.IsBlittableType(arrayType.ParameterType)) { return(MarshallerKind.BlittableArray); } if (arrayType.ParameterType == context.GetWellKnownType(WellKnownType.Char)) { if (PInvokeMethodData.GetCharSet() == PInvokeAttributes.CharSetUnicode) { return(MarshallerKind.BlittableArray); } } } if (type.IsByRef) { var byRefType = (ByRefType)type; if (MarshalHelpers.IsBlittableType(byRefType.ParameterType)) { return(MarshallerKind.BlittableByRef); } if (byRefType.ParameterType == context.GetWellKnownType(WellKnownType.Char)) { if (PInvokeMethodData.GetCharSet() == PInvokeAttributes.CharSetUnicode) { return(MarshallerKind.BlittableByRef); } } } if (type.IsString) { return(MarshallerKind.String); } if (type.Category == TypeFlags.Boolean) { return(MarshallerKind.Bool); } if (type is MetadataType) { var metadataType = (MetadataType)type; if (metadataType.Module == context.SystemModule) { var nameSpace = metadataType.Namespace; var name = metadataType.Name; if (name == "StringBuilder" && nameSpace == "System.Text") { return(MarshallerKind.StringBuilder); } } } if (PInvokeMethodData.IsSafeHandle(type)) { return(MarshallerKind.SafeHandle); } throw new NotSupportedException(); }