Beispiel #1
0
        /// <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);
        }
Beispiel #2
0
 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);
        }
Beispiel #4
0
        /// <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);
        }
Beispiel #5
0
        /// <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));
        }
Beispiel #8
0
        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);
            }
        }
Beispiel #9
0
        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);
            }
        }
Beispiel #12
0
        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);
        }
Beispiel #13
0
        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);
        }
Beispiel #14
0
        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();
        }