diff --git a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs index 10200a87..9ab82ef4 100644 --- a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs +++ b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs @@ -1,7 +1,8 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; +using System.Linq; +using Cxxi.Types; namespace Cxxi.Generators.CLI { @@ -225,6 +226,7 @@ namespace Cxxi.Generators.CLI if (@class.IsRefType) GenerateClassProperties(@class); + GenerateClassEvents(@class); GenerateClassMethods(@class); WriteLine("};"); @@ -280,7 +282,8 @@ namespace Cxxi.Generators.CLI if (!baseClass.IsValueType || baseClass.Ignore) { - Console.WriteLine("Ignored base class of value type '{0}'", baseClass.Name); + Console.WriteLine("Ignored base class of value type '{0}'", + baseClass.Name); continue; } @@ -288,6 +291,49 @@ namespace Cxxi.Generators.CLI } } + public void GenerateClassEvents(Class @class) + { + PushIndent(); + foreach (var @event in @class.Events) + { + if (@event.Ignore) continue; + + var typePrinter = new CppTypePrinter(Driver.TypeDatabase, Library); + + var @params = GetEventParameters(@event); + var args = typePrinter.VisitParameters(@params, hasNames: true); + + PopIndent(); + WriteLine("private:"); + PushIndent(); + + var delegateName = string.Format("_{0}Delegate", @event.Name); + WriteLine("delegate void {0}({1});", delegateName, args); + WriteLine("{0}^ {0}Instance;", delegateName); + + WriteLine("void _{0}Raise({1});", @event.Name, args); + WriteLine("{0} _{1};", @event.Type, @event.Name); + + PopIndent(); + WriteLine("public:"); + PushIndent(); + + WriteLine("event {0} {1}", @event.Type, @event.Name); + WriteStartBraceIndent(); + + WriteLine("void add({0} evt);", @event.Type); + WriteLine("void remove({0} evt);", @event.Type); + + var paramNames = @event.Parameters.Select(param => param.ToString()). + ToList(); + var parameters = string.Join(", ", paramNames); + + WriteLine("void raise({0});", parameters); + WriteCloseBraceIndent(); + } + PopIndent(); + } + public void GenerateClassMethods(Class @class) { PushIndent(); diff --git a/src/Generator/Generators/CLI/CLISourcesTemplate.cs b/src/Generator/Generators/CLI/CLISourcesTemplate.cs index e4ee8f2e..16c347a3 100644 --- a/src/Generator/Generators/CLI/CLISourcesTemplate.cs +++ b/src/Generator/Generators/CLI/CLISourcesTemplate.cs @@ -129,6 +129,126 @@ namespace Cxxi.Generators.CLI NewLine(); } + + foreach (var @event in @class.Events) + { + GenerateDeclarationCommon(@event); + GenerateEvent(@event, @class); + } + } + + 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, Library); + + var @params = GetEventParameters(@event); + var args = typePrinter.VisitParameters(@params, 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.TypeDatabase, Library); + + var @params = GetEventParameters(@event); + var args = typePrinter.VisitParameters(@params, hasNames: true); + + WriteLine("void {0}::{1}::raise({2})", QualifiedIdentifier(@class), + @event.Name, args); + + WriteStartBraceIndent(); + + var paramNames = @params.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, Library); + + var @params = GetEventParameters(@event); + var args = typePrinter.VisitParameters(@params, hasNames: true); + + WriteLine("void {0}::_{1}Raise({2})", QualifiedIdentifier(@class), + @event.Name, args); + + WriteStartBraceIndent(); + + var returns = new List(); + foreach (var param in @params) + { + var ctx = new MarshalContext() + { + ReturnVarName = param.Name, + ReturnType = param.Type + }; + + var marshal = new CLIMarshalNativeToManagedPrinter( + Driver.TypeDatabase, Library, ctx); + + param.Visit(marshal); + + returns.Add(marshal.Return); + } + + Write("{0}::raise(", @event.Name); + Write("{0}", string.Join(", ", returns)); + WriteLine(");"); + + WriteCloseBraceIndent(); } private void GenerateClassConstructor(Class @class, bool isIntPtr) diff --git a/src/Generator/Generators/CLI/CLITextTemplate.cs b/src/Generator/Generators/CLI/CLITextTemplate.cs index e75b5edb..df68f546 100644 --- a/src/Generator/Generators/CLI/CLITextTemplate.cs +++ b/src/Generator/Generators/CLI/CLITextTemplate.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Cxxi.Types; namespace Cxxi.Generators.CLI @@ -121,6 +122,21 @@ namespace Cxxi.Generators.CLI return false; } + public static List GetEventParameters(Event @event) + { + var i = 0; + var @params = new List(); + foreach (var type in @event.Parameters) + { + @params.Add(new Parameter() + { + Name = string.Format("_{0}", i++), + QualifiedType = type + }); + } + return @params; + } + public abstract override string FileExtension { get; } public abstract override void Generate();