| File: UnmanagedToManagedStubGenerator.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. using System.Collections.Immutable; using System.Diagnostics; namespace Microsoft.Interop { public sealed class UnmanagedToManagedStubGenerator { private const string ReturnIdentifier = "__retVal"; private readonly BoundGenerators _marshallers; private readonly StubIdentifierContext _context; public UnmanagedToManagedStubGenerator( ImmutableArray<TypePositionInfo> argTypes, GeneratorDiagnosticsBag diagnosticsBag, IMarshallingGeneratorResolver generatorResolver) { _marshallers = BoundGenerators.Create(argTypes, generatorResolver, StubCodeContext.DefaultNativeToManagedStub, new Forwarder(), out var bindingDiagnostics); diagnosticsBag.ReportGeneratorDiagnostics(bindingDiagnostics); if (_marshallers.NativeReturnMarshaller.UsesNativeIdentifier) { _context = new DefaultIdentifierContext(ReturnIdentifier, $"{ReturnIdentifier}{StubIdentifierContext.GeneratedNativeIdentifierSuffix}", MarshalDirection.UnmanagedToManaged); } else { _context = new DefaultIdentifierContext(ReturnIdentifier, ReturnIdentifier, MarshalDirection.UnmanagedToManaged); } } /// <summary>Generates the braced body of an unmanaged-to-managed method stub.</summary> /// <param name="methodToInvoke">The managed method access expression.</param> /// <returns>The method body, which requires an unsafe context.</returns> public string GenerateStubBodyForMethod(string methodToInvoke) { GeneratedStatements statements = GeneratedStatements.Create( _marshallers, StubCodeContext.DefaultNativeToManagedStub, _context, methodToInvoke); return BuildBodyFromStatements(statements); } /// <summary>Generates a property accessor body.</summary> /// <param name="propertyAccess">The managed property access expression.</param> /// <param name="isSetter">True for a setter; false for a getter.</param> /// <returns>The accessor body.</returns> public string GenerateStubBodyForProperty(string propertyAccess, bool isSetter) { GeneratedStatements statements = GeneratedStatements.CreateForProperty(_marshallers, _context, propertyAccess, isSetter); return BuildBodyFromStatements(statements); } /// <summary>Generates an indexer accessor using the marshalled index arguments.</summary> /// <param name="instance">The managed target instance expression.</param> /// <param name="isSetter">True for a setter; false for a getter.</param> /// <returns>The accessor body.</returns> public string GenerateStubBodyForIndexer(string instance, bool isSetter) { ImmutableArray<IBoundMarshallingGenerator> parameters = _marshallers.ManagedParameterMarshallers; int indexCount = isSetter ? parameters.Length - 1 : parameters.Length; var arguments = new string[indexCount]; for (int i = 0; i < indexCount; i++) { arguments[i] = parameters[i].AsManagedArgument(_context); } return GenerateStubBodyForProperty($"{instance}[{string.Join(", ", arguments)}]", isSetter); } private string BuildBodyFromStatements(GeneratedStatements statements) { Debug.Assert(statements.CleanupCalleeAllocated.Length == 0); bool shouldInitializeVariables = statements.GuaranteedUnmarshal.Length != 0 || statements.CleanupCallerAllocated.Length != 0 || statements.ManagedExceptionCatchClauses.Length != 0; VariableDeclarations declarations = VariableDeclarations.GenerateDeclarationsForUnmanagedToManaged(_marshallers, _context, shouldInitializeVariables); var writer = new IndentedTextWriter(); using (writer.WriteBlock()) { writer.Write(declarations.Initializations); writer.Write(declarations.Variables); writer.Write(statements.Setup); bool needsTry = statements.ManagedExceptionCatchClauses.Length != 0 || statements.CleanupCallerAllocated.Length != 0; if (needsTry) { writer.WriteLine("try"); using (writer.WriteBlock()) { WriteTryStatements(); } writer.Write(statements.ManagedExceptionCatchClauses); if (statements.CleanupCallerAllocated.Length != 0) { writer.WriteLine("finally"); using (writer.WriteBlock()) { writer.Write(statements.CleanupCallerAllocated); } } } else { WriteTryStatements(); } if (!_marshallers.IsUnmanagedVoidReturn) { writer.WriteLine($"return {_context.GetIdentifiers(_marshallers.NativeReturnMarshaller.TypeInfo).native};"); } } return writer.ToString(); void WriteTryStatements() { writer.Write(statements.ErrorUnmarshalCapture); writer.Write(statements.ErrorUnmarshal); writer.Write(statements.GuaranteedUnmarshal); writer.Write(statements.Unmarshal); writer.Write(statements.InvokeStatement); writer.Write(statements.NotifyForSuccessfulInvoke); writer.Write(statements.Marshal); writer.Write(statements.PinnedMarshal); } } public GeneratedMethodSignature GenerateAbiMethodSignatureData() { return _marshallers.GenerateTargetMethodSignatureData(_context); } } }