/// <summary> /// Create a marshaller /// </summary> /// <param name="parameterType">type of the parameter to marshal</param> /// <param name="pInvokeMethodData">PInvoke Method specific marshal data</param> /// <param name="pInvokeParameterdata">PInvoke parameter specific marshal data</param> /// <returns>The created Marshaller</returns> public static Marshaller CreateMarshaller(TypeDesc parameterType, PInvokeMethodData pInvokeMethodData, ParameterMetadata pInvokeParameterdata) { MarshallerKind marshallerKind = GetMarshallerKind(parameterType, pInvokeParameterdata, pInvokeMethodData, isField: false); // Create the marshaller based on MarshallerKind Marshaller marshaller = Marshaller.CreateMarshallerInternal(marshallerKind); marshaller.PInvokeMethodData = pInvokeMethodData; marshaller.PInvokeParameterMetadata = pInvokeParameterdata; marshaller.MarshallerKind = marshallerKind; marshaller.NativeParameterType = null; marshaller.ManagedParameterType = parameterType; marshaller.Optional = pInvokeParameterdata.Optional; marshaller.Return = pInvokeParameterdata.Return; marshaller.IsByRef = parameterType.IsByRef; marshaller.In = pInvokeParameterdata.In; // // Desktop ignores [Out] on marshaling scenarios where they don't make sense (such as passing // value types and string as [out] without byref). // if (parameterType.IsByRef) { // Passing as [Out] by ref is valid marshaller.Out = pInvokeParameterdata.Out; } else { // Passing as [Out] is valid only if it is not ValueType nor string if (!parameterType.IsValueType && !parameterType.IsString) { marshaller.Out = pInvokeParameterdata.Out; } } if (!marshaller.In && !marshaller.Out) { // // Rules for in/out // 1. ByRef args: [in]/[out] implied by default // 2. StringBuilder: [in, out] by default // 3. non-ByRef args: [In] is implied if no [In]/[Out] is specified // if (parameterType.IsByRef) { marshaller.In = true; marshaller.Out = true; } else if (pInvokeMethodData.IsStringBuilder(parameterType)) { marshaller.In = true; marshaller.Out = true; } else { marshaller.In = true; } } return(marshaller); }
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); }