diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerAnalyzer.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerAnalyzer.cs index c4f219267c60ef..dfc4139263dc5c 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerAnalyzer.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerAnalyzer.cs @@ -490,7 +490,7 @@ private static void AnalyzeManagedTypeMarshallingInfo(SymbolAnalysisContext cont type.ToDisplayString())); } - (bool hasCustomTypeMarshallerAttribute, ITypeSymbol? marshallerManagedType, _) = ManualTypeMarshallingHelper.GetMarshallerShapeInfo(marshallerType); + (bool hasCustomTypeMarshallerAttribute, ITypeSymbol? marshallerManagedType, _) = ManualTypeMarshallingHelper_V1.GetMarshallerShapeInfo(marshallerType); marshallerManagedType = ManualTypeMarshallingHelper.ResolveManagedType(marshallerManagedType, marshallerType, context.Compilation); @@ -534,7 +534,7 @@ private static bool TypeSymbolsConstructedFromEqualTypes(ITypeSymbol left, IType public void AnalyzeMarshallerType(SymbolAnalysisContext context) { INamedTypeSymbol marshallerType = (INamedTypeSymbol)context.Symbol; - (bool hasCustomTypeMarshallerAttribute, ITypeSymbol? type, CustomTypeMarshallerData? marshallerDataMaybe) = ManualTypeMarshallingHelper.GetMarshallerShapeInfo(marshallerType); + (bool hasCustomTypeMarshallerAttribute, ITypeSymbol? type, CustomTypeMarshallerData_V1? marshallerDataMaybe) = ManualTypeMarshallingHelper_V1.GetMarshallerShapeInfo(marshallerType); type = ManualTypeMarshallingHelper.ResolveManagedType(type, marshallerType, context.Compilation); if (!hasCustomTypeMarshallerAttribute) @@ -583,12 +583,12 @@ public void AnalyzeMarshallerType(SymbolAnalysisContext context) continue; } - if (inConstructor is null && ManualTypeMarshallingHelper.IsManagedToNativeConstructor(ctor, type, marshallerData.Kind)) + if (inConstructor is null && ManualTypeMarshallingHelper_V1.IsManagedToNativeConstructor(ctor, type, marshallerData.Kind)) { inConstructor = ctor; } - if (callerAllocatedSpanConstructor is null && ManualTypeMarshallingHelper.IsCallerAllocatedSpanConstructor(ctor, type, _spanOfT, marshallerData.Kind, out _)) + if (callerAllocatedSpanConstructor is null && ManualTypeMarshallingHelper_V1.IsCallerAllocatedSpanConstructor(ctor, type, _spanOfT, marshallerData.Kind, out _)) { callerAllocatedSpanConstructor = ctor; } @@ -653,30 +653,30 @@ public void AnalyzeMarshallerType(SymbolAnalysisContext context) } } - if (marshallerData.Direction.HasFlag(CustomTypeMarshallerDirection.Out) && !ManualTypeMarshallingHelper.HasToManagedMethod(marshallerType, type)) + if (marshallerData.Direction.HasFlag(CustomTypeMarshallerDirection.Out) && !ManualTypeMarshallingHelper_V1.HasToManagedMethod(marshallerType, type)) { context.ReportDiagnostic( marshallerType.CreateDiagnostic( OutRequiresToManagedRule, ImmutableDictionary.Empty.Add( MissingMemberNames.Key, - ShapeMemberNames.Value.ToManaged), + ShapeMemberNames_V1.Value.ToManaged), marshallerType.ToDisplayString())); } if (marshallerData.Kind == CustomTypeMarshallerKind.LinearCollection) { - IMethodSymbol? getManagedValuesSourceMethod = ManualTypeMarshallingHelper.FindGetManagedValuesSourceMethod(marshallerType, _readOnlySpanOfT); - IMethodSymbol? getManagedValuesDestinationMethod = ManualTypeMarshallingHelper.FindGetManagedValuesDestinationMethod(marshallerType, _spanOfT); - IMethodSymbol? getNativeValuesSourceMethod = ManualTypeMarshallingHelper.FindGetNativeValuesSourceMethod(marshallerType, _readOnlySpanOfByte); - IMethodSymbol? getNativeValuesDestinationMethod = ManualTypeMarshallingHelper.FindGetNativeValuesDestinationMethod(marshallerType, _spanOfByte); + IMethodSymbol? getManagedValuesSourceMethod = ManualTypeMarshallingHelper_V1.FindGetManagedValuesSourceMethod(marshallerType, _readOnlySpanOfT); + IMethodSymbol? getManagedValuesDestinationMethod = ManualTypeMarshallingHelper_V1.FindGetManagedValuesDestinationMethod(marshallerType, _spanOfT); + IMethodSymbol? getNativeValuesSourceMethod = ManualTypeMarshallingHelper_V1.FindGetNativeValuesSourceMethod(marshallerType, _readOnlySpanOfByte); + IMethodSymbol? getNativeValuesDestinationMethod = ManualTypeMarshallingHelper_V1.FindGetNativeValuesDestinationMethod(marshallerType, _spanOfByte); if (marshallerData.Direction.HasFlag(CustomTypeMarshallerDirection.In) && (getManagedValuesSourceMethod is null || getNativeValuesDestinationMethod is null)) { var missingMembers = (getManagedValuesSourceMethod, getNativeValuesDestinationMethod) switch { - (null, not null) => ShapeMemberNames.LinearCollection.GetManagedValuesSource, - (not null, null) => ShapeMemberNames.LinearCollection.GetNativeValuesDestination, - (null, null) => $"{ShapeMemberNames.LinearCollection.GetManagedValuesSource}{MissingMemberNames.Delimiter}{ShapeMemberNames.LinearCollection.GetNativeValuesDestination}", + (null, not null) => ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource, + (not null, null) => ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination, + (null, null) => $"{ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource}{MissingMemberNames.Delimiter}{ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination}", (not null, not null) => string.Empty }; context.ReportDiagnostic( @@ -692,9 +692,9 @@ public void AnalyzeMarshallerType(SymbolAnalysisContext context) { var missingMembers = (getNativeValuesSourceMethod, getManagedValuesDestinationMethod) switch { - (not null, null) => ShapeMemberNames.LinearCollection.GetNativeValuesSource, - (null, not null) => ShapeMemberNames.LinearCollection.GetManagedValuesDestination, - (null, null) => $"{ShapeMemberNames.LinearCollection.GetNativeValuesSource}{MissingMemberNames.Delimiter}{ShapeMemberNames.LinearCollection.GetManagedValuesDestination}", + (not null, null) => ShapeMemberNames_V1.LinearCollection.GetNativeValuesSource, + (null, not null) => ShapeMemberNames_V1.LinearCollection.GetManagedValuesDestination, + (null, null) => $"{ShapeMemberNames_V1.LinearCollection.GetNativeValuesSource}{MissingMemberNames.Delimiter}{ShapeMemberNames_V1.LinearCollection.GetManagedValuesDestination}", (not null, not null) => string.Empty }; context.ReportDiagnostic( @@ -736,18 +736,18 @@ public void AnalyzeMarshallerType(SymbolAnalysisContext context) marshallerType.ToDisplayString())); } - if (marshallerData.Features.HasFlag(CustomTypeMarshallerFeatures.UnmanagedResources) && !ManualTypeMarshallingHelper.HasFreeNativeMethod(marshallerType)) + if (marshallerData.Features.HasFlag(CustomTypeMarshallerFeatures.UnmanagedResources) && !ManualTypeMarshallingHelper_V1.HasFreeNativeMethod(marshallerType)) { context.ReportDiagnostic( marshallerType.CreateDiagnostic( UnmanagedResourcesRequiresFreeNativeRule, ImmutableDictionary.Empty.Add( MissingMemberNames.Key, - ShapeMemberNames.Value.FreeNative), + ShapeMemberNames_V1.Value.FreeNative), marshallerType.ToDisplayString(), type.ToDisplayString())); } - else if (!marshallerData.Features.HasFlag(CustomTypeMarshallerFeatures.UnmanagedResources) && ManualTypeMarshallingHelper.HasFreeNativeMethod(marshallerType)) + else if (!marshallerData.Features.HasFlag(CustomTypeMarshallerFeatures.UnmanagedResources) && ManualTypeMarshallingHelper_V1.HasFreeNativeMethod(marshallerType)) { context.ReportDiagnostic( marshallerType.CreateDiagnostic( @@ -758,8 +758,8 @@ public void AnalyzeMarshallerType(SymbolAnalysisContext context) marshallerType.ToDisplayString())); } - IMethodSymbol? toNativeValueMethod = ManualTypeMarshallingHelper.FindToNativeValueMethod(marshallerType); - IMethodSymbol? fromNativeValueMethod = ManualTypeMarshallingHelper.FindFromNativeValueMethod(marshallerType); + IMethodSymbol? toNativeValueMethod = ManualTypeMarshallingHelper_V1.FindToNativeValueMethod(marshallerType); + IMethodSymbol? fromNativeValueMethod = ManualTypeMarshallingHelper_V1.FindFromNativeValueMethod(marshallerType); bool toNativeValueMethodIsRefReturn = toNativeValueMethod is { ReturnsByRef: true } or { ReturnsByRefReadonly: true }; ITypeSymbol nativeType = marshallerType; @@ -771,7 +771,7 @@ public void AnalyzeMarshallerType(SymbolAnalysisContext context) InTwoStageMarshallingRequiresToNativeValueRule, ImmutableDictionary.Empty.Add( MissingMemberNames.Key, - ShapeMemberNames.Value.ToNativeValue), + ShapeMemberNames_V1.Value.ToNativeValue), marshallerType.ToDisplayString())); } if (marshallerData.Direction.HasFlag(CustomTypeMarshallerDirection.Out) && fromNativeValueMethod is null) @@ -780,7 +780,7 @@ public void AnalyzeMarshallerType(SymbolAnalysisContext context) OutTwoStageMarshallingRequiresFromNativeValueRule, ImmutableDictionary.Empty.Add( MissingMemberNames.Key, - ShapeMemberNames.Value.FromNativeValue), + ShapeMemberNames_V1.Value.FromNativeValue), marshallerType.ToDisplayString())); } diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerFixer.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerFixer.cs index 7a349d5c6329c6..084acbe9d0255e 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerFixer.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerFixer.cs @@ -214,7 +214,7 @@ private static SyntaxNode AddMissingFeatures(string attributeName, AttributeData SyntaxNode featureAttributeArgument = gen.AttributeArgument("Features", gen.GetEnumValueAsFlagsExpression( - customTypeMarshallerAttribute.AttributeClass.GetMembers(ManualTypeMarshallingHelper.CustomMarshallerAttributeFields.Features).OfType().First().Type, + customTypeMarshallerAttribute.AttributeClass.GetMembers(ManualTypeMarshallingHelper_V1.CustomMarshallerAttributeFields.Features).OfType().First().Type, (int)newFeaturesValue, includeZeroValueFlags: false)); @@ -251,12 +251,12 @@ private static SyntaxNode AddMissingMembers(SyntaxNode node, ITypeSymbol SyntaxNode updatedDeclaration = node; - (_, ITypeSymbol managedType, _) = ManualTypeMarshallingHelper.GetMarshallerShapeInfo(marshallerType); + (_, ITypeSymbol managedType, _) = ManualTypeMarshallingHelper_V1.GetMarshallerShapeInfo(marshallerType); - IMethodSymbol? fromNativeValueMethod = ManualTypeMarshallingHelper.FindFromNativeValueMethod(marshallerType); - IMethodSymbol? toNativeValueMethod = ManualTypeMarshallingHelper.FindToNativeValueMethod(marshallerType); - IMethodSymbol? getManagedValuesSourceMethod = ManualTypeMarshallingHelper.FindGetManagedValuesSourceMethod(marshallerType, readOnlySpanOfT); - IMethodSymbol? getManagedValuesDestinationMethod = ManualTypeMarshallingHelper.FindGetManagedValuesDestinationMethod(marshallerType, spanOfT); + IMethodSymbol? fromNativeValueMethod = ManualTypeMarshallingHelper_V1.FindFromNativeValueMethod(marshallerType); + IMethodSymbol? toNativeValueMethod = ManualTypeMarshallingHelper_V1.FindToNativeValueMethod(marshallerType); + IMethodSymbol? getManagedValuesSourceMethod = ManualTypeMarshallingHelper_V1.FindGetManagedValuesSourceMethod(marshallerType, readOnlySpanOfT); + IMethodSymbol? getManagedValuesDestinationMethod = ManualTypeMarshallingHelper_V1.FindGetManagedValuesDestinationMethod(marshallerType, spanOfT); SyntaxNode[] throwNotImplementedStatements = new[] { @@ -321,21 +321,21 @@ private static SyntaxNode AddMissingMembers(SyntaxNode node, ITypeSymbol accessibility: Accessibility.Public, statements: throwNotImplementedStatements)); break; - case ShapeMemberNames.Value.ToManaged: + case ShapeMemberNames_V1.Value.ToManaged: updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration( - ShapeMemberNames.Value.ToManaged, + ShapeMemberNames_V1.Value.ToManaged, returnType: gen.TypeExpression(managedType), accessibility: Accessibility.Public, statements: throwNotImplementedStatements)); break; - case ShapeMemberNames.Value.FreeNative: - updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration(ShapeMemberNames.Value.FreeNative, + case ShapeMemberNames_V1.Value.FreeNative: + updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration(ShapeMemberNames_V1.Value.FreeNative, accessibility: Accessibility.Public, statements: throwNotImplementedStatements)); break; - case ShapeMemberNames.Value.FromNativeValue: + case ShapeMemberNames_V1.Value.FromNativeValue: updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration( - ShapeMemberNames.Value.FromNativeValue, + ShapeMemberNames_V1.Value.FromNativeValue, parameters: new[] { gen.ParameterDeclaration("value", @@ -344,33 +344,33 @@ private static SyntaxNode AddMissingMembers(SyntaxNode node, ITypeSymbol accessibility: Accessibility.Public, statements: throwNotImplementedStatements)); break; - case ShapeMemberNames.Value.ToNativeValue: + case ShapeMemberNames_V1.Value.ToNativeValue: updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration( - ShapeMemberNames.Value.ToNativeValue, + ShapeMemberNames_V1.Value.ToNativeValue, returnType: gen.TypeExpression(fromNativeValueMethod?.Parameters[0].Type ?? @byte), accessibility: Accessibility.Public, statements: throwNotImplementedStatements)); break; - case ShapeMemberNames.LinearCollection.GetManagedValuesSource: + case ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource: INamedTypeSymbol? getManagedValuesDestinationReturnType = (INamedTypeSymbol?)getManagedValuesDestinationMethod?.ReturnType; updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration( - ShapeMemberNames.LinearCollection.GetManagedValuesSource, + ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource, returnType: gen.TypeExpression( readOnlySpanOfT.Construct( getManagedValuesDestinationReturnType?.TypeArguments[0] ?? @object)), accessibility: Accessibility.Public, statements: throwNotImplementedStatements)); break; - case ShapeMemberNames.LinearCollection.GetNativeValuesDestination: + case ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination: updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration( - ShapeMemberNames.LinearCollection.GetNativeValuesDestination, + ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination, returnType: gen.TypeExpression(spanOfByte), accessibility: Accessibility.Public, statements: throwNotImplementedStatements)); break; - case ShapeMemberNames.LinearCollection.GetNativeValuesSource: + case ShapeMemberNames_V1.LinearCollection.GetNativeValuesSource: updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration( - ShapeMemberNames.LinearCollection.GetNativeValuesSource, + ShapeMemberNames_V1.LinearCollection.GetNativeValuesSource, parameters: new[] { gen.ParameterDeclaration("numElements", type: gen.TypeExpression(int32)) @@ -379,10 +379,10 @@ private static SyntaxNode AddMissingMembers(SyntaxNode node, ITypeSymbol accessibility: Accessibility.Public, statements: throwNotImplementedStatements)); break; - case ShapeMemberNames.LinearCollection.GetManagedValuesDestination: + case ShapeMemberNames_V1.LinearCollection.GetManagedValuesDestination: INamedTypeSymbol? getManagedValuesSourceReturnType = (INamedTypeSymbol?)getManagedValuesSourceMethod?.ReturnType; updatedDeclaration = gen.AddMembers(updatedDeclaration, gen.MethodDeclaration( - ShapeMemberNames.LinearCollection.GetNativeValuesDestination, + ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination, parameters: new[] { gen.ParameterDeclaration("numElements", type: gen.TypeExpression(int32)) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.V1.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.V1.cs new file mode 100644 index 00000000000000..83e02fa4e3e58b --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.V1.cs @@ -0,0 +1,227 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis; + +namespace Microsoft.Interop +{ + public readonly record struct CustomTypeMarshallerData_V1(CustomTypeMarshallerKind Kind, CustomTypeMarshallerDirection Direction, CustomTypeMarshallerFeatures Features, int? BufferSize); + + public static class ShapeMemberNames_V1 + { + public abstract class Value + { + public const string ToNativeValue = nameof(ToNativeValue); + public const string FromNativeValue = nameof(FromNativeValue); + public const string GetPinnableReference = nameof(GetPinnableReference); + public const string FreeNative = nameof(FreeNative); + public const string ToManaged = nameof(ToManaged); + } + + public abstract class LinearCollection : Value + { + public const string GetManagedValuesDestination = nameof(GetManagedValuesDestination); + public const string GetManagedValuesSource = nameof(GetManagedValuesSource); + public const string GetNativeValuesDestination = nameof(GetNativeValuesDestination); + public const string GetNativeValuesSource = nameof(GetNativeValuesSource); + } + } + public static class ManualTypeMarshallingHelper_V1 + { + public static class CustomMarshallerAttributeFields + { + public const string BufferSize = nameof(BufferSize); + public const string Direction = nameof(Direction); + public const string Features = nameof(Features); + } + + public static (bool hasAttribute, ITypeSymbol? managedType, CustomTypeMarshallerData_V1? kind) GetMarshallerShapeInfo(ITypeSymbol marshallerType) + { + var attr = marshallerType.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.ToDisplayString() == TypeNames.CustomTypeMarshallerAttribute); + if (attr is null) + { + return (false, null, null); + } + if (attr.ConstructorArguments.Length == 0) + { + return (true, null, null); + } + CustomTypeMarshallerKind kind = CustomTypeMarshallerKind.Value; + ITypeSymbol? managedType = attr.ConstructorArguments[0].Value as ITypeSymbol; + if (attr.ConstructorArguments.Length > 1) + { + if (attr.ConstructorArguments[1].Value is not int i) + { + return (true, managedType, null); + } + kind = (CustomTypeMarshallerKind)i; + } + var namedArguments = attr.NamedArguments.ToImmutableDictionary(); + int? bufferSize = namedArguments.TryGetValue(CustomMarshallerAttributeFields.BufferSize, out TypedConstant bufferSizeConstant) ? bufferSizeConstant.Value as int? : null; + CustomTypeMarshallerDirection direction = namedArguments.TryGetValue(CustomMarshallerAttributeFields.Direction, out TypedConstant directionConstant) ? (CustomTypeMarshallerDirection)directionConstant.Value : CustomTypeMarshallerDirection.Ref; + CustomTypeMarshallerFeatures features = namedArguments.TryGetValue(CustomMarshallerAttributeFields.Features, out TypedConstant featuresConstant) ? (CustomTypeMarshallerFeatures)featuresConstant.Value : CustomTypeMarshallerFeatures.None; + return (true, managedType, new CustomTypeMarshallerData_V1(kind, direction, features, bufferSize)); + } + + /// + /// Get the supported for a marshaller type + /// + /// The marshaller type. + /// The mananged type that would be marshalled. + /// Supported + public static CustomTypeMarshallerPinning GetMarshallerPinningFeatures(ITypeSymbol marshallerType, ITypeSymbol? managedType) + { + CustomTypeMarshallerPinning pinning = CustomTypeMarshallerPinning.None; + + if (ManualTypeMarshallingHelper.FindGetPinnableReference(marshallerType) is not null) + { + pinning |= CustomTypeMarshallerPinning.NativeType; + } + + if (managedType is not null && ManualTypeMarshallingHelper.FindGetPinnableReference(managedType) is not null) + { + pinning |= CustomTypeMarshallerPinning.ManagedType; + } + + return pinning; + } + + public static bool HasToManagedMethod(ITypeSymbol nativeType, ITypeSymbol managedType) + { + return nativeType.GetMembers(ShapeMemberNames_V1.Value.ToManaged) + .OfType() + .Any(m => m.Parameters.IsEmpty + && !m.ReturnsByRef + && !m.ReturnsByRefReadonly + && SymbolEqualityComparer.Default.Equals(m.ReturnType, managedType) + && !m.IsStatic); + } + + public static bool IsManagedToNativeConstructor( + IMethodSymbol ctor, + ITypeSymbol managedType, + CustomTypeMarshallerKind variant) + { + if (variant == CustomTypeMarshallerKind.LinearCollection) + { + return ctor.Parameters.Length == 2 + && SymbolEqualityComparer.Default.Equals(managedType, ctor.Parameters[0].Type) + && ctor.Parameters[1].Type.SpecialType == SpecialType.System_Int32; + } + return ctor.Parameters.Length == 1 + && SymbolEqualityComparer.Default.Equals(managedType, ctor.Parameters[0].Type); + } + + public static bool IsCallerAllocatedSpanConstructor( + IMethodSymbol ctor, + ITypeSymbol managedType, + ITypeSymbol spanOfT, + CustomTypeMarshallerKind variant, + out ITypeSymbol? spanElementType) + { + spanElementType = null; + if (variant == CustomTypeMarshallerKind.LinearCollection) + { + return ctor.Parameters.Length == 3 + && SymbolEqualityComparer.Default.Equals(managedType, ctor.Parameters[0].Type) + && IsSpanOfUnmanagedType(ctor.Parameters[1].Type, spanOfT, out spanElementType) + && spanElementType.SpecialType == SpecialType.System_Byte + && ctor.Parameters[2].Type.SpecialType == SpecialType.System_Int32; + } + return ctor.Parameters.Length == 2 + && SymbolEqualityComparer.Default.Equals(managedType, ctor.Parameters[0].Type) + && IsSpanOfUnmanagedType(ctor.Parameters[1].Type, spanOfT, out spanElementType); + + static bool IsSpanOfUnmanagedType(ITypeSymbol typeToCheck, ITypeSymbol spanOfT, out ITypeSymbol? typeArgument) + { + typeArgument = null; + if (typeToCheck is INamedTypeSymbol namedType + && SymbolEqualityComparer.Default.Equals(spanOfT, namedType.ConstructedFrom) + && namedType.TypeArguments.Length == 1 + && namedType.TypeArguments[0].IsUnmanagedType) + { + typeArgument = namedType.TypeArguments[0]; + return true; + } + + return false; + } + } + + public static bool HasFreeNativeMethod(ITypeSymbol type) + { + return type.GetMembers(ShapeMemberNames_V1.Value.FreeNative) + .OfType() + .Any(m => m is { IsStatic: false, Parameters.Length: 0, ReturnType.SpecialType: SpecialType.System_Void }); + } + + public static IMethodSymbol? FindToNativeValueMethod(ITypeSymbol type) + { + return type.GetMembers(ShapeMemberNames_V1.Value.ToNativeValue) + .OfType() + .FirstOrDefault(m => m is { IsStatic: false, Parameters.Length: 0 }); + } + + public static IMethodSymbol? FindFromNativeValueMethod(ITypeSymbol type) + { + return type.GetMembers(ShapeMemberNames_V1.Value.FromNativeValue) + .OfType() + .FirstOrDefault(m => m is { IsStatic: false, Parameters.Length: 1, ReturnType.SpecialType: SpecialType.System_Void }); + } + + public static bool TryGetElementTypeFromLinearCollectionMarshaller(ITypeSymbol type, ITypeSymbol readOnlySpanOfT, out ITypeSymbol elementType) + { + if (FindGetManagedValuesSourceMethod(type, readOnlySpanOfT) is not IMethodSymbol managedValuesSourceMethod) + { + elementType = null!; + return false; + } + + elementType = ((INamedTypeSymbol)managedValuesSourceMethod.ReturnType).TypeArguments[0]; + return true; + } + + public static IMethodSymbol? FindGetManagedValuesSourceMethod(ITypeSymbol type, ITypeSymbol readOnlySpanOfT) + { + return type + .GetMembers(ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource) + .OfType() + .FirstOrDefault(m => m is { IsStatic: false, ReturnsByRef: false, ReturnsByRefReadonly: false, Parameters.Length: 0, ReturnType: INamedTypeSymbol { ConstructedFrom: INamedTypeSymbol returnType } } + && SymbolEqualityComparer.Default.Equals(returnType, readOnlySpanOfT)); + } + + public static IMethodSymbol? FindGetManagedValuesDestinationMethod(ITypeSymbol type, ITypeSymbol spanOfT) + { + return type + .GetMembers(ShapeMemberNames_V1.LinearCollection.GetManagedValuesDestination) + .OfType() + .FirstOrDefault(m => m is { IsStatic: false, ReturnsByRef: false, ReturnsByRefReadonly: false, Parameters.Length: 1, ReturnType: INamedTypeSymbol { ConstructedFrom: INamedTypeSymbol returnType } } + && m.Parameters[0].Type.SpecialType == SpecialType.System_Int32 + && SymbolEqualityComparer.Default.Equals(returnType, spanOfT)); + } + + public static IMethodSymbol? FindGetNativeValuesDestinationMethod(ITypeSymbol type, ITypeSymbol spanOfByte) + { + return type + .GetMembers(ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination) + .OfType() + .FirstOrDefault(m => m is { IsStatic: false, ReturnsByRef: false, ReturnsByRefReadonly: false, Parameters.Length: 0, ReturnType: INamedTypeSymbol returnType } + && SymbolEqualityComparer.Default.Equals(returnType, spanOfByte)); + } + + public static IMethodSymbol? FindGetNativeValuesSourceMethod(ITypeSymbol type, ITypeSymbol readOnlySpanOfByte) + { + return type + .GetMembers(ShapeMemberNames_V1.LinearCollection.GetNativeValuesSource) + .OfType() + .FirstOrDefault(m => m is { IsStatic: false, ReturnsByRef: false, ReturnsByRefReadonly: false, Parameters.Length: 1, ReturnType: INamedTypeSymbol returnType } + && m.Parameters[0].Type.SpecialType == SpecialType.System_Int32 + && SymbolEqualityComparer.Default.Equals(returnType, readOnlySpanOfByte)); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs index 24887b880ed88f..426bada70d29b0 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs @@ -10,36 +10,50 @@ namespace Microsoft.Interop { - public readonly record struct CustomTypeMarshallerData(CustomTypeMarshallerKind Kind, CustomTypeMarshallerDirection Direction, CustomTypeMarshallerFeatures Features, int? BufferSize); + public readonly record struct CustomTypeMarshallerData( + ManagedTypeInfo MarshallerType, + ManagedTypeInfo NativeType, + CustomTypeMarshallerFeatures Features, + bool IsStrictlyBlittable, + ManagedTypeInfo? BufferElementType, + int? BufferSize); + + public readonly record struct CustomTypeMarshallers(CustomTypeMarshallerData? In, CustomTypeMarshallerData? Ref, CustomTypeMarshallerData? Out); public static class ShapeMemberNames { + public const string GetPinnableReference = nameof(GetPinnableReference); + public abstract class Value { - public const string ToNativeValue = nameof(ToNativeValue); - public const string FromNativeValue = nameof(FromNativeValue); - public const string GetPinnableReference = nameof(GetPinnableReference); - public const string FreeNative = nameof(FreeNative); - public const string ToManaged = nameof(ToManaged); + public abstract class Stateless + { + public const string ConvertToManaged = nameof(ConvertToManaged); + public const string ConvertToUnmanaged = nameof(ConvertToUnmanaged); + public const string Free = nameof(Free); + } } - public abstract class LinearCollection : Value + public abstract class LinearCollection { - public const string GetManagedValuesDestination = nameof(GetManagedValuesDestination); - public const string GetManagedValuesSource = nameof(GetManagedValuesSource); - public const string GetNativeValuesDestination = nameof(GetNativeValuesDestination); - public const string GetNativeValuesSource = nameof(GetNativeValuesSource); + public abstract class Stateless + { + // Managed to unmanaged + public const string AllocateContainerForUnmanagedElements = nameof(AllocateContainerForUnmanagedElements); + public const string GetManagedValuesSource = nameof(GetManagedValuesSource); + public const string GetUnmanagedValuesDestination = nameof(GetUnmanagedValuesDestination); + + // Unmanaged to managed + public const string AllocateContainerForManagedElements = nameof(AllocateContainerForManagedElements); + public const string GetManagedValuesDestination = nameof(GetManagedValuesDestination); + public const string GetUnmanagedValuesSource = nameof(GetUnmanagedValuesSource); + + public const string Free = nameof(Free); + } } } public static class ManualTypeMarshallingHelper { - public static class CustomMarshallerAttributeFields - { - public const string BufferSize = nameof(BufferSize); - public const string Direction = nameof(Direction); - public const string Features = nameof(Features); - } - public static class MarshalUsingProperties { public const string ElementIndirectionDepth = nameof(ElementIndirectionDepth); @@ -47,55 +61,67 @@ public static class MarshalUsingProperties public const string ConstantElementCount = nameof(ConstantElementCount); } - public static (bool hasAttribute, ITypeSymbol? managedType, CustomTypeMarshallerData? kind) GetMarshallerShapeInfo(ITypeSymbol marshallerType) + internal static class MarshallersProperties { - var attr = marshallerType.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.ToDisplayString() == TypeNames.CustomTypeMarshallerAttribute); - if (attr is null) - { - return (false, null, null); - } - if (attr.ConstructorArguments.Length == 0) - { - return (true, null, null); - } - CustomTypeMarshallerKind kind = CustomTypeMarshallerKind.Value; - ITypeSymbol? managedType = attr.ConstructorArguments[0].Value as ITypeSymbol; - if (attr.ConstructorArguments.Length > 1) - { - if (attr.ConstructorArguments[1].Value is not int i) - { - return (true, managedType, null); - } - kind = (CustomTypeMarshallerKind)i; - } - var namedArguments = attr.NamedArguments.ToImmutableDictionary(); - int? bufferSize = namedArguments.TryGetValue(CustomMarshallerAttributeFields.BufferSize, out TypedConstant bufferSizeConstant) ? bufferSizeConstant.Value as int? : null; - CustomTypeMarshallerDirection direction = namedArguments.TryGetValue(CustomMarshallerAttributeFields.Direction, out TypedConstant directionConstant) ? (CustomTypeMarshallerDirection)directionConstant.Value : CustomTypeMarshallerDirection.Ref; - CustomTypeMarshallerFeatures features = namedArguments.TryGetValue(CustomMarshallerAttributeFields.Features, out TypedConstant featuresConstant) ? (CustomTypeMarshallerFeatures)featuresConstant.Value : CustomTypeMarshallerFeatures.None; - return (true, managedType, new CustomTypeMarshallerData(kind, direction, features, bufferSize)); + public const string InMarshaller = nameof(InMarshaller); + public const string RefMarshaller = nameof(RefMarshaller); + public const string OutMarshaller = nameof(OutMarshaller); } - /// - /// Get the supported for a marshaller type - /// - /// The marshaller type. - /// The mananged type that would be marshalled. - /// Supported - public static CustomTypeMarshallerPinning GetMarshallerPinningFeatures(ITypeSymbol marshallerType, ITypeSymbol? managedType) + [Flags] + private enum MarshallingDirection { - CustomTypeMarshallerPinning pinning = CustomTypeMarshallerPinning.None; + ManagedToUnmanaged = 0x1, + UnmanagedToManaged = 0x2, + Bidirectional = ManagedToUnmanaged | UnmanagedToManaged + } - if (FindGetPinnableReference(marshallerType) is not null) - { - pinning |= CustomTypeMarshallerPinning.NativeType; - } + public static bool IsLinearCollectionEntryPoint(ITypeSymbol entryPointType) + { + // TODO: Check for linear collection marshaller - ElementUnmanagedType attribute on last generic parameter + return false; + } + + public static bool TryGetMarshallers(ITypeSymbol entryPointType, ITypeSymbol managedType, bool isLinearCollectionMarshalling, out CustomTypeMarshallers? marshallers) + { + marshallers = null; + var attr = entryPointType.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.ToDisplayString() == TypeNames.ManagedToUnmanagedMarshallersAttribute); + if (attr is null || attr.ConstructorArguments.Length == 0) + return false; - if (managedType is not null && FindGetPinnableReference(managedType) is not null) + ITypeSymbol? managedTypeOnAttr = attr.ConstructorArguments[0].Value as ITypeSymbol; + + var namedArguments = attr.NamedArguments.ToImmutableDictionary(); + CustomTypeMarshallerData? inMarshaller = GetNamedArgumentAsMarshallerData(namedArguments, MarshallersProperties.InMarshaller, MarshallingDirection.ManagedToUnmanaged); + if (inMarshaller is null) + inMarshaller = GetMarshallerDataForType(entryPointType, MarshallingDirection.ManagedToUnmanaged); + + CustomTypeMarshallerData? refMarshaller = GetNamedArgumentAsMarshallerData(namedArguments, MarshallersProperties.RefMarshaller, MarshallingDirection.Bidirectional); + if (refMarshaller is null) + refMarshaller = GetMarshallerDataForType(entryPointType, MarshallingDirection.Bidirectional); + + CustomTypeMarshallerData? outMarshaller = GetNamedArgumentAsMarshallerData(namedArguments, MarshallersProperties.OutMarshaller, MarshallingDirection.UnmanagedToManaged); + if (outMarshaller is null) + outMarshaller = GetMarshallerDataForType(entryPointType, MarshallingDirection.UnmanagedToManaged); + + if (inMarshaller is null && refMarshaller is null && outMarshaller is null) + return false; + + marshallers = new CustomTypeMarshallers() { - pinning |= CustomTypeMarshallerPinning.ManagedType; - } + In = inMarshaller, + Ref = refMarshaller, + Out = outMarshaller, + }; - return pinning; + return true; + } + + public static bool HasStatelessFree(ITypeSymbol type) + { + return type.GetMembers(ShapeMemberNames.Value.Stateless.Free) + .OfType() + .Any(m => m is { IsStatic: true, Parameters.Length: 1, ReturnsVoid: true }); } /// @@ -188,149 +214,80 @@ public static (AttributeData? attribute, INamedTypeSymbol? marshallerType) GetDe return (attr, marshallerType); } - public static bool HasToManagedMethod(ITypeSymbol nativeType, ITypeSymbol managedType) - { - return nativeType.GetMembers(ShapeMemberNames.Value.ToManaged) - .OfType() - .Any(m => m.Parameters.IsEmpty - && !m.ReturnsByRef - && !m.ReturnsByRefReadonly - && SymbolEqualityComparer.Default.Equals(m.ReturnType, managedType) - && !m.IsStatic); - } - - public static bool IsManagedToNativeConstructor( - IMethodSymbol ctor, - ITypeSymbol managedType, - CustomTypeMarshallerKind variant) - { - if (variant == CustomTypeMarshallerKind.LinearCollection) - { - return ctor.Parameters.Length == 2 - && SymbolEqualityComparer.Default.Equals(managedType, ctor.Parameters[0].Type) - && ctor.Parameters[1].Type.SpecialType == SpecialType.System_Int32; - } - return ctor.Parameters.Length == 1 - && SymbolEqualityComparer.Default.Equals(managedType, ctor.Parameters[0].Type); - } - - public static bool IsCallerAllocatedSpanConstructor( - IMethodSymbol ctor, - ITypeSymbol managedType, - ITypeSymbol spanOfT, - CustomTypeMarshallerKind variant, - out ITypeSymbol? spanElementType) - { - spanElementType = null; - if (variant == CustomTypeMarshallerKind.LinearCollection) - { - return ctor.Parameters.Length == 3 - && SymbolEqualityComparer.Default.Equals(managedType, ctor.Parameters[0].Type) - && IsSpanOfUnmanagedType(ctor.Parameters[1].Type, spanOfT, out spanElementType) - && spanElementType.SpecialType == SpecialType.System_Byte - && ctor.Parameters[2].Type.SpecialType == SpecialType.System_Int32; - } - return ctor.Parameters.Length == 2 - && SymbolEqualityComparer.Default.Equals(managedType, ctor.Parameters[0].Type) - && IsSpanOfUnmanagedType(ctor.Parameters[1].Type, spanOfT, out spanElementType); - - static bool IsSpanOfUnmanagedType(ITypeSymbol typeToCheck, ITypeSymbol spanOfT, out ITypeSymbol? typeArgument) - { - typeArgument = null; - if (typeToCheck is INamedTypeSymbol namedType - && SymbolEqualityComparer.Default.Equals(spanOfT, namedType.ConstructedFrom) - && namedType.TypeArguments.Length == 1 - && namedType.TypeArguments[0].IsUnmanagedType) - { - typeArgument = namedType.TypeArguments[0]; - return true; - } - - return false; - } - } - public static IMethodSymbol? FindGetPinnableReference(ITypeSymbol type) { // Lookup a GetPinnableReference method based on the spec for the pattern-based // fixed statement. We aren't supporting a GetPinnableReference extension method // (which is apparently supported in the compiler). // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-7.3/pattern-based-fixed - return type.GetMembers(ShapeMemberNames.Value.GetPinnableReference) + return type.GetMembers(ShapeMemberNames.GetPinnableReference) .OfType() .FirstOrDefault(m => m is { Parameters.Length: 0 } and ({ ReturnsByRef: true } or { ReturnsByRefReadonly: true })); } - public static bool HasFreeNativeMethod(ITypeSymbol type) + private static CustomTypeMarshallerData? GetNamedArgumentAsMarshallerData(ImmutableDictionary namedArguments, string name, MarshallingDirection direction) { - return type.GetMembers(ShapeMemberNames.Value.FreeNative) - .OfType() - .Any(m => m is { IsStatic: false, Parameters.Length: 0, ReturnType.SpecialType: SpecialType.System_Void }); - } + ITypeSymbol? marshallerType = namedArguments.TryGetValue(name, out TypedConstant typeMaybe) ? typeMaybe.Value as ITypeSymbol : null; + if (marshallerType is null) + return null; - public static IMethodSymbol? FindToNativeValueMethod(ITypeSymbol type) - { - return type.GetMembers(ShapeMemberNames.Value.ToNativeValue) - .OfType() - .FirstOrDefault(m => m is { IsStatic: false, Parameters.Length: 0 }); + // TODO: Report invalid shape + return GetMarshallerDataForType(marshallerType, direction); } - public static IMethodSymbol? FindFromNativeValueMethod(ITypeSymbol type) + private static CustomTypeMarshallerData? GetMarshallerDataForType(ITypeSymbol marshallerType, MarshallingDirection direction) { - return type.GetMembers(ShapeMemberNames.Value.FromNativeValue) - .OfType() - .FirstOrDefault(m => m is { IsStatic: false, Parameters.Length: 1, ReturnType.SpecialType: SpecialType.System_Void }); - } - - public static bool TryGetElementTypeFromLinearCollectionMarshaller(ITypeSymbol type, ITypeSymbol readOnlySpanOfT, out ITypeSymbol elementType) - { - if (FindGetManagedValuesSourceMethod(type, readOnlySpanOfT) is not IMethodSymbol managedValuesSourceMethod) + ITypeSymbol? nativeType = null; + if (direction.HasFlag(MarshallingDirection.ManagedToUnmanaged)) { - elementType = null!; - return false; + // Make sure required method exists + IMethodSymbol? method = GetConvertToUnmanagedMethod(marshallerType); + if (method is null) + return null; + + nativeType = method.ReturnType; } - elementType = ((INamedTypeSymbol)managedValuesSourceMethod.ReturnType).TypeArguments[0]; - return true; - } + if (direction.HasFlag(MarshallingDirection.UnmanagedToManaged)) + { + // Make sure required method exists + IMethodSymbol? method = GetConvertToManagedMethod(marshallerType); + if (method is null) + return null; - public static IMethodSymbol? FindGetManagedValuesSourceMethod(ITypeSymbol type, ITypeSymbol readOnlySpanOfT) - { - return type - .GetMembers(ShapeMemberNames.LinearCollection.GetManagedValuesSource) - .OfType() - .FirstOrDefault(m => m is { IsStatic: false, ReturnsByRef: false, ReturnsByRefReadonly: false, Parameters.Length: 0, ReturnType: INamedTypeSymbol { ConstructedFrom: INamedTypeSymbol returnType } } - && SymbolEqualityComparer.Default.Equals(returnType, readOnlySpanOfT)); - } + nativeType = method.Parameters[0].Type; + } - public static IMethodSymbol? FindGetManagedValuesDestinationMethod(ITypeSymbol type, ITypeSymbol spanOfT) - { - return type - .GetMembers(ShapeMemberNames.LinearCollection.GetManagedValuesDestination) - .OfType() - .FirstOrDefault(m => m is { IsStatic: false, ReturnsByRef: false, ReturnsByRefReadonly: false, Parameters.Length: 1, ReturnType: INamedTypeSymbol { ConstructedFrom: INamedTypeSymbol returnType } } - && m.Parameters[0].Type.SpecialType == SpecialType.System_Int32 - && SymbolEqualityComparer.Default.Equals(returnType, spanOfT)); + if (nativeType is null) + return null; + + var features = CustomTypeMarshallerFeatures.None; + if (HasStatelessFree(marshallerType)) + features |= CustomTypeMarshallerFeatures.UnmanagedResources; + + // TODO: Determine optional support - caller-allocated buffer, pinning, free + return new CustomTypeMarshallerData( + ManagedTypeInfo.CreateTypeInfoForTypeSymbol(marshallerType), + ManagedTypeInfo.CreateTypeInfoForTypeSymbol(nativeType), + features, + nativeType.IsStrictlyBlittable(), + BufferElementType: null, + BufferSize: null); } - public static IMethodSymbol? FindGetNativeValuesDestinationMethod(ITypeSymbol type, ITypeSymbol spanOfByte) + private static IMethodSymbol? GetConvertToUnmanagedMethod(ITypeSymbol type) { - return type - .GetMembers(ShapeMemberNames.LinearCollection.GetNativeValuesDestination) + return type.GetMembers(ShapeMemberNames.Value.Stateless.ConvertToUnmanaged) .OfType() - .FirstOrDefault(m => m is { IsStatic: false, ReturnsByRef: false, ReturnsByRefReadonly: false, Parameters.Length: 0, ReturnType: INamedTypeSymbol returnType } - && SymbolEqualityComparer.Default.Equals(returnType, spanOfByte)); + .FirstOrDefault(m => m is { IsStatic: true, Parameters.Length: 1, ReturnsVoid: false }); } - public static IMethodSymbol? FindGetNativeValuesSourceMethod(ITypeSymbol type, ITypeSymbol readOnlySpanOfByte) + private static IMethodSymbol? GetConvertToManagedMethod(ITypeSymbol type) { - return type - .GetMembers(ShapeMemberNames.LinearCollection.GetNativeValuesSource) + return type.GetMembers(ShapeMemberNames.Value.Stateless.ConvertToManaged) .OfType() - .FirstOrDefault(m => m is { IsStatic: false, ReturnsByRef: false, ReturnsByRefReadonly: false, Parameters.Length: 1, ReturnType: INamedTypeSymbol returnType } - && m.Parameters[0].Type.SpecialType == SpecialType.System_Int32 - && SymbolEqualityComparer.Default.Equals(returnType, readOnlySpanOfByte)); + .FirstOrDefault(m => m is { IsStatic: true, Parameters.Length: 1, ReturnsVoid: false }); } } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ArrayMarshaller.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ArrayMarshaller.cs index b436ae134f4e0c..0b41be2390e9d4 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ArrayMarshaller.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ArrayMarshaller.cs @@ -72,7 +72,7 @@ public bool SupportsByValueMarshalKind(ByValueContentsMarshalKind marshalKind, S // the status remains the same regardless of whether or not runtime marshalling is enabled if (_elementInfo.MarshallingAttributeInfo is NoMarshallingInfo || _elementInfo.MarshallingAttributeInfo is UnmanagedBlittableMarshallingInfo { IsStrictlyBlittable: true } - || _elementInfo.MarshallingAttributeInfo is NativeMarshallingAttributeInfo { IsStrictlyBlittable: true }) + || _elementInfo.MarshallingAttributeInfo is NativeMarshallingAttributeInfo_V1 { IsStrictlyBlittable: true }) { return false; } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs index 80afc1731f0c94..597ba7c967b6b0 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs @@ -52,20 +52,25 @@ public IMarshallingGenerator Create(TypePositionInfo info, StubCodeContext conte { if (info.MarshallingAttributeInfo is NativeMarshallingAttributeInfo marshalInfo) { - if (Options.RuntimeMarshallingDisabled || marshalInfo.IsStrictlyBlittable) + return CreateCustomNativeTypeMarshaller(info, context, marshalInfo); + } + + if (info.MarshallingAttributeInfo is NativeMarshallingAttributeInfo_V1 marshalInfoV1) + { + if (Options.RuntimeMarshallingDisabled || marshalInfoV1.IsStrictlyBlittable) { - return CreateCustomNativeTypeMarshaller(info, context, marshalInfo); + return CreateCustomNativeTypeMarshaller_V1(info, context, marshalInfoV1); } - if (marshalInfo.NativeValueType is SpecialTypeInfo specialType + if (marshalInfoV1.NativeValueType is SpecialTypeInfo specialType && specialType.SpecialType.IsAlwaysBlittable()) { - return CreateCustomNativeTypeMarshaller(info, context, marshalInfo); + return CreateCustomNativeTypeMarshaller_V1(info, context, marshalInfoV1); } - if (marshalInfo.NativeValueType is PointerTypeInfo) + if (marshalInfoV1.NativeValueType is PointerTypeInfo) { - return CreateCustomNativeTypeMarshaller(info, context, marshalInfo); + return CreateCustomNativeTypeMarshaller_V1(info, context, marshalInfoV1); } throw new MarshallingNotSupportedException(info, context) @@ -129,7 +134,7 @@ ExpressionSyntax GetExpressionForParam(TypePositionInfo paramInfo) for (int i = 0; i < numIndirectionLevels; i++) { - if (marshallingInfo is NativeLinearCollectionMarshallingInfo collectionInfo) + if (marshallingInfo is NativeLinearCollectionMarshallingInfo_V1 collectionInfo) { type = collectionInfo.ElementType; marshallingInfo = collectionInfo.ElementMarshallingInfo; @@ -187,10 +192,106 @@ static ExpressionSyntax GetIndexedNumElementsExpression(StubCodeContext context, } } + private bool ValidateRuntimeMarshallingOptions(CustomTypeMarshallerData marshallerData) + { + if (Options.RuntimeMarshallingDisabled || marshallerData.IsStrictlyBlittable) + return true; + + if (marshallerData.NativeType is SpecialTypeInfo specialType && specialType.SpecialType.IsAlwaysBlittable()) + return true; + + if (marshallerData.NativeType is PointerTypeInfo) + return true; + + return false; + } + private IMarshallingGenerator CreateCustomNativeTypeMarshaller(TypePositionInfo info, StubCodeContext context, NativeMarshallingAttributeInfo marshalInfo) { ValidateCustomNativeTypeMarshallingSupported(info, context, marshalInfo); + CustomTypeMarshallerData marshallerData; + if (info.IsManagedReturnPosition) + { + marshallerData = marshalInfo.ManagedToUnmanagedMarshallers.Out.Value; + } + else + { + marshallerData = info.RefKind switch + { + RefKind.None or RefKind.In => marshalInfo.ManagedToUnmanagedMarshallers.In.Value, + RefKind.Ref => marshalInfo.ManagedToUnmanagedMarshallers.Ref.Value, + RefKind.Out => marshalInfo.ManagedToUnmanagedMarshallers.Out.Value, + _ => throw new MarshallingNotSupportedException(info, context) + }; + } + + if (!ValidateRuntimeMarshallingOptions(marshallerData)) + { + throw new MarshallingNotSupportedException(info, context) + { + NotSupportedDetails = SR.RuntimeMarshallingMustBeDisabled, + DiagnosticProperties = AddDisableRuntimeMarshallingAttributeProperties + }; + } + + ICustomTypeMarshallingStrategy marshallingStrategy = new StatelessValueMarshalling(marshallerData.MarshallerType.Syntax, marshallerData.NativeType.Syntax, marshallerData.Features); + + IMarshallingGenerator marshallingGenerator = new CustomNativeTypeMarshallingGenerator(marshallingStrategy, enableByValueContentsMarshalling: false); + + return marshalInfo.IsPinnableManagedType + ? new PinnableManagedValueMarshaller(marshallingGenerator) + : marshallingGenerator; + } + + private static void ValidateCustomNativeTypeMarshallingSupported(TypePositionInfo info, StubCodeContext context, NativeMarshallingAttributeInfo marshalInfo) + { + // Marshalling out or return parameter, but no out marshaller is specified + if ((info.RefKind == RefKind.Out || info.IsManagedReturnPosition) + && !marshalInfo.ManagedToUnmanagedMarshallers.Out.HasValue) + { + throw new MarshallingNotSupportedException(info, context) + { + NotSupportedDetails = string.Format(SR.UnmanagedToManagedMissingRequiredMarshaller, ManualTypeMarshallingHelper.MarshallersProperties.OutMarshaller, marshalInfo.EntryPointType.FullTypeName) + }; + } + + // Marshalling ref parameter, but no ref marshaller is specified + if (info.RefKind == RefKind.Ref && !marshalInfo.ManagedToUnmanagedMarshallers.Ref.HasValue) + { + throw new MarshallingNotSupportedException(info, context) + { + NotSupportedDetails = string.Format(SR.BidirectionalMissingRequiredMarshaller, ManualTypeMarshallingHelper.MarshallersProperties.RefMarshaller, marshalInfo.EntryPointType.FullTypeName) + }; + } + + // Marshalling in parameter, but no in marshaller is specified + if (info.RefKind == RefKind.In + && !marshalInfo.ManagedToUnmanagedMarshallers.In.HasValue) + { + throw new MarshallingNotSupportedException(info, context) + { + NotSupportedDetails = string.Format(SR.ManagedToUnmanagedMissingRequiredMarshaller, ManualTypeMarshallingHelper.MarshallersProperties.InMarshaller, marshalInfo.EntryPointType.FullTypeName) + }; + } + + // Marshalling by value, but no in marshaller is specified + if (!info.IsByRef + && !info.IsManagedReturnPosition + && context.SingleFrameSpansNativeContext + && !(marshalInfo.IsPinnableManagedType || marshalInfo.ManagedToUnmanagedMarshallers.In.HasValue)) + { + throw new MarshallingNotSupportedException(info, context) + { + NotSupportedDetails = string.Format(SR.ManagedToUnmanagedMissingRequiredMarshaller, ManualTypeMarshallingHelper.MarshallersProperties.InMarshaller, marshalInfo.EntryPointType.FullTypeName) + }; + } + } + + private IMarshallingGenerator CreateCustomNativeTypeMarshaller_V1(TypePositionInfo info, StubCodeContext context, NativeMarshallingAttributeInfo_V1 marshalInfo) + { + ValidateCustomNativeTypeMarshallingSupported_V1(info, context, marshalInfo); + ICustomNativeTypeMarshallingStrategy marshallingStrategy = new SimpleCustomNativeTypeMarshalling(marshalInfo.NativeMarshallingType.Syntax); if ((marshalInfo.MarshallingFeatures & CustomTypeMarshallerFeatures.CallerAllocatedBuffer) != 0) @@ -208,7 +309,7 @@ private IMarshallingGenerator CreateCustomNativeTypeMarshaller(TypePositionInfo } // Collections have extra configuration, so handle them here. - if (marshalInfo is NativeLinearCollectionMarshallingInfo collectionMarshallingInfo) + if (marshalInfo is NativeLinearCollectionMarshallingInfo_V1 collectionMarshallingInfo) { return CreateNativeCollectionMarshaller(info, context, collectionMarshallingInfo, marshallingStrategy); } @@ -231,7 +332,7 @@ private IMarshallingGenerator CreateCustomNativeTypeMarshaller(TypePositionInfo return marshallingGenerator; } - private static void ValidateCustomNativeTypeMarshallingSupported(TypePositionInfo info, StubCodeContext context, NativeMarshallingAttributeInfo marshalInfo) + private static void ValidateCustomNativeTypeMarshallingSupported_V1(TypePositionInfo info, StubCodeContext context, NativeMarshallingAttributeInfo_V1 marshalInfo) { // The marshalling method for this type doesn't support marshalling from native to managed, // but our scenario requires marshalling from native to managed. @@ -289,7 +390,7 @@ private static void ValidateCustomNativeTypeMarshallingSupported(TypePositionInf private IMarshallingGenerator CreateNativeCollectionMarshaller( TypePositionInfo info, StubCodeContext context, - NativeLinearCollectionMarshallingInfo collectionInfo, + NativeLinearCollectionMarshallingInfo_V1 collectionInfo, ICustomNativeTypeMarshallingStrategy marshallingStrategy) { var elementInfo = new TypePositionInfo(collectionInfo.ElementType, collectionInfo.ElementMarshallingInfo) { ManagedIndex = info.ManagedIndex }; diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CustomNativeTypeMarshallingGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CustomNativeTypeMarshallingGenerator.cs index de758a34d23e0b..d420a1647086ef 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CustomNativeTypeMarshallingGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CustomNativeTypeMarshallingGenerator.cs @@ -14,10 +14,10 @@ namespace Microsoft.Interop /// internal sealed class CustomNativeTypeMarshallingGenerator : IMarshallingGenerator { - private readonly ICustomNativeTypeMarshallingStrategy _nativeTypeMarshaller; + private readonly ICustomTypeMarshallingStrategy _nativeTypeMarshaller; private readonly bool _enableByValueContentsMarshalling; - public CustomNativeTypeMarshallingGenerator(ICustomNativeTypeMarshallingStrategy nativeTypeMarshaller, bool enableByValueContentsMarshalling) + public CustomNativeTypeMarshallingGenerator(ICustomTypeMarshallingStrategy nativeTypeMarshaller, bool enableByValueContentsMarshalling) { _nativeTypeMarshaller = nativeTypeMarshaller; _enableByValueContentsMarshalling = enableByValueContentsMarshalling; diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomNativeTypeMarshallingStrategy.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomNativeTypeMarshallingStrategy.cs index 0d89208515d78f..9ce1336be558bf 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomNativeTypeMarshallingStrategy.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomNativeTypeMarshallingStrategy.cs @@ -11,31 +11,7 @@ namespace Microsoft.Interop { - /// - /// The base interface for implementing various different aspects of the custom native type and collection marshalling specs. - /// - internal interface ICustomNativeTypeMarshallingStrategy - { - TypeSyntax AsNativeType(TypePositionInfo info); - - IEnumerable GetNativeTypeConstructorArguments(TypePositionInfo info, StubCodeContext context); - - IEnumerable GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context, IEnumerable nativeTypeConstructorArguments); - - IEnumerable GeneratePinnedMarshalStatements(TypePositionInfo info, StubCodeContext context); - - IEnumerable GenerateSetupStatements(TypePositionInfo info, StubCodeContext context); - - IEnumerable GenerateCleanupStatements(TypePositionInfo info, StubCodeContext context); - - IEnumerable GeneratePinStatements(TypePositionInfo info, StubCodeContext context); - - IEnumerable GenerateUnmarshalCaptureStatements(TypePositionInfo info, StubCodeContext context); - - IEnumerable GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context); - - bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context); - } + internal interface ICustomNativeTypeMarshallingStrategy : ICustomTypeMarshallingStrategy { } /// /// Marshalling support for a type that has a custom native type. @@ -98,7 +74,7 @@ public IEnumerable GenerateUnmarshalStatements(TypePositionInfo InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames.Value.ToManaged))))); + IdentifierName(ShapeMemberNames_V1.Value.ToManaged))))); } public IEnumerable GenerateUnmarshalCaptureStatements(TypePositionInfo info, StubCodeContext context) @@ -214,7 +190,7 @@ public IEnumerable GeneratePinnedMarshalStatements(TypePosition InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(subContext.GetIdentifiers(info).native), - IdentifierName(ShapeMemberNames.Value.ToNativeValue)), + IdentifierName(ShapeMemberNames_V1.Value.ToNativeValue)), ArgumentList()))); } @@ -225,7 +201,7 @@ private static StatementSyntax GenerateFromNativeValueInvocation(TypePositionInf InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(subContext.GetIdentifiers(info).native), - IdentifierName(ShapeMemberNames.Value.FromNativeValue)), + IdentifierName(ShapeMemberNames_V1.Value.FromNativeValue)), ArgumentList(SingletonSeparatedList(Argument(IdentifierName(context.GetIdentifiers(info).native)))))); } @@ -421,7 +397,7 @@ public IEnumerable GenerateCleanupStatements(TypePositionInfo i InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(context.GetIdentifiers(info).native), - IdentifierName(ShapeMemberNames.Value.FreeNative)))); + IdentifierName(ShapeMemberNames_V1.Value.FreeNative)))); } public IEnumerable GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context, IEnumerable nativeTypeConstructorArguments) @@ -692,7 +668,7 @@ public IEnumerable GenerateMarshalStatements(TypePositionInfo i MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames.LinearCollection.GetNativeValuesDestination)), + IdentifierName(ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination)), ArgumentList()), IdentifierName("Clear")))); yield break; @@ -707,7 +683,7 @@ public IEnumerable GenerateMarshalStatements(TypePositionInfo i MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames.LinearCollection.GetManagedValuesSource)), + IdentifierName(ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource)), ArgumentList()), IdentifierName("CopyTo"))) .AddArgumentListArguments( @@ -732,7 +708,7 @@ public IEnumerable GenerateMarshalStatements(TypePositionInfo i MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames.LinearCollection.GetNativeValuesDestination)), + IdentifierName(ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination)), ArgumentList())))))); } @@ -770,7 +746,7 @@ public IEnumerable GenerateUnmarshalStatements(TypePositionInfo MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames.LinearCollection.GetNativeValuesDestination))); + IdentifierName(ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination))); // MemoryMarshal.CreateSpan(ref MemoryMarshal.GetReference(.GetManagedValuesSource()), .GetManagedValuesSource().Length) copyDestination = InvocationExpression( @@ -791,7 +767,7 @@ public IEnumerable GenerateUnmarshalStatements(TypePositionInfo InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames.LinearCollection.GetManagedValuesSource)))))))) + IdentifierName(ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource)))))))) .WithRefKindKeyword( Token(SyntaxKind.RefKeyword)), Argument( @@ -799,7 +775,7 @@ public IEnumerable GenerateUnmarshalStatements(TypePositionInfo InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames.LinearCollection.GetManagedValuesSource))), + IdentifierName(ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource))), IdentifierName("Length"))) }))); @@ -817,7 +793,7 @@ public IEnumerable GenerateUnmarshalStatements(TypePositionInfo MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames.LinearCollection.GetNativeValuesSource)), + IdentifierName(ShapeMemberNames_V1.LinearCollection.GetNativeValuesSource)), ArgumentList(SingletonSeparatedList(Argument(IdentifierName(numElementsIdentifier))))); // .GetManagedValuesDestination() @@ -825,7 +801,7 @@ public IEnumerable GenerateUnmarshalStatements(TypePositionInfo MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames.LinearCollection.GetManagedValuesDestination)), + IdentifierName(ShapeMemberNames_V1.LinearCollection.GetManagedValuesDestination)), ArgumentList(SingletonSeparatedList(Argument(IdentifierName(numElementsIdentifier))))); } @@ -924,7 +900,7 @@ private LocalDeclarationStatementSyntax GenerateNativeValuesDestinationDeclarati InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames.LinearCollection.GetNativeValuesDestination)), + IdentifierName(ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination)), ArgumentList())))))))); } @@ -960,7 +936,7 @@ private LocalDeclarationStatementSyntax GenerateNativeValuesSourceDeclaration(Ty InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames.LinearCollection.GetNativeValuesSource)), + IdentifierName(ShapeMemberNames_V1.LinearCollection.GetNativeValuesSource)), ArgumentList(SingletonSeparatedList(Argument(IdentifierName(numElementsIdentifier)))))))))))); } @@ -980,7 +956,7 @@ private LocalDeclarationStatementSyntax GeneratedManagedValuesSourceDeclaration( InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames.LinearCollection.GetManagedValuesSource)), + IdentifierName(ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource)), ArgumentList())))))); } @@ -1000,7 +976,7 @@ private LocalDeclarationStatementSyntax GeneratedManagedValuesDestinationDeclara InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames.LinearCollection.GetManagedValuesDestination)), + IdentifierName(ShapeMemberNames_V1.LinearCollection.GetManagedValuesDestination)), ArgumentList(SingletonSeparatedList(Argument(IdentifierName(numElementsIdentifier)))))))))); } @@ -1096,7 +1072,7 @@ public IEnumerable GenerateMarshalStatements(TypePositionInfo i MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames.LinearCollection.GetNativeValuesDestination)), + IdentifierName(ShapeMemberNames_V1.LinearCollection.GetNativeValuesDestination)), ArgumentList()), IdentifierName("Clear")))); yield break; @@ -1156,7 +1132,7 @@ private StatementSyntax GenerateByValueUnmarshalStatement(TypePositionInfo info, InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames.LinearCollection.GetManagedValuesSource)), + IdentifierName(ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource)), ArgumentList()), IdentifierName("Length"))))))); @@ -1192,7 +1168,7 @@ private StatementSyntax GenerateByValueUnmarshalStatement(TypePositionInfo info, InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(nativeIdentifier), - IdentifierName(ShapeMemberNames.LinearCollection.GetManagedValuesSource)), + IdentifierName(ShapeMemberNames_V1.LinearCollection.GetManagedValuesSource)), ArgumentList()), IdentifierName("GetPinnableReference")), ArgumentList())) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomTypeMarshallingStrategy.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomTypeMarshallingStrategy.cs new file mode 100644 index 00000000000000..ce559b7d2ca2b2 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomTypeMarshallingStrategy.cs @@ -0,0 +1,135 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace Microsoft.Interop +{ + /// + /// The base interface for implementing various aspects of the custom native type and collection marshalling specs. + /// + internal interface ICustomTypeMarshallingStrategy + { + TypeSyntax AsNativeType(TypePositionInfo info); + + IEnumerable GetNativeTypeConstructorArguments(TypePositionInfo info, StubCodeContext context); + + IEnumerable GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context, IEnumerable nativeTypeConstructorArguments); + + IEnumerable GeneratePinnedMarshalStatements(TypePositionInfo info, StubCodeContext context); + + IEnumerable GenerateSetupStatements(TypePositionInfo info, StubCodeContext context); + + IEnumerable GenerateCleanupStatements(TypePositionInfo info, StubCodeContext context); + + IEnumerable GeneratePinStatements(TypePositionInfo info, StubCodeContext context); + + IEnumerable GenerateUnmarshalCaptureStatements(TypePositionInfo info, StubCodeContext context); + + IEnumerable GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context); + + bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context); + } + + /// + /// Stateless marshalling support for a type that has a custom unmanaged type. + /// + internal sealed class StatelessValueMarshalling : ICustomTypeMarshallingStrategy + { + private readonly TypeSyntax _marshallerTypeSyntax; + private readonly TypeSyntax _nativeTypeSyntax; + private readonly CustomTypeMarshallerFeatures _features; + + public StatelessValueMarshalling(TypeSyntax marshallerTypeSyntax, TypeSyntax nativeTypeSyntax, CustomTypeMarshallerFeatures features) + { + _marshallerTypeSyntax = marshallerTypeSyntax; + _nativeTypeSyntax = nativeTypeSyntax; + _features = features; + } + + public TypeSyntax AsNativeType(TypePositionInfo info) + { + return _nativeTypeSyntax; + } + + public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) => true; + + public IEnumerable GenerateCleanupStatements(TypePositionInfo info, StubCodeContext context) + { + if (!_features.HasFlag(CustomTypeMarshallerFeatures.UnmanagedResources)) + yield break; + + // = .ConvertToManaged(); + yield return ExpressionStatement( + InvocationExpression( + MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, + _marshallerTypeSyntax, + IdentifierName(ShapeMemberNames.Value.Stateless.Free)), + ArgumentList(SingletonSeparatedList( + Argument(IdentifierName(context.GetIdentifiers(info).native)))))); + } + + public IEnumerable GenerateMarshalStatements(TypePositionInfo info, StubCodeContext context, IEnumerable nativeTypeConstructorArguments) + { + (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info); + + // = .ConvertToUnmanaged(); + yield return ExpressionStatement( + AssignmentExpression( + SyntaxKind.SimpleAssignmentExpression, + IdentifierName(nativeIdentifier), + InvocationExpression( + MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, + _marshallerTypeSyntax, + IdentifierName(ShapeMemberNames.Value.Stateless.ConvertToUnmanaged)), + ArgumentList(SingletonSeparatedList( + Argument(IdentifierName(managedIdentifier))))))); + } + + public IEnumerable GeneratePinnedMarshalStatements(TypePositionInfo info, StubCodeContext context) + { + return Array.Empty(); + } + + public IEnumerable GenerateUnmarshalStatements(TypePositionInfo info, StubCodeContext context) + { + (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info); + + // = .ConvertToManaged(); + yield return ExpressionStatement( + AssignmentExpression( + SyntaxKind.SimpleAssignmentExpression, + IdentifierName(managedIdentifier), + InvocationExpression( + MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, + _marshallerTypeSyntax, + IdentifierName(ShapeMemberNames.Value.Stateless.ConvertToManaged)), + ArgumentList(SingletonSeparatedList( + Argument(IdentifierName(nativeIdentifier))))))); + } + + public IEnumerable GenerateUnmarshalCaptureStatements(TypePositionInfo info, StubCodeContext context) + { + return Array.Empty(); + } + + public IEnumerable GetNativeTypeConstructorArguments(TypePositionInfo info, StubCodeContext context) + { + return Array.Empty(); + } + + public IEnumerable GenerateSetupStatements(TypePositionInfo info, StubCodeContext context) + { + return Array.Empty(); + } + + public IEnumerable GeneratePinStatements(TypePositionInfo info, StubCodeContext context) + { + return Array.Empty(); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallerHelpers.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallerHelpers.cs index 3730ba0b779302..7bf836506a9118 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallerHelpers.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallerHelpers.cs @@ -261,7 +261,7 @@ public bool AnyIncomingEdge(int to) public static IEnumerable GetDependentElementsOfMarshallingInfo( MarshallingInfo elementMarshallingInfo) { - if (elementMarshallingInfo is NativeLinearCollectionMarshallingInfo nestedCollection) + if (elementMarshallingInfo is NativeLinearCollectionMarshallingInfo_V1 nestedCollection) { if (nestedCollection.ElementCountInfo is CountElementCountInfo { ElementInfo: TypePositionInfo nestedCountElement }) { diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGeneratorExtensions.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGeneratorExtensions.cs index e07e8baaf616b0..ffba0c05600f9e 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGeneratorExtensions.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGeneratorExtensions.cs @@ -117,7 +117,7 @@ private static bool TryRehydrateMarshalAsAttribute(TypePositionInfo info, out At { CountInfo countInfo; MarshallingInfo elementMarshallingInfo; - if (info.MarshallingAttributeInfo is NativeLinearCollectionMarshallingInfo collectionMarshalling + if (info.MarshallingAttributeInfo is NativeLinearCollectionMarshallingInfo_V1 collectionMarshalling && collectionMarshalling.UseDefaultMarshalling && collectionMarshalling.ElementCountInfo is NoCountInfo or SizeAndParamIndexInfo && collectionMarshalling.ElementMarshallingInfo is NoMarshallingInfo or MarshalAsInfo { UnmanagedType: not UnmanagedType.CustomMarshaler } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs index 061cb4146e682d..af92671e381deb 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs @@ -138,9 +138,17 @@ public sealed record SizeAndParamIndexInfo(int ConstSize, TypePositionInfo? Para } /// - /// User-applied System.Runtime.InteropServices.NativeMarshallingAttribute + /// Custom type marshalling via MarshalUsingAttribute or NativeMarshallingAttribute /// public record NativeMarshallingAttributeInfo( + ManagedTypeInfo EntryPointType, + CustomTypeMarshallers ManagedToUnmanagedMarshallers, + bool IsPinnableManagedType) : MarshallingInfo; + + /// + /// User-applied System.Runtime.InteropServices.NativeMarshallingAttribute + /// + public record NativeMarshallingAttributeInfo_V1( ManagedTypeInfo NativeMarshallingType, ManagedTypeInfo? NativeValueType, CustomTypeMarshallerDirection Direction, @@ -160,7 +168,7 @@ public sealed record SafeHandleMarshallingInfo(bool AccessibleDefaultConstructor /// User-applied System.Runtime.InteropServices.NativeMarshallingAttribute /// with a contiguous collection marshaller /// - public sealed record NativeLinearCollectionMarshallingInfo( + public sealed record NativeLinearCollectionMarshallingInfo_V1( ManagedTypeInfo NativeMarshallingType, ManagedTypeInfo? NativeValueType, CustomTypeMarshallerDirection Direction, @@ -170,7 +178,7 @@ public sealed record NativeLinearCollectionMarshallingInfo( int? BufferSize, CountInfo ElementCountInfo, ManagedTypeInfo ElementType, - MarshallingInfo ElementMarshallingInfo) : NativeMarshallingAttributeInfo( + MarshallingInfo ElementMarshallingInfo) : NativeMarshallingAttributeInfo_V1( NativeMarshallingType, NativeValueType, Direction, @@ -565,6 +573,35 @@ private MarshallingInfo CreateInfoFromMarshalAs( } private MarshallingInfo CreateNativeMarshallingInfo( + ITypeSymbol type, + INamedTypeSymbol entryPointType, + AttributeData attrData, + bool isMarshalUsingAttribute, + int indirectionLevel, + CountInfo parsedCountInfo, + Dictionary useSiteAttributes, + ImmutableHashSet inspectedElements, + ref int maxIndirectionDepthUsed) + { + bool isLinearCollectionMarshalling = ManualTypeMarshallingHelper.IsLinearCollectionEntryPoint(entryPointType); + if (ManualTypeMarshallingHelper.TryGetMarshallers(entryPointType, type, isLinearCollectionMarshalling, out CustomTypeMarshallers? marshallers)) + { + if (!entryPointType.IsStatic) + { + _diagnostics.ReportInvalidMarshallingAttributeInfo(attrData, nameof(SR.MarshallerTypeMustBeStatic), entryPointType.ToDisplayString(), type.ToDisplayString()); + return NoMarshallingInfo.Instance; + } + + bool isPinnableManagedType = !isMarshalUsingAttribute && ManualTypeMarshallingHelper.FindGetPinnableReference(type) is not null; + return isLinearCollectionMarshalling + ? NoMarshallingInfo.Instance // TODO: handle linear collection marshallers + : new NativeMarshallingAttributeInfo(ManagedTypeInfo.CreateTypeInfoForTypeSymbol(entryPointType), marshallers.Value, isPinnableManagedType); + } + + return CreateNativeMarshallingInfo_V1(type, entryPointType, attrData, isMarshalUsingAttribute, indirectionLevel, parsedCountInfo, useSiteAttributes, inspectedElements, ref maxIndirectionDepthUsed); + } + + private MarshallingInfo CreateNativeMarshallingInfo_V1( ITypeSymbol type, INamedTypeSymbol nativeType, AttributeData attrData, @@ -601,7 +638,7 @@ private MarshallingInfo CreateNativeMarshallingInfo( } } - var (_, _, customTypeMarshallerData) = ManualTypeMarshallingHelper.GetMarshallerShapeInfo(nativeType); + var (_, _, customTypeMarshallerData) = ManualTypeMarshallingHelper_V1.GetMarshallerShapeInfo(nativeType); if (customTypeMarshallerData is null) { return NoMarshallingInfo.Instance; @@ -610,16 +647,16 @@ private MarshallingInfo CreateNativeMarshallingInfo( if (customTypeMarshallerData.Value.Kind == CustomTypeMarshallerKind.LinearCollection) { INamedTypeSymbol readOnlySpanOfT = _compilation.GetTypeByMetadataName(TypeNames.System_ReadOnlySpan_Metadata)!; - if (!ManualTypeMarshallingHelper.TryGetElementTypeFromLinearCollectionMarshaller(nativeType, readOnlySpanOfT, out ITypeSymbol elementType)) + if (!ManualTypeMarshallingHelper_V1.TryGetElementTypeFromLinearCollectionMarshaller(nativeType, readOnlySpanOfT, out ITypeSymbol elementType)) { _diagnostics.ReportInvalidMarshallingAttributeInfo(attrData, nameof(SR.CollectionNativeTypeMustHaveRequiredShapeMessage), nativeType.ToDisplayString()); return NoMarshallingInfo.Instance; } - CustomTypeMarshallerPinning pinning = ManualTypeMarshallingHelper.GetMarshallerPinningFeatures(nativeType, isMarshalUsingAttribute ? null : type); - IMethodSymbol? toNativeValueMethod = ManualTypeMarshallingHelper.FindToNativeValueMethod(nativeType); + CustomTypeMarshallerPinning pinning = ManualTypeMarshallingHelper_V1.GetMarshallerPinningFeatures(nativeType, isMarshalUsingAttribute ? null : type); + IMethodSymbol? toNativeValueMethod = ManualTypeMarshallingHelper_V1.FindToNativeValueMethod(nativeType); ManagedTypeInfo? nativeValueType = toNativeValueMethod is not null ? ManagedTypeInfo.CreateTypeInfoForTypeSymbol(toNativeValueMethod.ReturnType) : null; - return new NativeLinearCollectionMarshallingInfo( + return new NativeLinearCollectionMarshallingInfo_V1( ManagedTypeInfo.CreateTypeInfoForTypeSymbol(nativeType), nativeValueType, customTypeMarshallerData.Value.Direction, @@ -645,7 +682,7 @@ private MarshallingInfo CreateNativeMarshallingInfoForValue( ITypeSymbol type, INamedTypeSymbol nativeType, AttributeData attrData, - CustomTypeMarshallerData customTypeMarshallerData, + CustomTypeMarshallerData_V1 customTypeMarshallerData, bool allowPinningManagedType, bool useDefaultMarshalling) { @@ -656,7 +693,7 @@ private MarshallingInfo CreateNativeMarshallingInfoForValue( INamedTypeSymbol spanOfT = _compilation.GetTypeByMetadataName(TypeNames.System_Span_Metadata)!; foreach (IMethodSymbol ctor in nativeType.Constructors) { - if (ManualTypeMarshallingHelper.IsCallerAllocatedSpanConstructor(ctor, type, spanOfT, customTypeMarshallerData.Kind, out bufferElementType)) + if (ManualTypeMarshallingHelper_V1.IsCallerAllocatedSpanConstructor(ctor, type, spanOfT, customTypeMarshallerData.Kind, out bufferElementType)) break; } @@ -676,12 +713,12 @@ private MarshallingInfo CreateNativeMarshallingInfoForValue( bufferElementTypeInfo = ManagedTypeInfo.CreateTypeInfoForTypeSymbol(bufferElementType); } - CustomTypeMarshallerPinning pinning = ManualTypeMarshallingHelper.GetMarshallerPinningFeatures(nativeType, allowPinningManagedType ? type : null); + CustomTypeMarshallerPinning pinning = ManualTypeMarshallingHelper_V1.GetMarshallerPinningFeatures(nativeType, allowPinningManagedType ? type : null); - IMethodSymbol? toNativeValueMethod = ManualTypeMarshallingHelper.FindToNativeValueMethod(nativeType); + IMethodSymbol? toNativeValueMethod = ManualTypeMarshallingHelper_V1.FindToNativeValueMethod(nativeType); ManagedTypeInfo? nativeValueType = toNativeValueMethod is not null ? ManagedTypeInfo.CreateTypeInfoForTypeSymbol(toNativeValueMethod.ReturnType) : null; - return new NativeMarshallingAttributeInfo( + return new NativeMarshallingAttributeInfo_V1( ManagedTypeInfo.CreateTypeInfoForTypeSymbol(nativeType), nativeValueType, customTypeMarshallerData.Direction, @@ -817,19 +854,19 @@ private MarshallingInfo CreateArrayMarshallingInfo( return new MissingSupportCollectionMarshallingInfo(countInfo, elementMarshallingInfo); } - var (_, _, customTypeMarshallerData) = ManualTypeMarshallingHelper.GetMarshallerShapeInfo(arrayMarshaller); + var (_, _, customTypeMarshallerData) = ManualTypeMarshallingHelper_V1.GetMarshallerShapeInfo(arrayMarshaller); Debug.Assert(customTypeMarshallerData is not null); - ITypeSymbol? nativeValueType = ManualTypeMarshallingHelper.FindToNativeValueMethod(arrayMarshaller)?.ReturnType; + ITypeSymbol? nativeValueType = ManualTypeMarshallingHelper_V1.FindToNativeValueMethod(arrayMarshaller)?.ReturnType; INamedTypeSymbol readOnlySpanOfT = _compilation.GetTypeByMetadataName(TypeNames.System_ReadOnlySpan_Metadata)!; - if (!ManualTypeMarshallingHelper.TryGetElementTypeFromLinearCollectionMarshaller(arrayMarshaller, readOnlySpanOfT, out elementType)) + if (!ManualTypeMarshallingHelper_V1.TryGetElementTypeFromLinearCollectionMarshaller(arrayMarshaller, readOnlySpanOfT, out elementType)) { Debug.Fail("Runtime-provided array marshallers should have a valid shape"); return NoMarshallingInfo.Instance; } - return new NativeLinearCollectionMarshallingInfo( + return new NativeLinearCollectionMarshallingInfo_V1( NativeMarshallingType: ManagedTypeInfo.CreateTypeInfoForTypeSymbol(arrayMarshaller), NativeValueType: nativeValueType is not null ? ManagedTypeInfo.CreateTypeInfoForTypeSymbol(nativeValueType) : null, Direction: customTypeMarshallerData.Value.Direction, @@ -869,7 +906,7 @@ private MarshallingInfo CreateStringMarshallingInfo( if (stringMarshaller is null) return new MissingSupportMarshallingInfo(); - var (_, _, customTypeMarshallerData) = ManualTypeMarshallingHelper.GetMarshallerShapeInfo(stringMarshaller); + var (_, _, customTypeMarshallerData) = ManualTypeMarshallingHelper_V1.GetMarshallerShapeInfo(stringMarshaller); Debug.Assert(customTypeMarshallerData is not null); return CreateNativeMarshallingInfoForValue( diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/Strings.resx b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/Strings.resx index 8829f5479f19a2..54047927230a96 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/Strings.resx +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/Strings.resx @@ -204,4 +204,16 @@ Marshalling char with 'StringMarshalling.Custom' is not supported. To use a custom type marshaller, specify 'MarshalUsingAttribute'. - + + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + + + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + + + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + + + The marshaller type '{0}' for managed type '{1}' must be static. + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.cs.xlf b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.cs.xlf index c6fa7ec2bb54e6..6294668d6a91cd 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.cs.xlf @@ -12,6 +12,11 @@ Hodnota SizeParamIndex atributu MarshalAsAttribute je mimo rozsah. + + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + + The 'BlittableTypeAttribute' and 'NativeMarshallingAttribute' attributes are mutually exclusive. Atributy BlittableTypeAttribute a NativeMarshallingAttribute se vzájemně vylučují. @@ -92,6 +97,16 @@ Poskytnuté atributy „[In]“ a „[Out]“ u tohoto parametru se na tomto parametru nepodporují. + + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + + + + The marshaller type '{0}' for managed type '{1}' must be static. + The marshaller type '{0}' for managed type '{1}' must be static. + + Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'. Logická hodnota zařazování bez výslovných informací zařazování se nepodporuje. Určete buď MarshalUsingAttribute nebo MarshalAsAttribute. @@ -142,6 +157,11 @@ Určený typ nepodporují zdrojem generovaná volání P/Invokes. + + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + + The type '{0}' specifies that it supports 'In' marshalling with the 'CallerAllocatedBuffer' feature for '{1}' but does not provide a one-parameter constructor that takes a '{1}' and 'Span' of an 'unmanaged' type as parameters Typ {0} určuje, že podporuje zařazování In s funkcí CallerAllocatedBuffer pro {1}, ale neposkytuje jednoparametrový konstruktor, který přebírá {1} a Span jako parametry. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.de.xlf b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.de.xlf index e50f992e52cb79..512f6fa16d2fdb 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.de.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.de.xlf @@ -12,6 +12,11 @@ Der Wert \"SizeParamIndex\" im MarshalAsAttribute liegt außerhalb des gültigen Bereichs. + + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + + The 'BlittableTypeAttribute' and 'NativeMarshallingAttribute' attributes are mutually exclusive. Die Attribute \"BlittableTypeAttribute\" und \"NativeMarshallingAttribute\" schließen sich gegenseitig aus. @@ -92,6 +97,16 @@ Die angegebenen Attribute \"[In]\" und \"[Out]\" für diesen Parameter werden für diesen Parameter nicht unterstützt. + + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + + + + The marshaller type '{0}' for managed type '{1}' must be static. + The marshaller type '{0}' for managed type '{1}' must be static. + + Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'. Marshalling eines booleschen Werts ohne explizite Marshallinginformationen wird nicht unterstützt. Geben Sie entweder \"MarshalUsingAttribute\" oder \"MarshalAsAttribute\" an. @@ -142,6 +157,11 @@ Der angegebene Typ wird von quellgenerierten P/Invokes nicht unterstützt. + + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + + The type '{0}' specifies that it supports 'In' marshalling with the 'CallerAllocatedBuffer' feature for '{1}' but does not provide a one-parameter constructor that takes a '{1}' and 'Span' of an 'unmanaged' type as parameters Der Typ „{0}“ gibt an, dass er das „In“-Marshalling mit dem Feature „CallerAllocatedBuffer“ für „{1}“ unterstützt, stellt jedoch keinen Konstruktor mit einem Parameter bereit, der „{1}“ und „Span“ als Parameter akzeptiert. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.es.xlf b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.es.xlf index 1673287744e674..de23d9ff47ef44 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.es.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.es.xlf @@ -12,6 +12,11 @@ El valor “SizeParamIndex” de “MarshalAsAttribute” está fuera de rango. + + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + + The 'BlittableTypeAttribute' and 'NativeMarshallingAttribute' attributes are mutually exclusive. Los atributos “BlittableTypeAttribute” y “NativeMarshallingAttribute” son mutuamente excluyentes. @@ -92,6 +97,16 @@ En este parámetro, los atributos “[In]” y “[Out]” proporcionados no se admiten. + + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + + + + The marshaller type '{0}' for managed type '{1}' must be static. + The marshaller type '{0}' for managed type '{1}' must be static. + + Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'. No se admite la serialización booleana sin información de serialización explícita. Especifique “MarshalUsingAttribute” o “MarshalAsAttribute”. @@ -142,6 +157,11 @@ El tipo especificado no está admitido por P/Invokes de un generador de código fuente + + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + + The type '{0}' specifies that it supports 'In' marshalling with the 'CallerAllocatedBuffer' feature for '{1}' but does not provide a one-parameter constructor that takes a '{1}' and 'Span' of an 'unmanaged' type as parameters El tipo \"{0}\" especifica que admite serializar \"In\" con la característica \"CallerAllocatedBuffer\" para \"{1}\" pero no provee un constructor de un solo parámetro que tome un \"{1}\" y un \"Span\" de un tipo \"no administrado\" como parámetros diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.fr.xlf b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.fr.xlf index 9c7dac30a9b752..d2dd018671a829 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.fr.xlf @@ -12,6 +12,11 @@ La valeur « SizeParamIndex » dans « MarshalAsAttribute » est hors limites. + + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + + The 'BlittableTypeAttribute' and 'NativeMarshallingAttribute' attributes are mutually exclusive. Les attributs « BlittableTypeAttribute » et « NativeMarstribuingAttribute » s’excluent mutuellement. @@ -92,6 +97,16 @@ Les attributs « [In] » et « [Out] » fournis sur ce paramètre ne sont pas pris en charge sur ce paramètre. + + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + + + + The marshaller type '{0}' for managed type '{1}' must be static. + The marshaller type '{0}' for managed type '{1}' must be static. + + Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'. Le marshaling bool sans informations de marshaling explicite n’est pas pris en charge. Spécifiez « MarshalUsingAttribute » ou « MarshalAsAttribute ». @@ -142,6 +157,11 @@ Le type spécifié n’est pas prise en charge par les P/Invokes générés par la source. + + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + + The type '{0}' specifies that it supports 'In' marshalling with the 'CallerAllocatedBuffer' feature for '{1}' but does not provide a one-parameter constructor that takes a '{1}' and 'Span' of an 'unmanaged' type as parameters Le type « {0} » spécifie qu’il prend en charge le marshaling «In» avec la fonctionnalité «CallerAllocatedBuffer» pour « {1} » mais ne fournit pas de constructeur à un paramètre qui accepte un « {1} » et « Span » d’un type « non géré » comme paramètres. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.it.xlf b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.it.xlf index 83ae4b4d6353b3..fe0a51e958dbab 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.it.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.it.xlf @@ -12,6 +12,11 @@ Il valore 'SizeParamIndex' in 'MarshalAsAttribute' non è compreso nell'intervallo. + + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + + The 'BlittableTypeAttribute' and 'NativeMarshallingAttribute' attributes are mutually exclusive. Gli attributi 'BlittableTypeAttribute' e 'NativeMarshallingAttribute' si escludono a vicenda. @@ -92,6 +97,16 @@ Gli attributi '[In]' e '[Out]' specificati per questo parametro non sono supportati in questo parametro. + + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + + + + The marshaller type '{0}' for managed type '{1}' must be static. + The marshaller type '{0}' for managed type '{1}' must be static. + + Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'. Il marshalling del tipo di dati bool senza informazioni di marshalling esplicito non è supportato. Specificare 'MarshalUsingAttribute' o 'MarshalAsAttribute'. @@ -142,6 +157,11 @@ Il tipo specificato non è supportato dai P/Invoke generati dall'origine + + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + + The type '{0}' specifies that it supports 'In' marshalling with the 'CallerAllocatedBuffer' feature for '{1}' but does not provide a one-parameter constructor that takes a '{1}' and 'Span' of an 'unmanaged' type as parameters Il tipo '{0}' specifica che supporta il marshalling 'In' con la funzionalità 'CallerAllocatedBuffer' per '{1}' ma non fornisce un costruttore con un solo parametro che accetta '{1}' e 'Span' di un tipo 'non gestito' come parametri diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.ja.xlf b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.ja.xlf index e9eb3e7caa23c0..8c036f4885adc3 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.ja.xlf @@ -12,6 +12,11 @@ 'MarshalAsAttribute' の 'SizeParamIndex' 値は範囲外です。 + + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + + The 'BlittableTypeAttribute' and 'NativeMarshallingAttribute' attributes are mutually exclusive. 'BlittableTypeAttribute' 属性と 'NativeMarshallingAttribute' 属性は互いに排他的です。 @@ -92,6 +97,16 @@ このパラメーターに指定された '[In]' 属性と '[Out]' 属性は、このパラメーターではサポートされていません。 + + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + + + + The marshaller type '{0}' for managed type '{1}' must be static. + The marshaller type '{0}' for managed type '{1}' must be static. + + Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'. 明示的なマーシャリング情報を含まないブール値のマーシャリングはサポートされていません。'MarshalUsingAttribute' または 'MarshalAsAttribute' のいずれかを指定してください。 @@ -142,6 +157,11 @@ 指定された型は、ソースで生成された P/Invoke ではサポートされていません + + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + + The type '{0}' specifies that it supports 'In' marshalling with the 'CallerAllocatedBuffer' feature for '{1}' but does not provide a one-parameter constructor that takes a '{1}' and 'Span' of an 'unmanaged' type as parameters 型 '{0}' は、'{1}' の 'CallerAllocatedBuffer' 機能を使用した 'In' マーシャリングをサポートすることを指定していますが、'{1}' と 'アンマネージド' 型の 'Span' をパラメーターとして受け取る、1 つのパラメーター コンストラクターを指定しません diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.ko.xlf b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.ko.xlf index e13472537d0def..8cc806f394b3fb 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.ko.xlf @@ -12,6 +12,11 @@ 'MarshalAsAttribute'의 'SizeParamIndex' 값이 범위를 벗어났습니다. + + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + + The 'BlittableTypeAttribute' and 'NativeMarshallingAttribute' attributes are mutually exclusive. 'BlittableTypeAttribute' 및 'NativeMarshallingAttribute' 특성은 상호 배타적입니다. @@ -92,6 +97,16 @@ 이 매개 변수에 제공된 '[In]' 및 '[Out]' 특성은 이 매개 변수에서 지원되지 않습니다. + + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + + + + The marshaller type '{0}' for managed type '{1}' must be static. + The marshaller type '{0}' for managed type '{1}' must be static. + + Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'. 명시적 마샬링 정보가 없는 마샬링 bool은 지원되지 않습니다. 'MarshalUsingAttribute' 또는 'MarshalAsAttribute'를 지정하세요. @@ -142,6 +157,11 @@ 지정된 형식은 소스 생성 P/Invoke에서 지원되지 않습니다. + + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + + The type '{0}' specifies that it supports 'In' marshalling with the 'CallerAllocatedBuffer' feature for '{1}' but does not provide a one-parameter constructor that takes a '{1}' and 'Span' of an 'unmanaged' type as parameters 형식 '{0}은(는) '{1}에 대한 'CallerAllocatedBuffer' 기능으로 'In' 마샬링을 지원하도록 지정하지만 '{1} 및 '관리되지 않는' 형식의 'Span'을 매개 변수로 사용하는 단일 매개 변수 생성자는 제공하지 않습니다. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.pl.xlf b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.pl.xlf index 2faf8371d9afa5..a30718a12889c6 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.pl.xlf @@ -12,6 +12,11 @@ Wartość „SizeParamIndex” w atrybucie „MarshalAsAttribute” jest poza zakresem. + + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + + The 'BlittableTypeAttribute' and 'NativeMarshallingAttribute' attributes are mutually exclusive. Atrybuty „BlittableTypeAttribute” i „NativeMarshallingAttribute” wzajemnie się wykluczają. @@ -92,6 +97,16 @@ Podane atrybuty „[In]” i „[Out]” w tym parametrze nie są obsługiwane w tym parametrze. + + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + + + + The marshaller type '{0}' for managed type '{1}' must be static. + The marshaller type '{0}' for managed type '{1}' must be static. + + Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'. Skierowanie wartości logicznej bez wyraźnych informacji o skierowaniu nie jest obsługiwane. Określ atrybut „MarshalUsingAttribute” lub atrybut „MarshalAsAttribute”. @@ -142,6 +157,11 @@ Określony typ nie jest obsługiwany przez funkcję P/Invokes generowaną przez źródło + + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + + The type '{0}' specifies that it supports 'In' marshalling with the 'CallerAllocatedBuffer' feature for '{1}' but does not provide a one-parameter constructor that takes a '{1}' and 'Span' of an 'unmanaged' type as parameters Typ „{0}” określa, że obsługuje marshalling „In” z funkcją „CallerAllocatedBuffer” dla elementu „{1}”, ale nie zapewnia konstruktora z jednym parametrem, który przyjmuje element „{1}” i wartości „Span” typu „unmanaged” jako parametry diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.pt-BR.xlf index d9d5cd95539141..45478b851ef7a7 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.pt-BR.xlf @@ -12,6 +12,11 @@ O valor 'SizeParamIndex' em 'MarshalAsAttribute' está fora do intervalo. + + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + + The 'BlittableTypeAttribute' and 'NativeMarshallingAttribute' attributes are mutually exclusive. Os atributos 'BlittableTypeAttribute' e 'NativeMarshallingAttribute' são mutuamente exclusivos. @@ -92,6 +97,16 @@ Os atributos '[In]' e '[Out]' neste parâmetro não têm suporte neste parâmetro. + + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + + + + The marshaller type '{0}' for managed type '{1}' must be static. + The marshaller type '{0}' for managed type '{1}' must be static. + + Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'. Não há suporte para marshalling bool sem informações de marshalling explícitas. Especifique 'MarshalUsingAttribute' ou 'MarshalAsAttribute'. @@ -142,6 +157,11 @@ O tipo especificado não tem suporte de P/Invokes gerados pela origem. + + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + + The type '{0}' specifies that it supports 'In' marshalling with the 'CallerAllocatedBuffer' feature for '{1}' but does not provide a one-parameter constructor that takes a '{1}' and 'Span' of an 'unmanaged' type as parameters O tipo '{0}' especifica que ele dá suporte ao marshalling 'In' com o recurso 'CallerAllocatedBuffer' para '{1}', mas não fornece um construtor de um parâmetro que usa um '{1}' e 'Span' de um tipo 'não gerenciado' como parâmetros diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.ru.xlf b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.ru.xlf index 051d18db7e954b..22bb9193053a1f 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.ru.xlf @@ -12,6 +12,11 @@ Значение \"SizeParamIndex\" в \"MarshalAsAttribute\" выходит за пределы допустимого диапазона. + + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + + The 'BlittableTypeAttribute' and 'NativeMarshallingAttribute' attributes are mutually exclusive. Атрибуты \"BlittableTypeAttribute\" и \"NativeMarshallingAttribute\" взаимоисключающие. @@ -92,6 +97,16 @@ Указанные атрибуты \"[In]\" и \"[Out]\" для этого параметра не поддерживаются. + + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + + + + The marshaller type '{0}' for managed type '{1}' must be static. + The marshaller type '{0}' for managed type '{1}' must be static. + + Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'. Маршализация типа bool объекта без явного указания сведений маршализации не поддерживается. Укажите \"MarshalUsingAttribute\" или \"MarshalAsAttribute\". @@ -142,6 +157,11 @@ Указанный тип не поддерживается в P/Invoke с созданием источника. + + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + + The type '{0}' specifies that it supports 'In' marshalling with the 'CallerAllocatedBuffer' feature for '{1}' but does not provide a one-parameter constructor that takes a '{1}' and 'Span' of an 'unmanaged' type as parameters Тип \"{0}\" указывает, что поддерживает маршализацию в направлении \"внутрь\" с функцией \"CallerAllocatedBuffer\" для \"{1}\", но не предоставляет конструктор, принимающий два параметра: \"{1}\" и \"Span неуправляемого типа\" diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.tr.xlf b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.tr.xlf index 8e584c09036713..c76a08b00fc601 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.tr.xlf @@ -12,6 +12,11 @@ 'MarshalAsAttribute' öğesindeki 'SizeParamIndex' değeri aralık dışında. + + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + + The 'BlittableTypeAttribute' and 'NativeMarshallingAttribute' attributes are mutually exclusive. 'BlittableTypeAttribute' ve 'NativeMarshallingAttribute' öznitelikleri birlikte kullanılamazlar. @@ -92,6 +97,16 @@ Bu parametrede sağlanan '[In]' ve '[Out]' öznitelikleri bu parametrede desteklenmiyor. + + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + + + + The marshaller type '{0}' for managed type '{1}' must be static. + The marshaller type '{0}' for managed type '{1}' must be static. + + Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'. Açık sıralama bilgileri olmadan bool sıralama desteklenmiyor. 'MarshalUsingAttribute' veya 'MarshalAsAttribute' bilgilerini belirtin. @@ -142,6 +157,11 @@ Belirtilen tür, kaynak tarafından oluşturulan P/Invokes tarafından desteklenmiyor + + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + + The type '{0}' specifies that it supports 'In' marshalling with the 'CallerAllocatedBuffer' feature for '{1}' but does not provide a one-parameter constructor that takes a '{1}' and 'Span' of an 'unmanaged' type as parameters '{0}' türünde '{1}' için 'CallerAllocatedBuffer' özelliğiyle 'In' sıralamasının desteklendiği belirtiliyor, ancak parametre olarak '{1}' ve 'unmanaged' türünün 'Span' değerlerini alan tek parametreli bir oluşturucu sağlanmıyor diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.zh-Hans.xlf index 28a81e437e3654..0a7c97117aa249 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.zh-Hans.xlf @@ -12,6 +12,11 @@ “MarshalAsAttribute” 中的 “SizeParamIndex” 值超出范围。 + + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + + The 'BlittableTypeAttribute' and 'NativeMarshallingAttribute' attributes are mutually exclusive. “BlittableTypeAttribute” 和 “NativeMarshallingAttribute” 属性是相互排斥的。 @@ -92,6 +97,16 @@ 此参数上提供的 “[In]” 和 “[Out]” 属性在此参数上不受支持。 + + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + + + + The marshaller type '{0}' for managed type '{1}' must be static. + The marshaller type '{0}' for managed type '{1}' must be static. + + Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'. 不支持在没有显式封送信息的情况下封送布尔值。请指定 “MarshalUsingAttribute” 或 “MarshalAsAttribute”。 @@ -142,6 +157,11 @@ 源生成的 P/Invoke 不支持指定的类型 + + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + + The type '{0}' specifies that it supports 'In' marshalling with the 'CallerAllocatedBuffer' feature for '{1}' but does not provide a one-parameter constructor that takes a '{1}' and 'Span' of an 'unmanaged' type as parameters 类型 \"{0}\" 指定它支持使用 \"CallerAllocatedBuffer\" 功能对 \"{1}\" 进行 \"In\" 封送,但不提供以 \"{1}\" 和“非管理”类型的 \"Span\" 作为参数的单参数构造函数 diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.zh-Hant.xlf index 1da1b9b3a4935d..5da5835691bce4 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Resources/xlf/Strings.zh-Hant.xlf @@ -12,6 +12,11 @@ 'MarshalAsAttribute' 中的 'SizeParamIndex' 值超出範圍。 + + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged and unmanaged to managed, but the marshaller type '{0}' does not support it. + + The 'BlittableTypeAttribute' and 'NativeMarshallingAttribute' attributes are mutually exclusive. 'BlittableTypeAttribute' 和 'NativeMarshallingAttribute' 屬性互斥。 @@ -92,6 +97,16 @@ 此參數不支援在此參數上提供的 '[In]' 和 '[Out]' 屬性。 + + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from managed to unmanaged, but the marshaller type '{0}' does not support it. + + + + The marshaller type '{0}' for managed type '{1}' must be static. + The marshaller type '{0}' for managed type '{1}' must be static. + + Marshalling bool without explicit marshalling information is not supported. Specify either 'MarshalUsingAttribute' or 'MarshalAsAttribute'. 不支援沒有明確排列資訊的封送處理布林值。指定 'MarshalUsingAttribute' 或 'MarshalAsAttribute'。 @@ -142,6 +157,11 @@ 来源產生的 P/Invokes 不支援指定的類型。 + + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + The specified parameter needs to be marshalled from unmanaged to managed, but the marshaller type '{0}' does not support it. + + The type '{0}' specifies that it supports 'In' marshalling with the 'CallerAllocatedBuffer' feature for '{1}' but does not provide a one-parameter constructor that takes a '{1}' and 'Span' of an 'unmanaged' type as parameters 類型 '{0}' 指定其支援使用 'CallerAllocatedBuffer' 功能為 '{1}' 的 'In' 封送處理,但不提供接受 '{1}' 的單一參數構建函式,以及以 'unmanaged' 類型的 'Span' 作為參數 diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs index 778c1cd2beb39a..b73f03ca140a4b 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs @@ -14,9 +14,10 @@ public static class TypeNames public const string MarshalUsingAttribute = "System.Runtime.InteropServices.Marshalling.MarshalUsingAttribute"; public const string CustomTypeMarshallerAttribute = "System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerAttribute"; - public const string CustomTypeMarshallerAttributeGenericPlaceholder = "System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerAttribute.GenericPlaceholder"; + public const string ManagedToUnmanagedMarshallersAttribute = "System.Runtime.InteropServices.Marshalling.ManagedToUnmanagedMarshallersAttribute"; + public const string AnsiStringMarshaller = "System.Runtime.InteropServices.Marshalling.AnsiStringMarshaller"; public const string BStrStringMarshaller = "System.Runtime.InteropServices.Marshalling.BStrStringMarshaller"; public const string Utf16StringMarshaller = "System.Runtime.InteropServices.Marshalling.Utf16StringMarshaller"; diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/CustomTypeMarshallersAttributeBase.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/CustomTypeMarshallersAttributeBase.cs new file mode 100644 index 00000000000000..e20f63a714678e --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/CustomTypeMarshallersAttributeBase.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Runtime.InteropServices.Marshalling +{ + /// + /// Base class attribute for custom marshaller attributes. + /// + /// + /// Use a base class here to allow doing ManagedToUnmanagedMarshallersAttribute.GenericPlaceholder, etc. without having 3 separate placeholder types. + /// For the following attribute types, any marshaller types that are provided will be validated by an analyzer to have the correct members to prevent + /// developers from accidentally typoing a member like Free() and causing memory leaks. + /// + public abstract class CustomUnmanagedTypeMarshallersAttributeBase : Attribute + { + /// + /// Placeholder type for generic parameter + /// + public struct GenericPlaceholder { } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ManagedToUnmanagedMarshallersAttribute.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ManagedToUnmanagedMarshallersAttribute.cs new file mode 100644 index 00000000000000..c0221d1530758c --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ManagedToUnmanagedMarshallersAttribute.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Runtime.InteropServices.Marshalling +{ + /// + /// Specify marshallers used in the managed to unmanaged direction (that is, P/Invoke) + /// + public sealed class ManagedToUnmanagedMarshallersAttribute : CustomUnmanagedTypeMarshallersAttributeBase + { + /// + /// Create instance of . + /// + /// Managed type to marshal + public ManagedToUnmanagedMarshallersAttribute(Type managedType) { } + + /// + /// Marshaller to use when a parameter of the managed type is passed by-value or with the in keyword. + /// + public Type? InMarshaller { get; set; } + + /// + /// Marshaller to use when a parameter of the managed type is passed by-value or with the ref keyword. + /// + public Type? RefMarshaller { get; set; } + + /// + /// Marshaller to use when a parameter of the managed type is passed by-value or with the out keyword. + /// + public Type? OutMarshaller { get; set; } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.cs index 69b85f33cfa35a..a672d1eaf61dec 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.cs @@ -74,7 +74,7 @@ public partial class Arrays [LibraryImport(NativeExportsNE_Binary, EntryPoint = "and_all_members")] [return:MarshalAs(UnmanagedType.U1)] - public static partial bool AndAllMembers(BoolStruct[] pArray, int length); + public static partial bool AndAllMembers(BoolStruct_V1[] pArray, int length); [LibraryImport(NativeExportsNE_Binary, EntryPoint = "transpose_matrix")] [return: MarshalUsing(CountElementName = "numColumns")] @@ -400,19 +400,19 @@ public void ArrayWithSimpleNonBlittableTypeMarshalling(bool result) { var boolValues = new[] { - new BoolStruct + new BoolStruct_V1 { b1 = true, b2 = true, b3 = true, }, - new BoolStruct + new BoolStruct_V1 { b1 = true, b2 = true, b3 = true, }, - new BoolStruct + new BoolStruct_V1 { b1 = true, b2 = true, diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.cs index f0c35bf2ed24b2..cf058810d434bf 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CollectionTests.cs @@ -61,7 +61,7 @@ public static partial void ReverseStrings_Out( [LibraryImport(NativeExportsNE_Binary, EntryPoint = "and_all_members")] [return: MarshalAs(UnmanagedType.U1)] - public static partial bool AndAllMembers([MarshalUsing(typeof(ListMarshaller))] List pArray, int length); + public static partial bool AndAllMembers([MarshalUsing(typeof(ListMarshaller))] List pArray, int length); } } @@ -208,21 +208,21 @@ public void ConstantSizeCollection() [InlineData(false)] public void CollectionWithSimpleNonBlittableTypeMarshalling(bool result) { - var boolValues = new List + var boolValues = new List { - new BoolStruct + new BoolStruct_V1 { b1 = true, b2 = true, b3 = true, }, - new BoolStruct + new BoolStruct_V1 { b1 = true, b2 = true, b3 = true, }, - new BoolStruct + new BoolStruct_V1 { b1 = true, b2 = true, diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.V1.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.V1.cs new file mode 100644 index 00000000000000..f3f159423933f8 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.V1.cs @@ -0,0 +1,157 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using System.Text; +using SharedTypes; + +using Xunit; + +namespace LibraryImportGenerator.IntegrationTests +{ + partial class NativeExportsNE + { + internal partial class V1 + { + [LibraryImport(NativeExportsNE_Binary, EntryPoint = "stringcontainer_deepduplicate")] + public static partial void DeepDuplicateStrings(StringContainer_V1 strings, out StringContainer_V1 pStringsOut); + + [LibraryImport(NativeExportsNE_Binary, EntryPoint = "stringcontainer_reverse_strings")] + public static partial void ReverseStrings(ref StringContainer_V1 strings); + + [LibraryImport(NativeExportsNE_Binary, EntryPoint = "get_long_bytes_as_double")] + public static partial double GetLongBytesAsDouble([MarshalUsing(typeof(DoubleToLongMarshaller_V1))] double d); + + [LibraryImport(NativeExportsNE_Binary, EntryPoint = "negate_bools")] + public static partial void NegateBools( + BoolStruct_V1 boolStruct, + out BoolStruct_V1 pBoolStructOut); + + [LibraryImport(NativeExportsNE_Binary, EntryPoint = "and_bools_ref")] + [return: MarshalAs(UnmanagedType.U1)] + public static partial bool AndBoolsRef(in BoolStruct_V1 boolStruct); + + [LibraryImport(NativeExportsNE_Binary, EntryPoint = "double_int_ref")] + public static partial IntWrapper_V1 DoubleIntRef(IntWrapper_V1 pInt); + } + } + + public class CustomMarshallingTests_V1 + { + [Fact] + public void NonBlittableStructWithFree() + { + var stringContainer = new StringContainer_V1 + { + str1 = "Foo", + str2 = "Bar" + }; + + NativeExportsNE.V1.DeepDuplicateStrings(stringContainer, out var stringContainer2); + + Assert.Equal(stringContainer, stringContainer2); + } + + [Fact] + public void MarshalUsing() + { + double d = 1234.56789; + + Assert.Equal(d, NativeExportsNE.V1.GetLongBytesAsDouble(d)); + } + + [Fact] + public void NonBlittableStructWithoutAllocation() + { + var boolStruct = new BoolStruct_V1 + { + b1 = true, + b2 = false, + b3 = true + }; + + NativeExportsNE.V1.NegateBools(boolStruct, out BoolStruct_V1 boolStructNegated); + + Assert.Equal(!boolStruct.b1, boolStructNegated.b1); + Assert.Equal(!boolStruct.b2, boolStructNegated.b2); + Assert.Equal(!boolStruct.b3, boolStructNegated.b3); + } + + [Fact] + public void GetPinnableReferenceMarshalling() + { + int originalValue = 42; + var wrapper = new IntWrapper_V1 { i = originalValue }; + + var retVal = NativeExportsNE.V1.DoubleIntRef(wrapper); + + Assert.Equal(originalValue * 2, wrapper.i); + Assert.Equal(originalValue * 2, retVal.i); + } + + [Fact] + public void NonBlittableStructRef() + { + var stringContainer = new StringContainer_V1 + { + str1 = "Foo", + str2 = "Bar" + }; + + var expected = new StringContainer_V1 + { + str1 = ReverseUTF8Bytes(stringContainer.str1), + str2 = ReverseUTF8Bytes(stringContainer.str2) + }; + + var stringContainerCopy = stringContainer; + + NativeExportsNE.V1.ReverseStrings(ref stringContainerCopy); + + Assert.Equal(expected, stringContainerCopy); + } + + [Theory] + [InlineData(true, true, true)] + [InlineData(true, true, false)] + [InlineData(true, false, true)] + [InlineData(true, false, false)] + [InlineData(false, true, true)] + [InlineData(false, true, false)] + [InlineData(false, false, true)] + [InlineData(false, false, false)] + public void NonBlittableStructIn(bool b1, bool b2, bool b3) + { + var container = new BoolStruct_V1 + { + b1 = b1, + b2 = b2, + b3 = b3 + }; + + Assert.Equal(b1 && b2 && b3, NativeExportsNE.V1.AndBoolsRef(container)); + } + + private static string ReverseChars(string value) + { + if (value == null) + return null; + + var chars = value.ToCharArray(); + Array.Reverse(chars); + return new string(chars); + } + + private static string ReverseUTF8Bytes(string value) + { + if (value == null) + return null; + + byte[] bytes = Encoding.UTF8.GetBytes(value); + Array.Reverse(bytes); + return Encoding.UTF8.GetString(bytes); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.cs index 8afd4544cdcf43..13800c9980a281 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.cs @@ -13,26 +13,29 @@ namespace LibraryImportGenerator.IntegrationTests { partial class NativeExportsNE { - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "stringcontainer_deepduplicate")] - public static partial void DeepDuplicateStrings(StringContainer strings, out StringContainer pStringsOut); + internal partial class Stateless + { + [LibraryImport(NativeExportsNE_Binary, EntryPoint = "stringcontainer_deepduplicate")] + public static partial void DeepDuplicateStrings(StringContainer strings, out StringContainer pStringsOut); - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "stringcontainer_reverse_strings")] - public static partial void ReverseStrings(ref StringContainer strings); + [LibraryImport(NativeExportsNE_Binary, EntryPoint = "stringcontainer_reverse_strings")] + public static partial void ReverseStrings(ref StringContainer strings); - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "get_long_bytes_as_double")] - public static partial double GetLongBytesAsDouble([MarshalUsing(typeof(DoubleToLongMarshaler))] double d); + [LibraryImport(NativeExportsNE_Binary, EntryPoint = "get_long_bytes_as_double")] + public static partial double GetLongBytesAsDouble([MarshalUsing(typeof(DoubleToLongMarshaller))] double d); - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "negate_bools")] - public static partial void NegateBools( - BoolStruct boolStruct, - out BoolStruct pBoolStructOut); + [LibraryImport(NativeExportsNE_Binary, EntryPoint = "negate_bools")] + public static partial void NegateBools( + BoolStruct boolStruct, + out BoolStruct pBoolStructOut); - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "and_bools_ref")] - [return: MarshalAs(UnmanagedType.U1)] - public static partial bool AndBoolsRef(in BoolStruct boolStruct); + [LibraryImport(NativeExportsNE_Binary, EntryPoint = "and_bools_ref")] + [return: MarshalAs(UnmanagedType.U1)] + public static partial bool AndBoolsRef(in BoolStruct boolStruct); - [LibraryImport(NativeExportsNE_Binary, EntryPoint = "double_int_ref")] - public static partial IntWrapper DoubleIntRef(IntWrapper pInt); + [LibraryImport(NativeExportsNE_Binary, EntryPoint = "double_int_ref")] + public static partial IntWrapper DoubleIntRef(IntWrapper pInt); + } [LibraryImport(NativeExportsNE_Binary, EntryPoint = "reverse_replace_ref_ushort")] public static partial void ReverseReplaceString([MarshalUsing(typeof(Utf16StringMarshaller))] ref string s); @@ -52,7 +55,7 @@ public void NonBlittableStructWithFree() str2 = "Bar" }; - NativeExportsNE.DeepDuplicateStrings(stringContainer, out var stringContainer2); + NativeExportsNE.Stateless.DeepDuplicateStrings(stringContainer, out var stringContainer2); Assert.Equal(stringContainer, stringContainer2); } @@ -62,7 +65,7 @@ public void MarshalUsing() { double d = 1234.56789; - Assert.Equal(d, NativeExportsNE.GetLongBytesAsDouble(d)); + Assert.Equal(d, NativeExportsNE.Stateless.GetLongBytesAsDouble(d)); } [Fact] @@ -75,7 +78,7 @@ public void NonBlittableStructWithoutAllocation() b3 = true }; - NativeExportsNE.NegateBools(boolStruct, out BoolStruct boolStructNegated); + NativeExportsNE.Stateless.NegateBools(boolStruct, out BoolStruct boolStructNegated); Assert.Equal(!boolStruct.b1, boolStructNegated.b1); Assert.Equal(!boolStruct.b2, boolStructNegated.b2); @@ -88,7 +91,7 @@ public void GetPinnableReferenceMarshalling() int originalValue = 42; var wrapper = new IntWrapper { i = originalValue }; - var retVal = NativeExportsNE.DoubleIntRef(wrapper); + var retVal = NativeExportsNE.Stateless.DoubleIntRef(wrapper); Assert.Equal(originalValue * 2, wrapper.i); Assert.Equal(originalValue * 2, retVal.i); @@ -111,7 +114,7 @@ public void NonBlittableStructRef() var stringContainerCopy = stringContainer; - NativeExportsNE.ReverseStrings(ref stringContainerCopy); + NativeExportsNE.Stateless.ReverseStrings(ref stringContainerCopy); Assert.Equal(expected, stringContainerCopy); } @@ -134,7 +137,7 @@ public void NonBlittableStructIn(bool b1, bool b2, bool b3) b3 = b3 }; - Assert.Equal(b1 && b2 && b3, NativeExportsNE.AndBoolsRef(container)); + Assert.Equal(b1 && b2 && b3, NativeExportsNE.Stateless.AndBoolsRef(container)); } [Fact] diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/SpanTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/SpanTests.cs index f92e2bc9e5e960..d26aa04c5e1a0e 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/SpanTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/SpanTests.cs @@ -49,7 +49,7 @@ public partial class Span [LibraryImport(NativeExportsNE_Binary, EntryPoint = "and_all_members")] [return: MarshalAs(UnmanagedType.U1)] - public static partial bool AndAllMembers([MarshalUsing(typeof(SpanMarshaller))] Span pArray, int length); + public static partial bool AndAllMembers([MarshalUsing(typeof(SpanMarshaller))] Span pArray, int length); } } @@ -135,21 +135,21 @@ public void NullBlittableElementSpanReturnedFromNative() [InlineData(false)] public void SpanWithSimpleNonBlittableTypeMarshalling(bool result) { - var boolValues = new BoolStruct[] + var boolValues = new BoolStruct_V1[] { - new BoolStruct + new BoolStruct_V1 { b1 = true, b2 = true, b3 = true, }, - new BoolStruct + new BoolStruct_V1 { b1 = true, b2 = true, b3 = true, }, - new BoolStruct + new BoolStruct_V1 { b1 = true, b2 = true, diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs index 6494198d0b5900..b31c6441fd67e6 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs @@ -681,6 +681,87 @@ partial class Test public static class CustomStructMarshalling { public static string NonBlittableUserDefinedType(bool defineNativeMarshalling = true) => $@" +{(defineNativeMarshalling ? "[NativeMarshalling(typeof(Marshaller))]" : string.Empty)} +public struct S +{{ +#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value + public bool b; +#pragma warning restore CS0649 +}} +"; + private static string NonStatic = @" +[ManagedToUnmanagedMarshallers(typeof(S))] +public class Marshaller +{ + public struct Native { } + + public static Native ConvertToUnmanaged(S s) => default; +} +"; + private static string StatelessIn = @" +[ManagedToUnmanagedMarshallers(typeof(S))] +public static class Marshaller +{ + public struct Native { } + + public static Native ConvertToUnmanaged(S s) => default; +} +"; + private static string StatelessOut = @" +[ManagedToUnmanagedMarshallers(typeof(S))] +public static class Marshaller +{ + public struct Native { } + + public static S ConvertToManaged(Native n) => default; +} +"; + public static string StatelessRef = @" +[ManagedToUnmanagedMarshallers(typeof(S))] +public static class Marshaller +{ + public struct Native { } + + public static Native ConvertToUnmanaged(S s) => default; + public static S ConvertToManaged(Native n) => default; +} +"; + public static string ManagedToNativeOnlyOutParameter => BasicParameterWithByRefModifier("out", "S") + + NonBlittableUserDefinedType() + + StatelessIn; + + public static string NativeToManagedOnlyOutParameter => BasicParameterWithByRefModifier("out", "S") + + NonBlittableUserDefinedType() + + StatelessOut; + + public static string ManagedToNativeOnlyReturnValue => BasicReturnType("S") + + NonBlittableUserDefinedType() + + StatelessIn; + + public static string NativeToManagedOnlyReturnValue => BasicReturnType("S") + + NonBlittableUserDefinedType() + + StatelessOut; + + public static string NativeToManagedOnlyInParameter => BasicParameterWithByRefModifier("in", "S") + + NonBlittableUserDefinedType() + + StatelessOut; + + public static string ParametersAndModifiers = BasicParametersAndModifiers("S", UsingSystemRuntimeInteropServicesMarshalling) + + NonBlittableUserDefinedType(defineNativeMarshalling: true) + + StatelessRef; + + public static string MarshalUsingParametersAndModifiers = MarshalUsingParametersAndModifiers("S", "Marshaller") + + NonBlittableUserDefinedType(defineNativeMarshalling: false) + + StatelessRef; + + public static string NonStaticMarshallerEntryPoint => BasicParameterByValue("S") + + NonBlittableUserDefinedType() + + NonStatic; + } + + public static class CustomStructMarshalling_V1 + { + public static string NonBlittableUserDefinedType(bool defineNativeMarshalling = true) => $@" {(defineNativeMarshalling ? "[NativeMarshalling(typeof(Native))]" : string.Empty)} struct S {{ diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs index 44aec66b22e64c..f7463afd4204ef 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs @@ -92,11 +92,15 @@ public static IEnumerable CodeSnippetsToCompile() yield return new object[] { CodeSnippets.MarshalUsingArrayParameterWithSizeParam(isByRef: false), 2, 0 }; // Custom type marshalling with invalid members - yield return new object[] { CodeSnippets.CustomStructMarshalling.TwoStageRefReturn, 3, 0 }; yield return new object[] { CodeSnippets.CustomStructMarshalling.ManagedToNativeOnlyOutParameter, 1, 0 }; yield return new object[] { CodeSnippets.CustomStructMarshalling.ManagedToNativeOnlyReturnValue, 1, 0 }; yield return new object[] { CodeSnippets.CustomStructMarshalling.NativeToManagedOnlyInParameter, 1, 0 }; - yield return new object[] { CodeSnippets.CustomStructMarshalling.StackallocOnlyRefParameter, 1, 0 }; + yield return new object[] { CodeSnippets.CustomStructMarshalling.NonStaticMarshallerEntryPoint, 2, 0 }; + yield return new object[] { CodeSnippets.CustomStructMarshalling_V1.TwoStageRefReturn, 3, 0 }; + yield return new object[] { CodeSnippets.CustomStructMarshalling_V1.ManagedToNativeOnlyOutParameter, 1, 0 }; + yield return new object[] { CodeSnippets.CustomStructMarshalling_V1.ManagedToNativeOnlyReturnValue, 1, 0 }; + yield return new object[] { CodeSnippets.CustomStructMarshalling_V1.NativeToManagedOnlyInParameter, 1, 0 }; + yield return new object[] { CodeSnippets.CustomStructMarshalling_V1.StackallocOnlyRefParameter, 1, 0 }; // Abstract SafeHandle type by reference yield return new object[] { CodeSnippets.BasicParameterWithByRefModifier("ref", "System.Runtime.InteropServices.SafeHandle"), 1, 0 }; diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs index 3448c83275cafb..c45a52e6b7b491 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using LibraryImportGenerator.UnitTests; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -117,11 +118,11 @@ public static IEnumerable CodeSnippetsToCompile() // [In, Out] attributes // By value non-blittable array yield return new [] { CodeSnippets.ByValueParameterWithModifier("S[]", "Out") - + CodeSnippets.CustomStructMarshalling.NonBlittableUserDefinedType() - + CodeSnippets.CustomStructMarshalling.NativeTypeRef }; + + CodeSnippets.CustomStructMarshalling_V1.NonBlittableUserDefinedType() + + CodeSnippets.CustomStructMarshalling_V1.NativeTypeRef }; yield return new [] { CodeSnippets.ByValueParameterWithModifier("S[]", "In, Out") - + CodeSnippets.CustomStructMarshalling.NonBlittableUserDefinedType() - + CodeSnippets.CustomStructMarshalling.NativeTypeRef }; + + CodeSnippets.CustomStructMarshalling_V1.NonBlittableUserDefinedType() + + CodeSnippets.CustomStructMarshalling_V1.NativeTypeRef }; // Enums yield return new[] { CodeSnippets.EnumParameters }; @@ -170,16 +171,20 @@ public static IEnumerable CodeSnippetsToCompile() // Custom type marshalling yield return new[] { CodeSnippets.CustomStructMarshalling.ParametersAndModifiers }; - yield return new[] { CodeSnippets.CustomStructMarshalling.StackallocParametersAndModifiersNoRef }; - yield return new[] { CodeSnippets.CustomStructMarshalling.StackallocTwoStageParametersAndModifiersNoRef }; - yield return new[] { CodeSnippets.CustomStructMarshalling.OptionalStackallocParametersAndModifiers }; - yield return new[] { CodeSnippets.CustomStructMarshalling.TwoStageParametersAndModifiers }; - yield return new[] { CodeSnippets.CustomStructMarshalling.PinnableParametersAndModifiers }; - yield return new[] { CodeSnippets.CustomStructMarshalling.NativeTypePinnable("byte", "byte") }; - yield return new[] { CodeSnippets.CustomStructMarshalling.NativeTypePinnable("byte", "int") }; yield return new[] { CodeSnippets.CustomStructMarshalling.MarshalUsingParametersAndModifiers }; yield return new[] { CodeSnippets.CustomStructMarshalling.NativeToManagedOnlyOutParameter }; yield return new[] { CodeSnippets.CustomStructMarshalling.NativeToManagedOnlyReturnValue }; + yield return new[] { CodeSnippets.CustomStructMarshalling_V1.ParametersAndModifiers }; + yield return new[] { CodeSnippets.CustomStructMarshalling_V1.StackallocParametersAndModifiersNoRef }; + yield return new[] { CodeSnippets.CustomStructMarshalling_V1.StackallocTwoStageParametersAndModifiersNoRef }; + yield return new[] { CodeSnippets.CustomStructMarshalling_V1.OptionalStackallocParametersAndModifiers }; + yield return new[] { CodeSnippets.CustomStructMarshalling_V1.TwoStageParametersAndModifiers }; + yield return new[] { CodeSnippets.CustomStructMarshalling_V1.PinnableParametersAndModifiers }; + yield return new[] { CodeSnippets.CustomStructMarshalling_V1.NativeTypePinnable("byte", "byte") }; + yield return new[] { CodeSnippets.CustomStructMarshalling_V1.NativeTypePinnable("byte", "int") }; + yield return new[] { CodeSnippets.CustomStructMarshalling_V1.MarshalUsingParametersAndModifiers }; + yield return new[] { CodeSnippets.CustomStructMarshalling_V1.NativeToManagedOnlyOutParameter }; + yield return new[] { CodeSnippets.CustomStructMarshalling_V1.NativeToManagedOnlyReturnValue }; yield return new[] { CodeSnippets.ArrayMarshallingWithCustomStructElement }; yield return new[] { CodeSnippets.ArrayMarshallingWithCustomStructElementWithValueProperty }; diff --git a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/Arrays.cs b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/Arrays.cs index e2e9996f669300..29b6a14904ce11 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/Arrays.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/Arrays.cs @@ -236,12 +236,12 @@ public static void Append(int** values, int numOriginalValues, int newValue) [UnmanagedCallersOnly(EntryPoint = "and_all_members")] [DNNE.C99DeclCode("struct bool_struct;")] - public static byte AndAllMembers([DNNE.C99Type("struct bool_struct*")] BoolStructNative* pArray, int length) + public static byte AndAllMembers([DNNE.C99Type("struct bool_struct*")] BoolStructNative_V1* pArray, int length) { bool result = true; for (int i = 0; i < length; i++) { - BoolStruct managed = pArray[i].ToManaged(); + BoolStruct_V1 managed = pArray[i].ToManaged(); result &= managed.b1 && managed.b2 && managed.b3; } return (byte)(result ? 1 : 0); diff --git a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/CustomMarshalling.cs b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/CustomMarshalling.cs index 2da06a7540871b..31a4771d46d1ed 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/CustomMarshalling.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/CustomMarshalling.cs @@ -12,16 +12,16 @@ public static unsafe class CustomMarshalling [UnmanagedCallersOnly(EntryPoint = "stringcontainer_deepduplicate")] [DNNE.C99DeclCode("struct string_container { char* str1; char* str2; };")] public static void DeepDuplicateStrings( - [DNNE.C99Type("struct string_container")] StringContainerNative strings, - [DNNE.C99Type("struct string_container*")] StringContainerNative* pStringsOut) + [DNNE.C99Type("struct string_container")] StringContainerNative_V1 strings, + [DNNE.C99Type("struct string_container*")] StringContainerNative_V1* pStringsOut) { // Round trip through the managed view to allocate a new native instance. - *pStringsOut = new StringContainerNative(strings.ToManaged()); + *pStringsOut = new StringContainerNative_V1(strings.ToManaged()); } [UnmanagedCallersOnly(EntryPoint = "stringcontainer_reverse_strings")] public static void ReverseStrings( - [DNNE.C99Type("struct string_container*")] StringContainerNative* strings) + [DNNE.C99Type("struct string_container*")] StringContainerNative_V1* strings) { strings->str1 = (IntPtr)Strings.Reverse((byte*)strings->str1); strings->str2 = (IntPtr)Strings.Reverse((byte*)strings->str2); @@ -36,10 +36,10 @@ public static double GetLongBytesAsDouble(long l) [UnmanagedCallersOnly(EntryPoint = "negate_bools")] [DNNE.C99DeclCode("struct bool_struct { int8_t b1; int8_t b2; int8_t b3; };")] public static void NegateBools( - [DNNE.C99Type("struct bool_struct")] BoolStructNative boolStruct, - [DNNE.C99Type("struct bool_struct*")] BoolStructNative* pBoolStructOut) + [DNNE.C99Type("struct bool_struct")] BoolStructNative_V1 boolStruct, + [DNNE.C99Type("struct bool_struct*")] BoolStructNative_V1* pBoolStructOut) { - *pBoolStructOut = new BoolStructNative + *pBoolStructOut = new BoolStructNative_V1 { b1 = (byte)(boolStruct.b1 != 0 ? 0 : 1), b2 = (byte)(boolStruct.b2 != 0 ? 0 : 1), @@ -49,7 +49,7 @@ public static void NegateBools( [UnmanagedCallersOnly(EntryPoint = "and_bools_ref")] public static byte AndBoolsRef( - [DNNE.C99Type("struct bool_struct*")] BoolStructNative* boolStruct) + [DNNE.C99Type("struct bool_struct*")] BoolStructNative_V1* boolStruct) { return (byte)(boolStruct->b1 != 0 && boolStruct->b2 != 0 && boolStruct->b3 != 0 ? 1 : 0); } diff --git a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.V1.cs b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.V1.cs new file mode 100644 index 00000000000000..7f8d5cc0f72ef6 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.V1.cs @@ -0,0 +1,283 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using System.Text; + +namespace SharedTypes +{ + [NativeMarshalling(typeof(StringContainerNative_V1))] + public struct StringContainer_V1 + { + public string str1; + public string str2; + } + + [CustomTypeMarshaller(typeof(StringContainer_V1), Features = CustomTypeMarshallerFeatures.UnmanagedResources)] + public struct StringContainerNative_V1 + { + public IntPtr str1; + public IntPtr str2; + + public StringContainerNative_V1(StringContainer_V1 managed) + { + str1 = Marshal.StringToCoTaskMemUTF8(managed.str1); + str2 = Marshal.StringToCoTaskMemUTF8(managed.str2); + } + + public StringContainer_V1 ToManaged() + { + return new StringContainer_V1 + { + str1 = Marshal.PtrToStringUTF8(str1), + str2 = Marshal.PtrToStringUTF8(str2) + }; + } + + public void FreeNative() + { + Marshal.FreeCoTaskMem(str1); + Marshal.FreeCoTaskMem(str2); + } + } + + [CustomTypeMarshaller(typeof(double), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] + public struct DoubleToLongMarshaller_V1 + { + public long l; + + public DoubleToLongMarshaller_V1(double d) + { + l = MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref d, 1))[0]; + } + + public double ToManaged() => MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref l, 1))[0]; + + public long ToNativeValue() => l; + + public void FromNativeValue(long value) => l = value; + } + + [NativeMarshalling(typeof(BoolStructNative_V1))] + public struct BoolStruct_V1 + { + public bool b1; + public bool b2; + public bool b3; + } + + [CustomTypeMarshaller(typeof(BoolStruct_V1))] + public struct BoolStructNative_V1 + { + public byte b1; + public byte b2; + public byte b3; + public BoolStructNative_V1(BoolStruct_V1 bs) + { + b1 = (byte)(bs.b1 ? 1 : 0); + b2 = (byte)(bs.b2 ? 1 : 0); + b3 = (byte)(bs.b3 ? 1 : 0); + } + + public BoolStruct_V1 ToManaged() + { + return new BoolStruct_V1 + { + b1 = b1 != 0, + b2 = b2 != 0, + b3 = b3 != 0 + }; + } + } + + [NativeMarshalling(typeof(IntWrapperMarshaler_V1))] + public class IntWrapper_V1 + { + public int i; + + public ref int GetPinnableReference() => ref i; + } + + [CustomTypeMarshaller(typeof(IntWrapper_V1), Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling)] + public unsafe struct IntWrapperMarshaler_V1 + { + public IntWrapperMarshaler_V1(IntWrapper_V1 managed) + { + Value = (int*)Marshal.AllocCoTaskMem(sizeof(int)); + *Value = managed.i; + } + + private int* Value { get; set; } + + public int* ToNativeValue() => Value; + public void FromNativeValue(int* value) => Value = value; + + public IntWrapper_V1 ToManaged() => new IntWrapper_V1 { i = *Value }; + + public void FreeNative() + { + Marshal.FreeCoTaskMem((IntPtr)Value); + } + } + + [NativeMarshalling(typeof(IntStructWrapperNative))] + public struct IntStructWrapper + { + public int Value; + } + + [CustomTypeMarshaller(typeof(IntStructWrapper))] + public struct IntStructWrapperNative + { + public int value; + public IntStructWrapperNative(IntStructWrapper managed) + { + value = managed.Value; + } + + public IntStructWrapper ToManaged() => new IntStructWrapper { Value = value }; + } + + [CustomTypeMarshaller(typeof(List<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling | CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 0x200)] + public unsafe ref struct ListMarshaller + { + private List managedList; + private readonly int sizeOfNativeElement; + private IntPtr allocatedMemory; + + public ListMarshaller(int sizeOfNativeElement) + : this() + { + this.sizeOfNativeElement = sizeOfNativeElement; + } + + public ListMarshaller(List managed, int sizeOfNativeElement) + :this(managed, Span.Empty, sizeOfNativeElement) + { + } + + public ListMarshaller(List managed, Span stackSpace, int sizeOfNativeElement) + { + allocatedMemory = default; + this.sizeOfNativeElement = sizeOfNativeElement; + if (managed is null) + { + managedList = null; + NativeValueStorage = default; + return; + } + managedList = managed; + // Always allocate at least one byte when the list is zero-length. + int spaceToAllocate = Math.Max(managed.Count * sizeOfNativeElement, 1); + if (spaceToAllocate <= stackSpace.Length) + { + NativeValueStorage = stackSpace[0..spaceToAllocate]; + } + else + { + allocatedMemory = Marshal.AllocCoTaskMem(spaceToAllocate); + NativeValueStorage = new Span((void*)allocatedMemory, spaceToAllocate); + } + } + + public ReadOnlySpan GetManagedValuesSource() => CollectionsMarshal.AsSpan(managedList); + + public Span GetManagedValuesDestination(int length) + { + if (allocatedMemory == IntPtr.Zero) + { + managedList = null; + return default; + } + managedList = new List(length); + for (int i = 0; i < length; i++) + { + managedList.Add(default); + } + return CollectionsMarshal.AsSpan(managedList); + } + + private Span NativeValueStorage { get; set; } + + public Span GetNativeValuesDestination() => NativeValueStorage; + + public ReadOnlySpan GetNativeValuesSource(int length) + { + return allocatedMemory == IntPtr.Zero ? default : NativeValueStorage = new Span((void*)allocatedMemory, length * sizeOfNativeElement); + } + + public ref byte GetPinnableReference() => ref NativeValueStorage.GetPinnableReference(); + + public byte* ToNativeValue() => (byte*)Unsafe.AsPointer(ref GetPinnableReference()); + + public void FromNativeValue(byte* value) + { + allocatedMemory = (IntPtr)value; + } + + public List ToManaged() => managedList; + + public void FreeNative() + { + Marshal.FreeCoTaskMem(allocatedMemory); + } + } + + [NativeMarshalling(typeof(WrappedListMarshaller<>))] + public struct WrappedList + { + public WrappedList(List list) + { + Wrapped = list; + } + + public List Wrapped { get; } + + public ref T GetPinnableReference() => ref CollectionsMarshal.AsSpan(Wrapped).GetPinnableReference(); + } + + [CustomTypeMarshaller(typeof(WrappedList<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling | CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 0x200)] + public unsafe ref struct WrappedListMarshaller + { + private ListMarshaller _marshaller; + + public WrappedListMarshaller(int sizeOfNativeElement) + : this() + { + this._marshaller = new ListMarshaller(sizeOfNativeElement); + } + + public WrappedListMarshaller(WrappedList managed, int sizeOfNativeElement) + : this(managed, Span.Empty, sizeOfNativeElement) + { + } + + public WrappedListMarshaller(WrappedList managed, Span stackSpace, int sizeOfNativeElement) + { + this._marshaller = new ListMarshaller(managed.Wrapped, stackSpace, sizeOfNativeElement); + } + + public ReadOnlySpan GetManagedValuesSource() => _marshaller.GetManagedValuesSource(); + + public Span GetManagedValuesDestination(int length) => _marshaller.GetManagedValuesDestination(length); + + public Span GetNativeValuesDestination() => _marshaller.GetNativeValuesDestination(); + + public ReadOnlySpan GetNativeValuesSource(int length) => _marshaller.GetNativeValuesSource(length); + + public ref byte GetPinnableReference() => ref _marshaller.GetPinnableReference(); + + public byte* ToNativeValue() => _marshaller.ToNativeValue(); + + public void FromNativeValue(byte* value) => _marshaller.FromNativeValue(value); + + public WrappedList ToManaged() => new(_marshaller.ToManaged()); + + public void FreeNative() => _marshaller.FreeNative(); + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs index d580054ad4ab19..c8c2c9dbbc5868 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs @@ -11,59 +11,81 @@ namespace SharedTypes { - [NativeMarshalling(typeof(StringContainerNative))] + [NativeMarshalling(typeof(StringContainerMarshaller))] public struct StringContainer { public string str1; public string str2; } - [CustomTypeMarshaller(typeof(StringContainer), Features = CustomTypeMarshallerFeatures.UnmanagedResources)] - public struct StringContainerNative + [ManagedToUnmanagedMarshallers(typeof(StringContainer), + InMarshaller = typeof(In), + RefMarshaller = typeof(Ref), + OutMarshaller = typeof(Out))] + public static class StringContainerMarshaller { - public IntPtr str1; - public IntPtr str2; + public struct StringContainerNative + { + public IntPtr str1; + public IntPtr str2; + } - public StringContainerNative(StringContainer managed) + public static class In { - str1 = Marshal.StringToCoTaskMemUTF8(managed.str1); - str2 = Marshal.StringToCoTaskMemUTF8(managed.str2); + public static StringContainerNative ConvertToUnmanaged(StringContainer managed) + => Ref.ConvertToUnmanaged(managed); + + public static void Free(StringContainerNative unmanaged) + => Ref.Free(unmanaged); } - public StringContainer ToManaged() + public static class Ref { - return new StringContainer + public static StringContainerNative ConvertToUnmanaged(StringContainer managed) { - str1 = Marshal.PtrToStringUTF8(str1), - str2 = Marshal.PtrToStringUTF8(str2) - }; + return new StringContainerNative + { + str1 = Marshal.StringToCoTaskMemUTF8(managed.str1), + str2 = Marshal.StringToCoTaskMemUTF8(managed.str2) + }; + } + + public static StringContainer ConvertToManaged(StringContainerNative unmanaged) + { + return new StringContainer + { + str1 = Marshal.PtrToStringUTF8(unmanaged.str1), + str2 = Marshal.PtrToStringUTF8(unmanaged.str2) + }; + } + + public static void Free(StringContainerNative unmanaged) + { + Marshal.FreeCoTaskMem(unmanaged.str1); + Marshal.FreeCoTaskMem(unmanaged.str2); + } } - public void FreeNative() + public static class Out { - Marshal.FreeCoTaskMem(str1); - Marshal.FreeCoTaskMem(str2); + public static StringContainer ConvertToManaged(StringContainerNative unmanaged) + => Ref.ConvertToManaged(unmanaged); + + public static void Free(StringContainerNative unmanaged) + => Ref.Free(unmanaged); } } - [CustomTypeMarshaller(typeof(double), Features = CustomTypeMarshallerFeatures.TwoStageMarshalling)] - public struct DoubleToLongMarshaler + [ManagedToUnmanagedMarshallers(typeof(double))] + public static class DoubleToLongMarshaller { - public long l; - - public DoubleToLongMarshaler(double d) + public static long ConvertToUnmanaged(double managed) { - l = MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref d, 1))[0]; + return MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref managed, 1))[0]; } - - public double ToManaged() => MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref l, 1))[0]; - - public long ToNativeValue() => l; - - public void FromNativeValue(long value) => l = value; } - [NativeMarshalling(typeof(BoolStructNative))] + [NativeMarshalling(typeof(BoolStructMarshaller))] public struct BoolStruct { public bool b1; @@ -71,213 +93,63 @@ public struct BoolStruct public bool b3; } - [CustomTypeMarshaller(typeof(BoolStruct))] - public struct BoolStructNative + [ManagedToUnmanagedMarshallers(typeof(BoolStruct))] + public static class BoolStructMarshaller { - public byte b1; - public byte b2; - public byte b3; - public BoolStructNative(BoolStruct bs) + public struct BoolStructNative { - b1 = (byte)(bs.b1 ? 1 : 0); - b2 = (byte)(bs.b2 ? 1 : 0); - b3 = (byte)(bs.b3 ? 1 : 0); + public byte b1; + public byte b2; + public byte b3; } - public BoolStruct ToManaged() + public static BoolStructNative ConvertToUnmanaged(BoolStruct managed) { - return new BoolStruct + return new BoolStructNative { - b1 = b1 != 0, - b2 = b2 != 0, - b3 = b3 != 0 + b1 = (byte)(managed.b1 ? 1 : 0), + b2 = (byte)(managed.b2 ? 1 : 0), + b3 = (byte)(managed.b3 ? 1 : 0) }; } - } - - [NativeMarshalling(typeof(IntWrapperMarshaler))] - public class IntWrapper - { - public int i; - - public ref int GetPinnableReference() => ref i; - } - - [CustomTypeMarshaller(typeof(IntWrapper), Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling)] - public unsafe struct IntWrapperMarshaler - { - public IntWrapperMarshaler(IntWrapper managed) - { - Value = (int*)Marshal.AllocCoTaskMem(sizeof(int)); - *Value = managed.i; - } - - private int* Value { get; set; } - - public int* ToNativeValue() => Value; - public void FromNativeValue(int* value) => Value = value; - - public IntWrapper ToManaged() => new IntWrapper { i = *Value }; - - public void FreeNative() - { - Marshal.FreeCoTaskMem((IntPtr)Value); - } - } - - [NativeMarshalling(typeof(IntStructWrapperNative))] - public struct IntStructWrapper - { - public int Value; - } - - [CustomTypeMarshaller(typeof(IntStructWrapper))] - public struct IntStructWrapperNative - { - public int value; - public IntStructWrapperNative(IntStructWrapper managed) - { - value = managed.Value; - } - - public IntStructWrapper ToManaged() => new IntStructWrapper { Value = value }; - } - - [CustomTypeMarshaller(typeof(List<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling | CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 0x200)] - public unsafe ref struct ListMarshaller - { - private List managedList; - private readonly int sizeOfNativeElement; - private IntPtr allocatedMemory; - - public ListMarshaller(int sizeOfNativeElement) - : this() - { - this.sizeOfNativeElement = sizeOfNativeElement; - } - - public ListMarshaller(List managed, int sizeOfNativeElement) - :this(managed, Span.Empty, sizeOfNativeElement) - { - } - public ListMarshaller(List managed, Span stackSpace, int sizeOfNativeElement) + public static BoolStruct ConvertToManaged(BoolStructNative unmanaged) { - allocatedMemory = default; - this.sizeOfNativeElement = sizeOfNativeElement; - if (managed is null) - { - managedList = null; - NativeValueStorage = default; - return; - } - managedList = managed; - // Always allocate at least one byte when the list is zero-length. - int spaceToAllocate = Math.Max(managed.Count * sizeOfNativeElement, 1); - if (spaceToAllocate <= stackSpace.Length) - { - NativeValueStorage = stackSpace[0..spaceToAllocate]; - } - else - { - allocatedMemory = Marshal.AllocCoTaskMem(spaceToAllocate); - NativeValueStorage = new Span((void*)allocatedMemory, spaceToAllocate); - } - } - - public ReadOnlySpan GetManagedValuesSource() => CollectionsMarshal.AsSpan(managedList); - - public Span GetManagedValuesDestination(int length) - { - if (allocatedMemory == IntPtr.Zero) - { - managedList = null; - return default; - } - managedList = new List(length); - for (int i = 0; i < length; i++) + return new BoolStruct { - managedList.Add(default); - } - return CollectionsMarshal.AsSpan(managedList); - } - - private Span NativeValueStorage { get; set; } - - public Span GetNativeValuesDestination() => NativeValueStorage; - - public ReadOnlySpan GetNativeValuesSource(int length) - { - return allocatedMemory == IntPtr.Zero ? default : NativeValueStorage = new Span((void*)allocatedMemory, length * sizeOfNativeElement); - } - - public ref byte GetPinnableReference() => ref NativeValueStorage.GetPinnableReference(); - - public byte* ToNativeValue() => (byte*)Unsafe.AsPointer(ref GetPinnableReference()); - - public void FromNativeValue(byte* value) - { - allocatedMemory = (IntPtr)value; - } - - public List ToManaged() => managedList; - - public void FreeNative() - { - Marshal.FreeCoTaskMem(allocatedMemory); + b1 = unmanaged.b1 != 0, + b2 = unmanaged.b2 != 0, + b3 = unmanaged.b3 != 0 + }; } } - [NativeMarshalling(typeof(WrappedListMarshaller<>))] - public struct WrappedList + [NativeMarshalling(typeof(IntWrapperMarshaller))] + public class IntWrapper { - public WrappedList(List list) - { - Wrapped = list; - } - - public List Wrapped { get; } + public int i; - public ref T GetPinnableReference() => ref CollectionsMarshal.AsSpan(Wrapped).GetPinnableReference(); + public ref int GetPinnableReference() => ref i; } - [CustomTypeMarshaller(typeof(WrappedList<>), CustomTypeMarshallerKind.LinearCollection, Features = CustomTypeMarshallerFeatures.UnmanagedResources | CustomTypeMarshallerFeatures.TwoStageMarshalling | CustomTypeMarshallerFeatures.CallerAllocatedBuffer, BufferSize = 0x200)] - public unsafe ref struct WrappedListMarshaller + [ManagedToUnmanagedMarshallers(typeof(IntWrapper))] + public static unsafe class IntWrapperMarshaller { - private ListMarshaller _marshaller; - - public WrappedListMarshaller(int sizeOfNativeElement) - : this() + public static int* ConvertToUnmanaged(IntWrapper managed) { - this._marshaller = new ListMarshaller(sizeOfNativeElement); + int* ret = (int*)Marshal.AllocCoTaskMem(sizeof(int)); + *ret = managed.i; + return ret; } - public WrappedListMarshaller(WrappedList managed, int sizeOfNativeElement) - : this(managed, Span.Empty, sizeOfNativeElement) + public static IntWrapper ConvertToManaged(int* unmanaged) { + return new IntWrapper { i = *unmanaged }; } - public WrappedListMarshaller(WrappedList managed, Span stackSpace, int sizeOfNativeElement) + public static void Free(int* unmanaged) { - this._marshaller = new ListMarshaller(managed.Wrapped, stackSpace, sizeOfNativeElement); + Marshal.FreeCoTaskMem((IntPtr)unmanaged); } - - public ReadOnlySpan GetManagedValuesSource() => _marshaller.GetManagedValuesSource(); - - public Span GetManagedValuesDestination(int length) => _marshaller.GetManagedValuesDestination(length); - - public Span GetNativeValuesDestination() => _marshaller.GetNativeValuesDestination(); - - public ReadOnlySpan GetNativeValuesSource(int length) => _marshaller.GetNativeValuesSource(length); - - public ref byte GetPinnableReference() => ref _marshaller.GetPinnableReference(); - - public byte* ToNativeValue() => _marshaller.ToNativeValue(); - - public void FromNativeValue(byte* value) => _marshaller.FromNativeValue(value); - - public WrappedList ToManaged() => new(_marshaller.ToManaged()); - - public void FreeNative() => _marshaller.FreeNative(); } }