void ConvertIntPtr(AstTypeNode type) { if (type.Name == "void" && type.PointerLevel > 0) { type.Name = "IntPtr"; type.PointerLevel--; } }
protected override void VisitType(AstTypeNode type) { if (type.IsLink) { type.PointerLevel++; type.IsLink = false; } base.VisitType(type); }
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)); }
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); }
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); }
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()); }
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 + ");")); }