using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using CppSharp.AST; using CppSharp.Generators.CSharp; using CppSharp.Types; using Type = CppSharp.AST.Type; namespace CppSharp.Generators.CLI { /// /// Generates C++/CLI source files. /// public class CLISourcesTemplate : CLITextTemplate { public CLISourcesTemplate(Driver driver, TranslationUnit unit) : base(driver, unit) { } public override void Process() { PushBlock(BlockKind.Header); PopBlock(); var file = Path.GetFileNameWithoutExtension(TranslationUnit.FileName) .Replace('\\', '/'); if (Driver.Options.GenerateName != null) file = Driver.Options.GenerateName(TranslationUnit); PushBlock(CLIBlockKind.Includes); WriteLine("#include \"{0}.h\"", file); GenerateForwardReferenceHeaders(); NewLine(); PopBlock(); PushBlock(CLIBlockKind.Usings); WriteLine("using namespace System;"); WriteLine("using namespace System::Runtime::InteropServices;"); NewLine(); PopBlock(); GenerateDeclContext(TranslationUnit); PushBlock(BlockKind.Footer); PopBlock(); } public void GenerateForwardReferenceHeaders() { PushBlock(CLIBlockKind.IncludesForwardReferences); var typeReferenceCollector = new CLITypeReferenceCollector(Driver.TypeDatabase); typeReferenceCollector.Process(TranslationUnit, filterNamespaces: false); var includes = new SortedSet(StringComparer.InvariantCulture); foreach (var typeRef in typeReferenceCollector.TypeReferences) { if (typeRef.Include.File == TranslationUnit.FileName) continue; var include = typeRef.Include; if(!string.IsNullOrEmpty(include.File) && !include.InHeader) includes.Add(include.ToString()); } foreach (var include in includes) WriteLine(include); PopBlock(); } private void GenerateDeclContext(DeclarationContext @namespace) { PushBlock(CLIBlockKind.Namespace); foreach (var @class in @namespace.Classes) { if (@class.Ignore) continue; if (@class.IsOpaque || @class.IsIncomplete) continue; GenerateClass(@class); } if (@namespace.HasFunctions) { // Generate all the function declarations for the module. foreach (var function in @namespace.Functions) { if (function.Ignore) continue; GenerateFunction(function, @namespace); NewLine(); } } if (Options.GenerateFunctionTemplates) { foreach (var template in @namespace.Templates) { if (template.Ignore) continue; var functionTemplate = template as FunctionTemplate; if (functionTemplate == null) continue; if (functionTemplate.Ignore) continue; GenerateFunctionTemplate(functionTemplate); } } foreach(var childNamespace in @namespace.Namespaces) GenerateDeclContext(childNamespace); PopBlock(); } public void GenerateClass(Class @class) { PushBlock(CLIBlockKind.Class); GenerateDeclContext(@class); // Output a default constructor that takes the native pointer. GenerateClassConstructor(@class, isIntPtr: false); GenerateClassConstructor(@class, isIntPtr: true); if (@class.IsRefType) { GenerateClassDestructor(@class); GenerateClassFinalizer(@class); } foreach (var method in @class.Methods) { if (ASTUtils.CheckIgnoreMethod(method)) continue; GenerateMethod(method, @class); } if (CSharpTextTemplate.ShouldGenerateClassNativeField(@class)) { PushBlock(CLIBlockKind.Method); WriteLine("System::IntPtr {0}::{1}::get()", QualifiedIdentifier(@class), Helpers.InstanceIdentifier); WriteStartBraceIndent(); WriteLine("return System::IntPtr(NativePtr);"); WriteCloseBraceIndent(); PopBlock(NewLineKind.BeforeNextBlock); PushBlock(CLIBlockKind.Method); WriteLine("void {0}::{1}::set(System::IntPtr object)", QualifiedIdentifier(@class), Helpers.InstanceIdentifier); WriteStartBraceIndent(); var nativeType = string.Format("::{0}*", @class.QualifiedOriginalName); WriteLine("NativePtr = ({0})object.ToPointer();", nativeType); WriteCloseBraceIndent(); PopBlock(NewLineKind.BeforeNextBlock); } GenerateClassProperties(@class, @class); foreach (var @event in @class.Events) { if (@event.Ignore) continue; GenerateDeclarationCommon(@event); GenerateEvent(@event, @class); } foreach (var variable in @class.Variables) { if (variable.Ignore) continue; if (variable.Access != AccessSpecifier.Public) continue; GenerateDeclarationCommon(variable); GenerateVariable(variable, @class); } PopBlock(); } private void GenerateClassProperties(Class @class, Class realOwner) { if (@class.IsValueType) { foreach (var @base in @class.Bases.Where(b => b.IsClass && !b.Class.Ignore)) { GenerateClassProperties(@base.Class, realOwner); } } foreach (var property in @class.Properties.Where( p => !p.Ignore && !p.IsInRefTypeAndBackedByValueClassField())) GenerateProperty(property, realOwner); } private void GenerateClassDestructor(Class @class) { if (!Options.GenerateFinalizers) return; PushBlock(CLIBlockKind.Destructor); WriteLine("{0}::~{1}()", QualifiedIdentifier(@class), @class.Name); WriteStartBraceIndent(); if (CSharpTextTemplate.ShouldGenerateClassNativeField(@class)) WriteLine("delete NativePtr;"); WriteCloseBraceIndent(); PopBlock(NewLineKind.BeforeNextBlock); } private void GenerateClassFinalizer(Class @class) { if (!Options.GenerateFinalizers) return; PushBlock(CLIBlockKind.Finalizer); WriteLine("{0}::!{1}()", QualifiedIdentifier(@class), @class.Name); WriteStartBraceIndent(); if (CSharpTextTemplate.ShouldGenerateClassNativeField(@class)) WriteLine("delete NativePtr;"); WriteCloseBraceIndent(); PopBlock(NewLineKind.BeforeNextBlock); } private void GenerateFunctionTemplate(FunctionTemplate template) { var printer = TypePrinter; var oldCtx = printer.Context; PushBlock(CLIBlockKind.Template); var function = template.TemplatedFunction; var typeCtx = new CLITypePrinterContext() { Kind = TypePrinterContextKind.Template, Declaration = template }; printer.Context = typeCtx; var typePrinter = new CLITypePrinter(Driver, typeCtx); var retType = function.ReturnType.Type.Visit(typePrinter, function.ReturnType.Qualifiers); var typeNames = ""; var paramNames = template.Parameters.Select(param => param.Name).ToList(); if (paramNames.Any()) typeNames = "typename " + string.Join(", typename ", paramNames); WriteLine("generic<{0}>", typeNames); WriteLine("{0} {1}::{2}({3})", retType, QualifiedIdentifier(function.Namespace), SafeIdentifier(function.Name), GenerateParametersList(function.Parameters)); WriteStartBraceIndent(); var @class = function.Namespace as Class; GenerateFunctionCall(function, @class); WriteCloseBraceIndent(); NewLine(); PopBlock(NewLineKind.BeforeNextBlock); printer.Context = oldCtx; } private void GenerateProperty(Property property, Class realOwner) { if (property.Ignore) return; PushBlock(CLIBlockKind.Property); var @class = property.Namespace as Class; if (property.Field != null) { if (property.HasGetter) GeneratePropertyGetter(property.Field, realOwner, property.Name, property.Type); if (property.HasSetter) GeneratePropertySetter(property.Field, realOwner, property.Name, property.Type); } else { if (property.HasGetter) GeneratePropertyGetter(property.GetMethod, realOwner, property.Name, property.Type); if (property.HasSetter) GeneratePropertySetter(property.SetMethod, realOwner, property.Name, property.Type); } PopBlock(); } private void GeneratePropertySetter(T decl, Class @class, string name, Type type) where T : Declaration, ITypedDecl { if (decl == null) return; WriteLine("void {0}::{1}::set({2} value)", QualifiedIdentifier(@class), name, type); WriteStartBraceIndent(); if (decl is Function) { var func = decl as Function; if(func.Parameters[0].Name != "value") WriteLine("auto {0} = value;", func.Parameters[0].Name); GenerateFunctionCall(func, @class); } else { if (@class.IsValueType && decl is Field) { WriteLine("{0} = value;", decl.Name); WriteCloseBraceIndent(); NewLine(); return; } var param = new Parameter { Name = "value", QualifiedType = decl.QualifiedType }; var ctx = new MarshalContext(Driver) { Parameter = param, ArgName = param.Name, }; var marshal = new CLIMarshalManagedToNativePrinter(ctx); param.Visit(marshal); string variable; if (decl is Variable) variable = string.Format("::{0}::{1}", @class.QualifiedOriginalName, decl.OriginalName); else variable = string.Format("((::{0}*)NativePtr)->{1}", @class.QualifiedOriginalName, decl.OriginalName); if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) Write(marshal.Context.SupportBefore); WriteLine("{0} = {1};", variable, marshal.Context.Return); } WriteCloseBraceIndent(); NewLine(); } private void GeneratePropertyGetter(T decl, Class @class, string name, Type type) where T : Declaration, ITypedDecl { if (decl == null) return; WriteLine("{0} {1}::{2}::get()", type, QualifiedIdentifier(@class), name); WriteStartBraceIndent(); if (decl is Function) { var func = decl as Function; GenerateFunctionCall(func, @class); } else { if (@class.IsValueType && decl is Field) { WriteLine("return {0};", decl.Name); WriteCloseBraceIndent(); NewLine(); return; } string variable; if (decl is Variable) variable = string.Format("::{0}::{1}", @class.QualifiedOriginalName, decl.OriginalName); else variable = string.Format("((::{0}*)NativePtr)->{1}", @class.QualifiedOriginalName, decl.OriginalName); var ctx = new MarshalContext(Driver) { Declaration = decl, ArgName = decl.Name, ReturnVarName = variable, ReturnType = decl.QualifiedType }; var marshal = new CLIMarshalNativeToManagedPrinter(ctx); decl.Visit(marshal); if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) Write(marshal.Context.SupportBefore); WriteLine("return {0};", marshal.Context.Return); } WriteCloseBraceIndent(); NewLine(); } private void GenerateEvent(Event @event, Class @class) { GenerateEventAdd(@event, @class); NewLine(); GenerateEventRemove(@event, @class); NewLine(); GenerateEventRaise(@event, @class); NewLine(); GenerateEventRaiseWrapper(@event, @class); NewLine(); } private void GenerateEventAdd(Event @event, Class @class) { WriteLine("void {0}::{1}::add({2} evt)", QualifiedIdentifier(@class), @event.Name, @event.Type); WriteStartBraceIndent(); var delegateName = string.Format("_{0}Delegate", @event.Name); WriteLine("if (!{0}Instance)", delegateName); WriteStartBraceIndent(); var typePrinter = new CppTypePrinter(Driver.TypeDatabase); var args = typePrinter.VisitParameters(@event.Parameters, hasNames: false); WriteLine("{0}Instance = gcnew {0}(this, &{1}::_{2}Raise);", delegateName, QualifiedIdentifier(@class), @event.Name); WriteLine("auto _fptr = (void (*)({0}))Marshal::GetFunctionPointerForDelegate({1}Instance).ToPointer();", args, delegateName); WriteLine("((::{0}*)NativePtr)->{1}.Connect(_fptr);", @class.QualifiedOriginalName, @event.OriginalName); WriteCloseBraceIndent(); WriteLine("_{0} = static_cast<{1}>(System::Delegate::Combine(_{0}, evt));", @event.Name, @event.Type); WriteCloseBraceIndent(); } private void GenerateEventRemove(Event @event, Class @class) { WriteLine("void {0}::{1}::remove({2} evt)", QualifiedIdentifier(@class), @event.Name, @event.Type); WriteStartBraceIndent(); WriteLine("_{0} = static_cast<{1}>(System::Delegate::Remove(_{0}, evt));", @event.Name, @event.Type); WriteCloseBraceIndent(); } private void GenerateEventRaise(Event @event, Class @class) { var typePrinter = new CLITypePrinter(Driver); var args = typePrinter.VisitParameters(@event.Parameters, hasNames: true); WriteLine("void {0}::{1}::raise({2})", QualifiedIdentifier(@class), @event.Name, args); WriteStartBraceIndent(); var paramNames = @event.Parameters.Select(param => param.Name).ToList(); WriteLine("_{0}({1});", @event.Name, string.Join(", ", paramNames)); WriteCloseBraceIndent(); } private void GenerateEventRaiseWrapper(Event @event, Class @class) { var typePrinter = new CppTypePrinter(Driver.TypeDatabase); var args = typePrinter.VisitParameters(@event.Parameters, hasNames: true); WriteLine("void {0}::_{1}Raise({2})", QualifiedIdentifier(@class), @event.Name, args); WriteStartBraceIndent(); var returns = new List(); foreach (var param in @event.Parameters) { var ctx = new MarshalContext(Driver) { ReturnVarName = param.Name, ReturnType = param.QualifiedType }; var marshal = new CLIMarshalNativeToManagedPrinter(ctx); param.Visit(marshal); returns.Add(marshal.Context.Return); } Write("{0}::raise(", @event.Name); Write("{0}", string.Join(", ", returns)); WriteLine(");"); WriteCloseBraceIndent(); } private void GenerateVariable(Variable variable, Class @class) { GeneratePropertyGetter(variable, @class, variable.Name, variable.Type); if (!variable.QualifiedType.Qualifiers.IsConst) GeneratePropertySetter(variable, @class, variable.Name, variable.Type); } private void GenerateClassConstructor(Class @class, bool isIntPtr) { Write("{0}::{1}(", QualifiedIdentifier(@class), SafeIdentifier(@class.Name)); var nativeType = string.Format("::{0}*", @class.QualifiedOriginalName); WriteLine("{0} native)", isIntPtr ? "System::IntPtr" : nativeType); var hasBase = GenerateClassConstructorBase(@class, isIntPtr); WriteStartBraceIndent(); var nativePtr = "native"; if (isIntPtr) { WriteLine("auto __native = (::{0}*)native.ToPointer();", @class.QualifiedOriginalName); nativePtr = "__native"; } if (@class.IsRefType) { if (!hasBase) { WriteLine("NativePtr = {0};", nativePtr); } } else { GenerateStructMarshaling(@class, nativePtr + "->"); } WriteCloseBraceIndent(); NewLine(); } private void GenerateStructMarshaling(Class @class, string nativeVar) { foreach (var @base in @class.Bases) { if (!@base.IsClass || @base.Class.Ignore) continue; var baseClass = @base.Class; GenerateStructMarshaling(baseClass, nativeVar); } foreach (var property in @class.Properties) { if (property.Ignore || property.Field == null) continue; var nativeField = string.Format("{0}{1}", nativeVar, property.Field.OriginalName); var ctx = new MarshalContext(Driver) { ArgName = property.Name, ReturnVarName = nativeField, ReturnType = property.QualifiedType }; var marshal = new CLIMarshalNativeToManagedPrinter(ctx); property.Visit(marshal); if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) Write(marshal.Context.SupportBefore); WriteLine("{0} = {1};", property.Field.Name, marshal.Context.Return); } } private bool GenerateClassConstructorBase(Class @class, bool isIntPtr, Method method = null) { var hasBase = @class.HasBase && @class.Bases[0].IsClass && !@class.Bases[0].Class.Ignore; if (!hasBase) return false; if (!@class.IsValueType) { PushIndent(); var baseClass = @class.Bases[0].Class; Write(": {0}(", QualifiedIdentifier(baseClass)); // We cast the value to the base clas type since otherwise there // could be ambiguous call to overloaded constructors. if (!isIntPtr) { var cppTypePrinter = new CppTypePrinter(Driver.TypeDatabase); var nativeTypeName = baseClass.Visit(cppTypePrinter); Write("({0}*)", nativeTypeName); } WriteLine("{0})", method != null ? "nullptr" : "native"); PopIndent(); } return true; } public void GenerateMethod(Method method, Class @class) { PushBlock(CLIBlockKind.Method, method); if (method.IsConstructor || method.IsDestructor || method.OperatorKind == CXXOperatorKind.Conversion) Write("{0}::{1}(", QualifiedIdentifier(@class), GetMethodName(method)); else Write("{0} {1}::{2}(", method.ReturnType, QualifiedIdentifier(@class), SafeIdentifier(method.Name)); GenerateMethodParameters(method); WriteLine(")"); if (method.IsConstructor) GenerateClassConstructorBase(@class, isIntPtr: false, method: method); WriteStartBraceIndent(); PushBlock(CLIBlockKind.MethodBody, method); if (method.IsProxy) goto SkipImpl; if (@class.IsRefType) { if (method.IsConstructor) { if (!@class.IsAbstract) { var @params = GenerateFunctionParamsMarshal(method.Parameters, method); Write("NativePtr = new ::{0}(", method.Namespace.QualifiedOriginalName); GenerateFunctionParams(@params); WriteLine(");"); } } else { GenerateFunctionCall(method, @class); } } else if (@class.IsValueType) { if (!method.IsConstructor) GenerateFunctionCall(method, @class); else GenerateValueTypeConstructorCall(method, @class); } SkipImpl: PopBlock(); WriteCloseBraceIndent(); PopBlock(NewLineKind.Always); } private void GenerateValueTypeConstructorCall(Method method, Class @class) { var names = new List(); var paramIndex = 0; foreach (var param in method.Parameters) { var ctx = new MarshalContext(Driver) { Function = method, Parameter = param, ArgName = param.Name, ParameterIndex = paramIndex++ }; var marshal = new CLIMarshalManagedToNativePrinter(ctx); param.Visit(marshal); if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) Write(marshal.Context.SupportBefore); names.Add(marshal.Context.Return); } WriteLine("::{0} _native({1});", @class.QualifiedOriginalName, string.Join(", ", names)); GenerateValueTypeConstructorCallProperties(@class); } private void GenerateValueTypeConstructorCallProperties(Class @class) { foreach (var @base in @class.Bases) { if (!@base.IsClass || @base.Class.Ignore) continue; var baseClass = @base.Class; GenerateValueTypeConstructorCallProperties(baseClass); } foreach (var property in @class.Properties) { if (property.Ignore || property.Field == null) continue; var varName = string.Format("_native.{0}", property.Field.OriginalName); var ctx = new MarshalContext(Driver) { ReturnVarName = varName, ReturnType = property.QualifiedType }; var marshal = new CLIMarshalNativeToManagedPrinter(ctx); property.Visit(marshal); if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) Write(marshal.Context.SupportBefore); WriteLine("this->{0} = {1};", property.Name, marshal.Context.Return); } } public void GenerateFunction(Function function, DeclarationContext @namespace) { if (function.Ignore) return; GenerateDeclarationCommon(function); var classSig = string.Format("{0}{1}{2}", QualifiedIdentifier(@namespace), Options.OutputNamespace, TranslationUnit.FileNameWithoutExtension); Write("{0} {1}::{2}(", function.ReturnType, classSig, SafeIdentifier(function.Name)); for (var i = 0; i < function.Parameters.Count; ++i) { var param = function.Parameters[i]; Write("{0}", TypePrinter.VisitParameter(param)); if (i < function.Parameters.Count - 1) Write(", "); } WriteLine(")"); WriteStartBraceIndent(); GenerateFunctionCall(function); WriteCloseBraceIndent(); } public void GenerateFunctionCall(Function function, Class @class = null) { var retType = function.ReturnType; var needsReturn = !retType.Type.IsPrimitiveType(PrimitiveType.Void); const string valueMarshalName = "_this0"; var isValueType = @class != null && @class.IsValueType; if (isValueType && !IsNativeFunctionOrStaticMethod(function)) { WriteLine("auto {0} = ::{1}();", valueMarshalName, @class.QualifiedOriginalName); var param = new Parameter { Name = "(*this)" }; var ctx = new MarshalContext(Driver) { MarshalVarPrefix = valueMarshalName, Parameter = param }; var marshal = new CLIMarshalManagedToNativePrinter(ctx); marshal.MarshalValueClassProperties(@class, valueMarshalName); if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) Write(marshal.Context.SupportBefore); } var @params = GenerateFunctionParamsMarshal(function.Parameters, function); if (needsReturn) Write("auto {0}{1} = ",(function.ReturnType.Type.IsReference())? "&": string.Empty, Generator.GeneratedIdentifier("ret")); if (function.OperatorKind == CXXOperatorKind.Conversion) { var method = function as Method; var typePrinter = new CppTypePrinter(Driver.TypeDatabase); var typeName = method.ConversionType.Visit(typePrinter); WriteLine("({0}) {1};", typeName, @params[0].Name); } else if (function.IsOperator) { 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("::{0}(", function.QualifiedOriginalName); } else { if (isValueType) Write("{0}.", valueMarshalName); else if (IsNativeMethod(function)) Write("((::{0}*)NativePtr)->", @class.QualifiedOriginalName); 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; var nativeVarName = paramInfo.Name; var ctx = new MarshalContext(Driver) { ArgName = nativeVarName, ReturnVarName = nativeVarName, ReturnType = param.QualifiedType }; var marshal = new CLIMarshalNativeToManagedPrinter(ctx); param.Visit(marshal); if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) Write(marshal.Context.SupportBefore); WriteLine("{0} = {1};",param.Name,marshal.Context.Return); } if (isValueType && !IsNativeFunctionOrStaticMethod(function)) { GenerateStructMarshaling(@class, valueMarshalName + "."); } if (needsReturn) { var retTypeName = retType.Visit(TypePrinter); var isIntPtr = retTypeName.Contains("IntPtr"); if (retType.Type.IsPointer() && (isIntPtr || retTypeName.EndsWith("^"))) { WriteLine("if ({0} == nullptr) return {1};", Generator.GeneratedIdentifier("ret"), isIntPtr ? "System::IntPtr()" : "nullptr"); } var ctx = new MarshalContext(Driver) { ArgName = Generator.GeneratedIdentifier("ret"), ReturnVarName = Generator.GeneratedIdentifier("ret"), ReturnType = retType }; var marshal = new CLIMarshalNativeToManagedPrinter(ctx); function.ReturnType.Visit(marshal); if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) Write(marshal.Context.SupportBefore); WriteLine("return {0};", marshal.Context.Return); } } private static bool IsNativeMethod(Function function) { var method = function as Method; if (method == null) return false; return method.Conversion == MethodConversionKind.None; } private static bool IsNativeFunctionOrStaticMethod(Function function) { var method = function as Method; if (method == null) return true; if (method.IsOperator && Operators.IsBuiltinOperator(method.OperatorKind)) return true; return method.IsStatic || method.Conversion != MethodConversionKind.None; } public struct ParamMarshal { public string Name; public string Prefix; public Parameter Param; } public List GenerateFunctionParamsMarshal(IEnumerable @params, Function function = null) { var marshals = new List(); var paramIndex = 0; foreach (var param in @params) { marshals.Add(GenerateFunctionParamMarshal(param, paramIndex, function)); paramIndex++; } return marshals; } private ParamMarshal GenerateFunctionParamMarshal(Parameter param, int paramIndex, Function function = null) { var paramMarshal = new ParamMarshal { Name = param.Name, Param = param }; if (param.Type is BuiltinType) return paramMarshal; var argName = "arg" + paramIndex.ToString(CultureInfo.InvariantCulture); if (param.IsOut || param.IsInOut) { var paramType = param.Type; if (paramType is PointerType) { if (!paramType.IsReference()) paramMarshal.Prefix = "&"; paramType = (paramType as PointerType).Pointee; } var typePrinter = new CppTypePrinter(Driver.TypeDatabase); var type = paramType.Visit(typePrinter); WriteLine("{0} {1};", type, argName); } else { var ctx = new MarshalContext(Driver) { Parameter = param, ParameterIndex = paramIndex, ArgName = argName, Function = function }; var marshal = new CLIMarshalManagedToNativePrinter(ctx); param.Visit(marshal); if (string.IsNullOrEmpty(marshal.Context.Return)) throw new Exception(string.Format("Cannot marshal argument of function '{0}'", function.QualifiedOriginalName)); if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) Write(marshal.Context.SupportBefore); WriteLine("auto {0}{1} = {2};", marshal.VarPrefix, argName, marshal.Context.Return); argName = marshal.ArgumentPrefix + argName; } paramMarshal.Name = argName; return paramMarshal; } public void GenerateFunctionParams(List @params) { var names = @params.Select(param => { if (!string.IsNullOrWhiteSpace(param.Prefix)) return param.Prefix + param.Name; return param.Name; }).ToList(); Write(string.Join(", ", names)); } public override string FileExtension { get { return "cpp"; } } } }