public void GenerateFunctionCall(Function function, Class @class = null, Type publicRetType = null) { CheckArgumentRange(function); if (function.OperatorKind == CXXOperatorKind.EqualEqual || function.OperatorKind == CXXOperatorKind.ExclaimEqual) { WriteLine("bool {0}Null = ReferenceEquals({0}, nullptr);", function.Parameters[0].Name); WriteLine("bool {0}Null = ReferenceEquals({0}, nullptr);", function.Parameters[1].Name); WriteLine("if ({0}Null || {1}Null)", function.Parameters[0].Name, function.Parameters[1].Name); WriteLineIndent("return {0}{1}Null && {2}Null{3};", function.OperatorKind == CXXOperatorKind.EqualEqual ? string.Empty : "!(", function.Parameters[0].Name, function.Parameters[1].Name, function.OperatorKind == CXXOperatorKind.EqualEqual ? string.Empty : ")"); } var retType = function.ReturnType; if (publicRetType == null) { publicRetType = retType.Type; } var needsReturn = !publicRetType.IsPrimitiveType(PrimitiveType.Void); const string valueMarshalName = "_this0"; var isValueType = @class != null && @class.IsValueType; if (isValueType && !IsNativeFunctionOrStaticMethod(function)) { WriteLine($"auto {valueMarshalName} = {typePrinter.PrintTag(@class)}::{@class.QualifiedOriginalName}();"); var param = new Parameter { Name = "(*this)", Namespace = function.Namespace }; var ctx = new MarshalContext(Context, CurrentIndentation) { Parameter = param }; ctx.VarPrefix.Write(valueMarshalName); var marshal = new CLIMarshalManagedToNativePrinter(ctx); marshal.MarshalValueClassProperties(@class, valueMarshalName); if (!string.IsNullOrWhiteSpace(marshal.Context.Before)) { Write(marshal.Context.Before); } } var @params = GenerateFunctionParamsMarshal(function.Parameters, function); var returnIdentifier = Helpers.ReturnIdentifier; if (needsReturn) { if (retType.Type.IsReference()) { Write("auto &{0} = ", returnIdentifier); } else { Write("auto {0} = ", returnIdentifier); } } if (function.OperatorKind == CXXOperatorKind.Conversion || function.OperatorKind == CXXOperatorKind.ExplicitConversion) { var method = function as Method; var typeName = method.ConversionType.Visit(new CppTypePrinter(Context)); WriteLine("({0}) {1};", typeName, @params[0].Name); } else if (function.IsOperator && function.OperatorKind != CXXOperatorKind.Subscript) { var opName = function.Name.Replace("operator", "").Trim(); switch (Operators.ClassifyOperator(function)) { case CXXOperatorArity.Unary: WriteLine("{0} {1};", opName, @params[0].Name); break; case CXXOperatorArity.Binary: WriteLine("{0} {1} {2};", @params[0].Name, opName, @params[1].Name); break; } } else { if (IsNativeFunctionOrStaticMethod(function)) { Write($"::{function.QualifiedOriginalName}("); } else { if (isValueType) { Write($"{valueMarshalName}."); } else if (IsNativeMethod(function)) { Write($"(({typePrinter.PrintTag(@class)}::{@class.QualifiedOriginalName}*)NativePtr)->"); } Write("{0}(", function.OriginalName); } GenerateFunctionParams(@params); WriteLine(");"); } foreach (var paramInfo in @params) { var param = paramInfo.Param; if (param.Usage != ParameterUsage.Out && param.Usage != ParameterUsage.InOut) { continue; } if (param.Type.IsPointer() && !param.Type.GetFinalPointee().IsPrimitiveType()) { param.QualifiedType = new QualifiedType(param.Type.GetFinalPointee()); } var nativeVarName = paramInfo.Name; var ctx = new MarshalContext(Context, CurrentIndentation) { ArgName = nativeVarName, ReturnVarName = nativeVarName, ReturnType = param.QualifiedType }; var marshal = new CLIMarshalNativeToManagedPrinter(ctx); param.Visit(marshal); if (!string.IsNullOrWhiteSpace(marshal.Context.Before)) { Write(marshal.Context.Before); } WriteLine("{0} = {1};", param.Name, marshal.Context.Return); } if (isValueType && !IsNativeFunctionOrStaticMethod(function)) { GenerateStructMarshaling(@class, valueMarshalName + "."); } if (needsReturn) { var retTypeName = retType.Visit(CTypePrinter).ToString(); var isIntPtr = retTypeName.Contains("IntPtr"); if (retType.Type.IsPointer() && (isIntPtr || retTypeName.EndsWith("^", StringComparison.Ordinal))) { WriteLine("if ({0} == nullptr) return {1};", returnIdentifier, isIntPtr ? "::System::IntPtr()" : "nullptr"); } var ctx = new MarshalContext(Context, CurrentIndentation) { ArgName = returnIdentifier, ReturnVarName = returnIdentifier, ReturnType = retType }; var marshal = new CLIMarshalNativeToManagedPrinter(ctx); retType.Visit(marshal); if (!string.IsNullOrWhiteSpace(marshal.Context.Before)) { Write(marshal.Context.Before); } // Special case for indexer - needs to dereference if the internal // function is a pointer type and the property is not. if (retType.Type.IsPointer() && retType.Type.GetPointee().Equals(publicRetType) && publicRetType.IsPrimitiveType()) { WriteLine("return *({0});", marshal.Context.Return); } else if (retType.Type.IsReference() && publicRetType.IsReference()) { WriteLine("return ({0})({1});", publicRetType, marshal.Context.Return); } else { WriteLine("return {0};", marshal.Context.Return); } } }