Ejemplo n.º 1
0
 void ConvertIntPtr(AstTypeNode type)
 {
     if (type.Name == "void" && type.PointerLevel > 0)
     {
         type.Name = "IntPtr";
         type.PointerLevel--;
     }
 }
Ejemplo n.º 2
0
            protected override void VisitType(AstTypeNode type)
            {
                if (type.IsLink)
                {
                    type.PointerLevel++;
                    type.IsLink = false;
                }

                base.VisitType(type);
            }
Ejemplo n.º 3
0
        static string ConvertType(AstTypeNode type)
        {
            var name = type.Name;

            if (name == "byte")
            {
                name = "unsigned char";
            }
            else if (name == "uint")
            {
                name = "unsigned int";
            }
            return(name + new string('*', type.PointerLevel));
        }
Ejemplo n.º 4
0
            protected override void VisitType(AstTypeNode type)
            {
                if (type.IsLink)
                {
                    type.PointerLevel++;
                    type.IsLink = false;
                }

                if (_typeMap.TryGetValue(type.Name, out var mapped))
                {
                    type.Name = mapped;
                }

                base.VisitType(type);
            }
Ejemplo n.º 5
0
        static AstTypeNode ParseType(ref TokenParser parser)
        {
            var ident = parser.ParseIdentifier();
            var t     = new AstTypeNode {
                Name = ident
            };

            while (parser.TryConsume('*'))
            {
                t.PointerLevel++;
            }
            if (parser.TryConsume("&"))
            {
                t.IsLink = true;
            }
            return(t);
        }
Ejemplo n.º 6
0
        static string ConvertType(AstTypeNode type)
        {
            var name = type.Name;

            if (name == "byte")
            {
                name = "unsigned char";
            }
            else if (name == "uint")
            {
                name = "unsigned int";
            }

            type      = type.Clone();
            type.Name = name;
            return(type.Format());
        }
Ejemplo n.º 7
0
 private bool IsInterface(AstTypeNode type) => IsInterface(type.Name);
        Arg ConvertArg(string name, AstTypeNode type)
        {
            type = new AstTypeNode {
                Name = ConvertNativeType(type.Name), PointerLevel = type.PointerLevel
            };

            if (type.PointerLevel == 2)
            {
                if (IsInterface(type))
                {
                    return new InterfaceReturnArg {
                               Name = name, InterfaceType = type.Name, NativeType = "void**"
                    }
                }
                ;
            }
            else if (type.PointerLevel == 1)
            {
                if (IsInterface(type))
                {
                    return new InterfaceArg {
                               Name = name, InterfaceType = type.Name, NativeType = "void*"
                    }
                }
                ;
                if (type.Name == "char")
                {
                    return new StringArg {
                               Name = name, NativeType = "byte*"
                    }
                }
                ;
            }

            return(new BypassArg
            {
                Name = name, Type = type.Name, PointerLevel = type.PointerLevel, NativeType = type.ToString()
            });
        }

        void GenerateInterfaceMember(AstInterfaceMemberNode member, ref InterfaceDeclarationSyntax iface,
                                     ref ClassDeclarationSyntax proxy, ref ClassDeclarationSyntax vtbl,
                                     List <StatementSyntax> vtblCtor, int num)
        {
            // Prepare method information
            var  args      = member.Select(a => ConvertArg(a.Name, a.Type)).ToList();
            var  returnArg = ConvertArg("__result", member.ReturnType);
            bool isHresult = member.ReturnType.Name == "HRESULT";
            bool isHresultLastArgumentReturn = isHresult &&
                                               args.Count > 0 &&
                                               (args.Last().Name == "ppv" || args.Last().Name == "retOut" || args.Last().Name == "ret") &&
                                               ((member.Last().Type.PointerLevel > 0 &&
                                                 !IsInterface(member.Last().Type)) ||
                                                member.Last().Type.PointerLevel == 2);

            bool isVoidReturn = member.ReturnType.Name == "void" && member.ReturnType.PointerLevel == 0;


            // Generate method signature
            MethodDeclarationSyntax GenerateManagedSig(string returnType, string name,
                                                       IEnumerable <(string n, string t)> args)
            => MethodDeclaration(ParseTypeName(returnType), name).WithParameterList(
                ParameterList(
                    SeparatedList(args.Select(x => Parameter(Identifier(x.n)).WithType(ParseTypeName(x.t))))));

            var managedSig =
                isHresult ?
                GenerateManagedSig(isHresultLastArgumentReturn ? args.Last().ReturnManagedType : "void",
                                   member.Name,
                                   (isHresultLastArgumentReturn ? args.SkipLast(1) : args).Select(a => (a.Name, a.ManagedType))) :
                GenerateManagedSig(returnArg.ManagedType, member.Name, args.Select(a => (a.Name, a.ManagedType)));

            iface = iface.AddMembers(managedSig.WithSemicolonToken(Semicolon()));

            // Prepare args for marshaling
            var preMarshal = new List <StatementSyntax>();

            if (!isVoidReturn)
            {
                preMarshal.Add(ParseStatement(returnArg.NativeType + " __result;"));
            }

            for (var idx = 0; idx < args.Count; idx++)
            {
                if (isHresultLastArgumentReturn && idx == args.Count - 1)
                {
                    args[idx].PreMarshalForReturn(preMarshal);
                }
                else
                {
                    args[idx].PreMarshal(preMarshal);
                }
            }

            // Generate call expression
            ExpressionSyntax callExpr = InvocationExpression(_localInterop.GetCaller(returnArg.NativeType,
                                                                                     args.Select(x => x.NativeType).ToList()))
                                        .AddArgumentListArguments(Argument(ParseExpression("PPV")))
                                        .AddArgumentListArguments(args
                                                                  .Select((a, i) => Argument(a.Value(isHresultLastArgumentReturn && i == args.Count - 1))).ToArray())
                                        .AddArgumentListArguments(Argument(ParseExpression("(*PPV)[base.VTableSize + " + num + "]")));

            if (!isVoidReturn)
            {
                callExpr = CastExpression(ParseTypeName(returnArg.NativeType), callExpr);
            }

            // Save call result if needed
            if (!isVoidReturn)
            {
                callExpr = AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, ParseExpression("__result"),
                                                callExpr);
            }


            // Wrap call into fixed() blocks
            StatementSyntax callStatement = ExpressionStatement(callExpr);

            foreach (var arg in args)
            {
                callStatement = arg.CreateFixed(callStatement);
            }

            // Build proxy body
            var proxyBody = Block()
                            .AddStatements(preMarshal.ToArray())
                            .AddStatements(callStatement);

            // Process return value
            if (!isVoidReturn)
            {
                if (isHresult)
                {
                    proxyBody = proxyBody.AddStatements(
                        ParseStatement(
                            $"if(__result != 0) throw new System.Runtime.InteropServices.COMException(\"{member.Name} failed\", __result);"));

                    if (isHresultLastArgumentReturn)
                    {
                        proxyBody = proxyBody.AddStatements(args.Last().ReturnMarshalResult());
                    }
                }
                else
                {
                    proxyBody = proxyBody.AddStatements(returnArg.ReturnMarshalResult());
                }
            }

            // Add the proxy method
            proxy = proxy.AddMembers(managedSig.AddModifiers(SyntaxKind.PublicKeyword)
                                     .WithBody(proxyBody));


            // Generate VTable method
            var shadowDelegate = DelegateDeclaration(ParseTypeName(returnArg.NativeType), member.Name + "Delegate")
                                 .AddParameterListParameters(Parameter(Identifier("@this")).WithType(ParseTypeName("IntPtr")))
                                 .AddParameterListParameters(args.Select(x =>
                                                                         Parameter(Identifier(x.Name)).WithType(ParseTypeName(x.NativeType))).ToArray())
                                 .AddAttribute("System.Runtime.InteropServices.UnmanagedFunctionPointer",
                                               "System.Runtime.InteropServices.CallingConvention.StdCall");

            var shadowMethod = MethodDeclaration(shadowDelegate.ReturnType, member.Name)
                               .WithParameterList(shadowDelegate.ParameterList)
                               .AddModifiers(Token(SyntaxKind.StaticKeyword));

            var backPreMarshal = new List <StatementSyntax>();

            foreach (var arg in args)
            {
                arg.BackPreMarshal(backPreMarshal);
            }

            backPreMarshal.Add(
                ParseStatement($"__target = ({iface.Identifier.Text})Avalonia.MicroCom.MicroComRuntime.GetObjectFromCcw(@this);"));

            var isBackVoidReturn = isVoidReturn || (isHresult && !isHresultLastArgumentReturn);

            StatementSyntax backCallStatement;

            var backCallExpr =
                IsPropertyRewriteCandidate(managedSig) ?
                ParseExpression("__target." + member.Name.Substring(3)) :
                InvocationExpression(ParseExpression("__target." + member.Name))
                .WithArgumentList(ArgumentList(SeparatedList(
                                                   (isHresultLastArgumentReturn ? args.SkipLast(1) : args)
                                                   .Select(a =>
                                                           Argument(a.BackMarshalValue())))));

            if (isBackVoidReturn)
            {
                backCallStatement = ExpressionStatement(backCallExpr);
            }
            else
            {
                backCallStatement = LocalDeclarationStatement(DeclareVar("var", "__result", backCallExpr));
                if (isHresultLastArgumentReturn)
                {
                    backCallStatement = Block(backCallStatement,
                                              ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
                                                                                       ParseExpression("*" + args.Last().Name),
                                                                                       args.Last().BackMarshalReturn("__result")
                                                                                       )));
                }
                else
                {
                    backCallStatement = Block(backCallStatement,
                                              ReturnStatement(returnArg.BackMarshalReturn("__result")));
                }
            }

            BlockSyntax backBodyBlock = Block().AddStatements(backPreMarshal.ToArray()).AddStatements(backCallStatement);


            backBodyBlock = Block(
                TryStatement(
                    SingletonList(CatchClause(
                                      CatchDeclaration(ParseTypeName("System.Exception"), Identifier("__exception__")), null,
                                      Block(
                                          ParseStatement(
                                              "Avalonia.MicroCom.MicroComRuntime.UnhandledException(__target, __exception__);"),
                                          isHresult ? ParseStatement("return unchecked((int)0x80004005u);")
                                : isVoidReturn ? EmptyStatement() : ParseStatement("return default;")
                                          ))))
                .WithBlock(Block(backBodyBlock))
                );
            if (isHresult)
            {
                backBodyBlock = backBodyBlock.AddStatements(ParseStatement("return 0;"));
            }


            backBodyBlock = Block()
                            .AddStatements(ParseStatement($"{iface.Identifier.Text} __target = null;"))
                            .AddStatements(backBodyBlock.Statements.ToArray());

            shadowMethod = shadowMethod.WithBody(backBodyBlock);

            vtbl = vtbl.AddMembers(shadowDelegate).AddMembers(shadowMethod);
            vtblCtor.Add(ParseStatement("base.AddMethod((" + shadowDelegate.Identifier.Text + ")" +
                                        shadowMethod.Identifier.Text + ");"));
        }