protected override TypeDesc MarshalArgument(TypeDesc managedType, ILEmitter emitter, ILCodeStream marshallingCodeStream, ILCodeStream unmarshallingCodeStream) { TypeSystemContext context = PInvokeMethodData.Context; if (PInvokeMethodData.GetCharSet() == PInvokeAttributes.CharSetUnicode) { // TODO: Handles [out] marshalling only for now var stringBuilderType = context.SystemModule.GetKnownType("System.Text", "StringBuilder"); var charArrayType = context.GetWellKnownType(WellKnownType.Char).MakeArrayType(); IL.Stubs.ILLocalVariable vStringBuilder = emitter.NewLocal(stringBuilderType); IL.Stubs.ILLocalVariable vBuffer = emitter.NewLocal(charArrayType); marshallingCodeStream.EmitStLoc(vStringBuilder); marshallingCodeStream.EmitLdLoc(vStringBuilder); marshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( context.GetHelperEntryPoint("InteropHelpers", "GetEmptyStringBuilderBuffer"))); marshallingCodeStream.EmitStLoc(vBuffer); unmarshallingCodeStream.EmitLdLoc(vStringBuilder); unmarshallingCodeStream.EmitLdLoc(vBuffer); unmarshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( context.GetHelperEntryPoint("InteropHelpers", "ReplaceStringBuilderBuffer"))); marshallingCodeStream.EmitLdLoc(vBuffer); return(base.MarshalArgument(charArrayType, emitter, marshallingCodeStream, unmarshallingCodeStream)); } else { throw new NotSupportedException(); } }
protected override TypeDesc MarshalArgument(TypeDesc managedType, ILEmitter emitter, ILCodeStream marshallingCodeStream, ILCodeStream unmarshallingCodeStream) { TypeSystemContext context = PInvokeMethodData.Context; if (PInvokeMethodData.GetCharSet() == PInvokeAttributes.CharSetUnicode) { // // Unicode marshalling. Pin the string and push a pointer to the first character on the stack. // TypeDesc stringType = context.GetWellKnownType(WellKnownType.String); IL.Stubs.ILLocalVariable vPinnedString = emitter.NewLocal(stringType, true); ILCodeLabel lNullString = emitter.NewCodeLabel(); marshallingCodeStream.EmitStLoc(vPinnedString); marshallingCodeStream.EmitLdLoc(vPinnedString); marshallingCodeStream.Emit(ILOpcode.conv_i); marshallingCodeStream.Emit(ILOpcode.dup); // Marshalling a null string? marshallingCodeStream.Emit(ILOpcode.brfalse, lNullString); marshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken( context.SystemModule. GetKnownType("System.Runtime.CompilerServices", "RuntimeHelpers"). GetKnownMethod("get_OffsetToStringData", null))); marshallingCodeStream.Emit(ILOpcode.add); marshallingCodeStream.EmitLabel(lNullString); return(context.GetWellKnownType(WellKnownType.IntPtr)); } else { // // ANSI marshalling. Allocate a byte array, copy characters, pin first element. // var stringToAnsi = context.GetHelperEntryPoint("InteropHelpers", "StringToAnsi"); marshallingCodeStream.Emit(ILOpcode.call, emitter.NewToken(stringToAnsi)); // Call the Array marshaller MarshalArgument return(base.MarshalArgument(context.GetWellKnownType(WellKnownType.Byte).MakeArrayType(), emitter, marshallingCodeStream, unmarshallingCodeStream)); } }
/// <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.MarshalAsDescriptor, pInvokeMethodData, pInvokeParameterdata.Return); // Create the marshaller based on MarshallerKind Marshaller marshaller = Marshaller.CreateMarshallerInternal(marshallerKind); marshaller.PInvokeMethodData = pInvokeMethodData; marshaller.PInvokeParameterMetadata = pInvokeParameterdata; marshaller.MarshallerKind = marshallerKind; marshaller.NativeType = null; marshaller.ManagedType = parameterType; return(marshaller); }
/// <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 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(); }