Example #1
0
 public IEnumerable <StatementSyntax> GenerateSetupStatements(TypePositionInfo info, StubCodeContext context)
 {
     yield return(MarshallerHelpers.Declare(
                      _marshallerTypeSyntax,
                      context.GetAdditionalIdentifier(info, MarshallerIdentifier),
                      ImplicitObjectCreationExpression(ArgumentList(), initializer: null)));
 }
        public IEnumerable <StatementSyntax> GenerateSetupStatements(TypePositionInfo info, StubCodeContext context)
        {
            // <marshaller> = new();
            LocalDeclarationStatementSyntax declaration = MarshallerHelpers.Declare(
                _marshallerType.Syntax,
                context.GetAdditionalIdentifier(info, MarshallerIdentifier),
                ImplicitObjectCreationExpression(ArgumentList(), initializer: null));

            // For byref-like marshaller types, we'll mark them as scoped.
            // Byref-like types can capture references, so by default the compiler has to worry that
            // they could enable those references to escape the current stack frame.
            // In particular, this can interact poorly with the caller-allocated-buffer marshalling
            // support and make the simple `marshaller.FromManaged(managed, stackalloc X[i])` expression
            // illegal. Mark the marshaller type as scoped so the compiler knows that it won't escape.
            if (_marshallerType is ValueTypeInfo {
                IsByRefLike : true
            })
        /// <summary>
        /// Generate the method body of the p/invoke stub.
        /// </summary>
        /// <param name="dllImportName">Name of the target DllImport function to invoke</param>
        /// <returns>Method body of the p/invoke stub</returns>
        /// <remarks>
        /// The generated code assumes it will be in an unsafe context.
        /// </remarks>
        public BlockSyntax GeneratePInvokeBody(string dllImportName)
        {
            GeneratedStatements statements    = GeneratedStatements.Create(_marshallers, _context, IdentifierName(dllImportName));
            bool shouldInitializeVariables    = !statements.GuaranteedUnmarshal.IsEmpty || !statements.Cleanup.IsEmpty;
            VariableDeclarations declarations = VariableDeclarations.GenerateDeclarationsForManagedToNative(_marshallers, _context, shouldInitializeVariables);

            var setupStatements = new List <StatementSyntax>();

            if (_setLastError)
            {
                // Declare variable for last error
                setupStatements.Add(MarshallerHelpers.Declare(
                                        PredefinedType(Token(SyntaxKind.IntKeyword)),
                                        LastErrorIdentifier,
                                        initializeToDefault: false));
            }

            if (!statements.GuaranteedUnmarshal.IsEmpty)
            {
                setupStatements.Add(MarshallerHelpers.Declare(PredefinedType(Token(SyntaxKind.BoolKeyword)), InvokeSucceededIdentifier, initializeToDefault: true));
            }

            setupStatements.AddRange(declarations.Initializations);
            setupStatements.AddRange(declarations.Variables);
            setupStatements.AddRange(statements.Setup);

            var tryStatements = new List <StatementSyntax>();

            tryStatements.AddRange(statements.Marshal);

            BlockSyntax fixedBlock = Block(statements.PinnedMarshal);

            if (_setLastError)
            {
                StatementSyntax clearLastError = MarshallerHelpers.CreateClearLastSystemErrorStatement(SuccessErrorCode);

                StatementSyntax getLastError = MarshallerHelpers.CreateGetLastSystemErrorStatement(LastErrorIdentifier);

                fixedBlock = fixedBlock.AddStatements(clearLastError, statements.InvokeStatement, getLastError);
            }
            else
            {
                fixedBlock = fixedBlock.AddStatements(statements.InvokeStatement);
            }
            tryStatements.Add(statements.Pin.NestFixedStatements(fixedBlock));
            // <invokeSucceeded> = true;
            if (!statements.GuaranteedUnmarshal.IsEmpty)
            {
                tryStatements.Add(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
                                                                           IdentifierName(InvokeSucceededIdentifier),
                                                                           LiteralExpression(SyntaxKind.TrueLiteralExpression))));
            }

            tryStatements.AddRange(statements.NotifyForSuccessfulInvoke);
            tryStatements.AddRange(statements.Unmarshal);

            List <StatementSyntax> allStatements     = setupStatements;
            List <StatementSyntax> finallyStatements = new List <StatementSyntax>();

            if (!statements.GuaranteedUnmarshal.IsEmpty)
            {
                finallyStatements.Add(IfStatement(IdentifierName(InvokeSucceededIdentifier), Block(statements.GuaranteedUnmarshal)));
            }

            finallyStatements.AddRange(statements.Cleanup);
            if (finallyStatements.Count > 0)
            {
                // Add try-finally block if there are any statements in the finally block
                allStatements.Add(
                    TryStatement(Block(tryStatements), default, FinallyClause(Block(finallyStatements))));