| File: Marshalling\CustomTypeMarshallingGenerator.cs | Web Access |
| Project: Microsoft.Interop.SourceGeneration.csproj (Microsoft.Interop.SourceGeneration) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace Microsoft.Interop { /// <summary> /// Implements generating code for an <see cref="ICustomTypeMarshallingStrategy"/> instance. /// </summary> internal sealed class CustomTypeMarshallingGenerator(ICustomTypeMarshallingStrategy nativeTypeMarshaller, ByValueMarshalKindSupportDescriptor byValueContentsMarshallingSupport, bool isPinned) : IBoundMarshallingGenerator { public ValueBoundaryBehavior ValueBoundaryBehavior => TypeInfo.IsByRef ? ValueBoundaryBehavior.AddressOfNativeIdentifier : ValueBoundaryBehavior.NativeIdentifier; public ManagedTypeInfo NativeType => nativeTypeMarshaller.NativeType; public SignatureBehavior NativeSignatureBehavior => TypeInfo.IsByRef ? SignatureBehavior.PointerToNativeType : SignatureBehavior.NativeType; public TypePositionInfo TypeInfo => nativeTypeMarshaller.TypeInfo; public StubCodeContext CodeContext => nativeTypeMarshaller.CodeContext; public void Generate(IndentedTextWriter writer, StubIdentifierContext context) { MarshalDirection elementMarshalDirection = MarshallerHelpers.GetMarshalDirection(TypeInfo, CodeContext); // Although custom native type marshalling doesn't support [In] or [Out] by value marshalling, // other marshallers that wrap this one might, so we handle the correct cases here. switch (context.CurrentStage) { case StubIdentifierContext.Stage.Setup: nativeTypeMarshaller.GenerateSetupStatements(writer, context); break; case StubIdentifierContext.Stage.Marshal: if (elementMarshalDirection is MarshalDirection.ManagedToUnmanaged or MarshalDirection.Bidirectional || (CodeContext.Direction == MarshalDirection.UnmanagedToManaged && ShouldGenerateByValueOutMarshalling)) { nativeTypeMarshaller.GenerateMarshalStatements(writer, context); } break; case StubIdentifierContext.Stage.Pin: if (CodeContext.SingleFrameSpansNativeContext && elementMarshalDirection is MarshalDirection.ManagedToUnmanaged) { nativeTypeMarshaller.GeneratePinStatements(writer, context); } break; case StubIdentifierContext.Stage.PinnedMarshal: if (elementMarshalDirection is MarshalDirection.ManagedToUnmanaged or MarshalDirection.Bidirectional) { nativeTypeMarshaller.GeneratePinnedMarshalStatements(writer, context); } break; case StubIdentifierContext.Stage.NotifyForSuccessfulInvoke: if (elementMarshalDirection is MarshalDirection.ManagedToUnmanaged or MarshalDirection.Bidirectional) { nativeTypeMarshaller.GenerateNotifyForSuccessfulInvokeStatements(writer, context); } break; case StubIdentifierContext.Stage.UnmarshalCapture: if (elementMarshalDirection is MarshalDirection.UnmanagedToManaged or MarshalDirection.Bidirectional) { nativeTypeMarshaller.GenerateUnmarshalCaptureStatements(writer, context); } break; case StubIdentifierContext.Stage.Unmarshal: if (elementMarshalDirection is MarshalDirection.UnmanagedToManaged or MarshalDirection.Bidirectional || (CodeContext.Direction == MarshalDirection.ManagedToUnmanaged && ShouldGenerateByValueOutMarshalling)) { nativeTypeMarshaller.GenerateUnmarshalStatements(writer, context); } break; case StubIdentifierContext.Stage.GuaranteedUnmarshal: if (elementMarshalDirection is MarshalDirection.UnmanagedToManaged or MarshalDirection.Bidirectional || (CodeContext.Direction == MarshalDirection.ManagedToUnmanaged && ShouldGenerateByValueOutMarshalling)) { nativeTypeMarshaller.GenerateGuaranteedUnmarshalStatements(writer, context); } break; case StubIdentifierContext.Stage.CleanupCallerAllocated: nativeTypeMarshaller.GenerateCleanupCallerAllocatedResourcesStatements(writer, context); break; case StubIdentifierContext.Stage.CleanupCalleeAllocated: nativeTypeMarshaller.GenerateCleanupCalleeAllocatedResourcesStatements(writer, context); break; default: break; } } private bool ShouldGenerateByValueOutMarshalling => TypeInfo.ByValueContentsMarshalKind.HasFlag(ByValueContentsMarshalKind.Out) && byValueContentsMarshallingSupport.GetSupport(TypeInfo.ByValueContentsMarshalKind, TypeInfo, out _) != ByValueMarshalKindSupport.NotSupported && !TypeInfo.IsByRef && !isPinned; public bool UsesNativeIdentifier => nativeTypeMarshaller.UsesNativeIdentifier; public ByValueMarshalKindSupport SupportsByValueMarshalKind(ByValueContentsMarshalKind marshalKind, out GeneratorDiagnostic? diagnostic) { return byValueContentsMarshallingSupport.GetSupport(marshalKind, TypeInfo, out diagnostic); } } }