File: Marshallers\ComInterfaceDispatchMarshallingResolver.cs
Web Access
Project: src\src\libraries\System.Runtime.InteropServices\gen\ComInterfaceGenerator\ComInterfaceGenerator.csproj (Microsoft.Interop.ComInterfaceGenerator)
// 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
{
    internal sealed record ComInterfaceDispatchMarshallingInfo : MarshallingInfo
    {
        public static readonly ComInterfaceDispatchMarshallingInfo Instance = new();
    }
 
    internal sealed class ComInterfaceDispatchMarshallingResolver : IMarshallingGeneratorResolver
    {
        public ResolvedGenerator Create(TypePositionInfo info, StubCodeContext context)
        {
            if (info.MarshallingAttributeInfo is ComInterfaceDispatchMarshallingInfo)
            {
                return context.Direction == MarshalDirection.UnmanagedToManaged
                    ? ResolvedGenerator.Resolved(new Marshaller().Bind(info, context))
                    : ResolvedGenerator.Resolved(KeepAliveThisMarshaller.Instance.Bind(info, context));
            }
            else
            {
                return ResolvedGenerator.UnresolvedGenerator;
            }
        }
 
        private sealed class Marshaller : IUnboundMarshallingGenerator
        {
            public ManagedTypeInfo AsNativeType(TypePositionInfo info) =>
                new PointerTypeInfo(
                    $"{TypeNames.GlobalAlias + TypeNames.System_Runtime_InteropServices_ComWrappers_ComInterfaceDispatch}*",
                    $"{TypeNames.System_Runtime_InteropServices_ComWrappers_ComInterfaceDispatch}*",
                    IsFunctionPointer: false);
            public IEnumerable<StatementSyntax> Generate(TypePositionInfo info, StubCodeContext codeContext, StubIdentifierContext context)
            {
                if (context.CurrentStage != StubIdentifierContext.Stage.Unmarshal)
                {
                    yield break;
                }
 
                var (managed, native) = context.GetIdentifiers(info);
 
                // <managed> = ComWrappers.ComInterfaceDispatch.GetInstance<<managedType>>(<native>);
                yield return ExpressionStatement(
                    AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
                        IdentifierName(managed),
                        InvocationExpression(
                            MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                TypeSyntaxes.System_Runtime_InteropServices_ComWrappers_ComInterfaceDispatch,
                                GenericName(
                                    Identifier("GetInstance"),
                                    TypeArgumentList(SingletonSeparatedList(info.ManagedType.Syntax)))),
                            ArgumentList(
                                SingletonSeparatedList(
                                    Argument(
                                        IdentifierName(native)))))));
            }
 
            public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) => SignatureBehavior.NativeType;
            public ValueBoundaryBehavior GetValueBoundaryBehavior(TypePositionInfo info, StubCodeContext context) => ValueBoundaryBehavior.NativeIdentifier;
            public ByValueMarshalKindSupport SupportsByValueMarshalKind(ByValueContentsMarshalKind marshalKind, TypePositionInfo info, out GeneratorDiagnostic? diagnostic)
                => ByValueMarshalKindSupportDescriptor.Default.GetSupport(marshalKind, info, out diagnostic);
            public bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context) => true;
        }
    }
}