From d4e4aaffad3d90a2db918bdf3e8d8e7fa00200d1 Mon Sep 17 00:00:00 2001 From: Tom Spilman Date: Mon, 11 Aug 2014 18:24:47 -0500 Subject: [PATCH 1/4] Fixed CLI and CSharp support for out parameter const char strings. Added test for out parameter const char strings. --- src/Generator/Generators/CLI/CLIMarshal.cs | 18 +++++++++--------- src/Generator/Generators/CLI/CLITypePrinter.cs | 3 +-- .../Generators/CSharp/CSharpMarshal.cs | 12 ++++++++++-- .../Generators/CSharp/CSharpTypePrinter.cs | 3 +-- tests/Basic/Basic.Tests.cs | 4 ++++ tests/Basic/Basic.cpp | 5 +++++ tests/Basic/Basic.h | 2 ++ 7 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/Generator/Generators/CLI/CLIMarshal.cs b/src/Generator/Generators/CLI/CLIMarshal.cs index 70fcb224..8167506a 100644 --- a/src/Generator/Generators/CLI/CLIMarshal.cs +++ b/src/Generator/Generators/CLI/CLIMarshal.cs @@ -67,15 +67,6 @@ namespace CppSharp.Generators.CLI var pointee = pointer.Pointee.Desugar(); - PrimitiveType primitive; - var param = Context.Parameter; - if (param != null && (param.IsOut || param.IsInOut) && - pointee.IsPrimitiveType(out primitive)) - { - Context.Return.Write(Context.ReturnVarName); - return true; - } - if (pointee.IsPrimitiveType(PrimitiveType.Void)) { Context.Return.Write(Context.ReturnVarName); @@ -89,6 +80,15 @@ namespace CppSharp.Generators.CLI return true; } + PrimitiveType primitive; + var param = Context.Parameter; + if (param != null && (param.IsOut || param.IsInOut) && + pointee.IsPrimitiveType(out primitive)) + { + Context.Return.Write(Context.ReturnVarName); + return true; + } + if (pointee.IsPrimitiveType(out primitive)) { var returnVarName = Context.ReturnVarName; diff --git a/src/Generator/Generators/CLI/CLITypePrinter.cs b/src/Generator/Generators/CLI/CLITypePrinter.cs index c4c7c4a1..2c4ef504 100644 --- a/src/Generator/Generators/CLI/CLITypePrinter.cs +++ b/src/Generator/Generators/CLI/CLITypePrinter.cs @@ -155,8 +155,7 @@ namespace CppSharp.Generators.CLI { // Skip one indirection if passed by reference var param = Context.Parameter; - if (param != null && (param.IsOut || param.IsInOut) - && pointee == finalPointee) + if (param != null && (param.IsOut || param.IsInOut)) return pointee.Visit(this, quals); return pointee.Visit(this, quals) + "*"; diff --git a/src/Generator/Generators/CSharp/CSharpMarshal.cs b/src/Generator/Generators/CSharp/CSharpMarshal.cs index 17ec4d89..34198090 100644 --- a/src/Generator/Generators/CSharp/CSharpMarshal.cs +++ b/src/Generator/Generators/CSharp/CSharpMarshal.cs @@ -430,8 +430,16 @@ namespace CppSharp.Generators.CSharp pointee.IsPrimitiveType(PrimitiveType.WideChar)) && pointer.QualifiedPointee.Qualifiers.IsConst) { - Context.Return.Write(MarshalStringToUnmanaged(Context.Parameter.Name)); - CSharpContext.Cleanup.WriteLine("Marshal.FreeHGlobal({0});", Context.ArgName); + if (Context.Parameter.IsOut) + { + Context.Return.Write("IntPtr.Zero"); + CSharpContext.ArgumentPrefix.Write("&"); + } + else + { + Context.Return.Write(MarshalStringToUnmanaged(Context.Parameter.Name)); + CSharpContext.Cleanup.WriteLine("Marshal.FreeHGlobal({0});", Context.ArgName); + } return true; } diff --git a/src/Generator/Generators/CSharp/CSharpTypePrinter.cs b/src/Generator/Generators/CSharp/CSharpTypePrinter.cs index f7aeb255..588a2f89 100644 --- a/src/Generator/Generators/CSharp/CSharpTypePrinter.cs +++ b/src/Generator/Generators/CSharp/CSharpTypePrinter.cs @@ -217,8 +217,7 @@ namespace CppSharp.Generators.CSharp { // Skip one indirection if passed by reference var param = Context.Parameter; - if (isManagedContext && param != null && (param.IsOut || param.IsInOut) - && pointee == finalPointee) + if (isManagedContext && param != null && (param.IsOut || param.IsInOut)) return pointee.Visit(this, quals); if (ContextKind == CSharpTypePrinterContextKind.GenericDelegate) diff --git a/tests/Basic/Basic.Tests.cs b/tests/Basic/Basic.Tests.cs index 013c08d7..c2469ab5 100644 --- a/tests/Basic/Basic.Tests.cs +++ b/tests/Basic/Basic.Tests.cs @@ -55,6 +55,10 @@ public class BasicTests : GeneratorTestFixture //Assert.That(hello.RetEnum(Enum.D), Is.EqualTo(-2147483648)); Assert.That(hello.RetEnum(Enum.E), Is.EqualTo(1)); Assert.That(hello.RetEnum(Enum.F), Is.EqualTo(-9)); + + string str; + hello.StringOut(out str); + Assert.That(str, Is.EqualTo("HelloStringOut")); } [Test] diff --git a/tests/Basic/Basic.cpp b/tests/Basic/Basic.cpp index 4db6854a..a19d482e 100644 --- a/tests/Basic/Basic.cpp +++ b/tests/Basic/Basic.cpp @@ -203,6 +203,11 @@ void Hello::EnumInOutRef(CS_IN_OUT Enum& e) e = Enum::F; } +void Hello::StringOut(CS_OUT const char** str) +{ + *str = "HelloStringOut"; +} + int unsafeFunction(const Bar& ret, char* testForString, void (*foo)(int)) { return ret.A; diff --git a/tests/Basic/Basic.h b/tests/Basic/Basic.h index 160c129b..60fc5b6d 100644 --- a/tests/Basic/Basic.h +++ b/tests/Basic/Basic.h @@ -132,6 +132,8 @@ public: void EnumInOut(CS_IN_OUT Enum* e); void EnumInOutRef(CS_IN_OUT Enum& e); + + void StringOut(CS_OUT const char** str); }; class DLL_API AbstractFoo From 4bddc0798b5b396eb4e535b5a98e7972b6708443 Mon Sep 17 00:00:00 2001 From: Tom Spilman Date: Mon, 11 Aug 2014 18:35:07 -0500 Subject: [PATCH 2/4] Added StringOutRef test. Moved const char string in/out into its own test function. --- tests/Basic/Basic.Tests.cs | 10 +++++++++- tests/Basic/Basic.cpp | 5 +++++ tests/Basic/Basic.h | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/Basic/Basic.Tests.cs b/tests/Basic/Basic.Tests.cs index c2469ab5..7893748e 100644 --- a/tests/Basic/Basic.Tests.cs +++ b/tests/Basic/Basic.Tests.cs @@ -55,12 +55,20 @@ public class BasicTests : GeneratorTestFixture //Assert.That(hello.RetEnum(Enum.D), Is.EqualTo(-2147483648)); Assert.That(hello.RetEnum(Enum.E), Is.EqualTo(1)); Assert.That(hello.RetEnum(Enum.F), Is.EqualTo(-9)); + } + + [Test] + public void TestPrimitiveConstCharStringInOut() + { + var hello = new Hello(); string str; hello.StringOut(out str); Assert.That(str, Is.EqualTo("HelloStringOut")); + hello.StringOutRef(out str); + Assert.That(str, Is.EqualTo("HelloStringOutRef")); } - + [Test] public void TestPrimitiveOutParameters() { diff --git a/tests/Basic/Basic.cpp b/tests/Basic/Basic.cpp index a19d482e..c992e5ee 100644 --- a/tests/Basic/Basic.cpp +++ b/tests/Basic/Basic.cpp @@ -208,6 +208,11 @@ void Hello::StringOut(CS_OUT const char** str) *str = "HelloStringOut"; } +void Hello::StringOutRef(CS_OUT const char*& str) +{ + str = "HelloStringOutRef"; +} + int unsafeFunction(const Bar& ret, char* testForString, void (*foo)(int)) { return ret.A; diff --git a/tests/Basic/Basic.h b/tests/Basic/Basic.h index 60fc5b6d..7dcd7d65 100644 --- a/tests/Basic/Basic.h +++ b/tests/Basic/Basic.h @@ -134,6 +134,7 @@ public: void EnumInOutRef(CS_IN_OUT Enum& e); void StringOut(CS_OUT const char** str); + void StringOutRef(CS_OUT const char*& str); }; class DLL_API AbstractFoo From 7e8f7432283e84a780443119e362f6b745841b7f Mon Sep 17 00:00:00 2001 From: Tom Spilman Date: Mon, 11 Aug 2014 19:27:23 -0500 Subject: [PATCH 3/4] Fixed const char string CS_IN_OUT case. --- src/Generator/Generators/CLI/CLISourcesTemplate.cs | 5 +++++ src/Generator/Generators/CSharp/CSharpMarshal.cs | 5 +++++ tests/Basic/Basic.Tests.cs | 3 +++ tests/Basic/Basic.cpp | 9 +++++++++ tests/Basic/Basic.h | 2 ++ 5 files changed, 24 insertions(+) diff --git a/src/Generator/Generators/CLI/CLISourcesTemplate.cs b/src/Generator/Generators/CLI/CLISourcesTemplate.cs index b9568359..c3c9e76c 100644 --- a/src/Generator/Generators/CLI/CLISourcesTemplate.cs +++ b/src/Generator/Generators/CLI/CLISourcesTemplate.cs @@ -1101,7 +1101,12 @@ namespace CppSharp.Generators.CLI var type = paramType.Visit(typePrinter); if (param.IsInOut) + { + if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) + Write(marshal.Context.SupportBefore); + WriteLine("{0} {1} = {2};", type, argName, marshal.Context.Return); + } else WriteLine("{0} {1};", type, argName); } diff --git a/src/Generator/Generators/CSharp/CSharpMarshal.cs b/src/Generator/Generators/CSharp/CSharpMarshal.cs index 34198090..0366c35d 100644 --- a/src/Generator/Generators/CSharp/CSharpMarshal.cs +++ b/src/Generator/Generators/CSharp/CSharpMarshal.cs @@ -435,6 +435,11 @@ namespace CppSharp.Generators.CSharp Context.Return.Write("IntPtr.Zero"); CSharpContext.ArgumentPrefix.Write("&"); } + else if (Context.Parameter.IsInOut) + { + Context.Return.Write(MarshalStringToUnmanaged(Context.Parameter.Name)); + CSharpContext.ArgumentPrefix.Write("&"); + } else { Context.Return.Write(MarshalStringToUnmanaged(Context.Parameter.Name)); diff --git a/tests/Basic/Basic.Tests.cs b/tests/Basic/Basic.Tests.cs index 7893748e..cb9eac03 100644 --- a/tests/Basic/Basic.Tests.cs +++ b/tests/Basic/Basic.Tests.cs @@ -67,6 +67,9 @@ public class BasicTests : GeneratorTestFixture Assert.That(str, Is.EqualTo("HelloStringOut")); hello.StringOutRef(out str); Assert.That(str, Is.EqualTo("HelloStringOutRef")); + str = "Hello"; + hello.StringInOut(ref str); + Assert.That(str, Is.EqualTo("StringInOut")); } [Test] diff --git a/tests/Basic/Basic.cpp b/tests/Basic/Basic.cpp index c992e5ee..e405f60d 100644 --- a/tests/Basic/Basic.cpp +++ b/tests/Basic/Basic.cpp @@ -1,4 +1,5 @@ #include "Basic.h" +#include Foo::Foo() { @@ -213,6 +214,14 @@ void Hello::StringOutRef(CS_OUT const char*& str) str = "HelloStringOutRef"; } +void Hello::StringInOut(CS_IN_OUT const char** str) +{ + if (strcmp(*str, "Hello") == 0) + *str = "StringInOut"; + else + *str = "Failed"; +} + int unsafeFunction(const Bar& ret, char* testForString, void (*foo)(int)) { return ret.A; diff --git a/tests/Basic/Basic.h b/tests/Basic/Basic.h index 7dcd7d65..9f7318eb 100644 --- a/tests/Basic/Basic.h +++ b/tests/Basic/Basic.h @@ -135,6 +135,8 @@ public: void StringOut(CS_OUT const char** str); void StringOutRef(CS_OUT const char*& str); + void StringInOut(CS_IN_OUT const char** str); + //void StringInOutRef(CS_OUT const char*& str); }; class DLL_API AbstractFoo From 27a2016f8a5ae281a53548a28a7f53427f952993 Mon Sep 17 00:00:00 2001 From: Tom Spilman Date: Mon, 11 Aug 2014 19:34:11 -0500 Subject: [PATCH 4/4] Added reference test case. --- tests/Basic/Basic.Tests.cs | 3 +++ tests/Basic/Basic.cpp | 8 ++++++++ tests/Basic/Basic.h | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/Basic/Basic.Tests.cs b/tests/Basic/Basic.Tests.cs index cb9eac03..78b0ac27 100644 --- a/tests/Basic/Basic.Tests.cs +++ b/tests/Basic/Basic.Tests.cs @@ -70,6 +70,9 @@ public class BasicTests : GeneratorTestFixture str = "Hello"; hello.StringInOut(ref str); Assert.That(str, Is.EqualTo("StringInOut")); + str = "Hello"; + hello.StringInOutRef(ref str); + Assert.That(str, Is.EqualTo("StringInOutRef")); } [Test] diff --git a/tests/Basic/Basic.cpp b/tests/Basic/Basic.cpp index e405f60d..9d8c6d11 100644 --- a/tests/Basic/Basic.cpp +++ b/tests/Basic/Basic.cpp @@ -222,6 +222,14 @@ void Hello::StringInOut(CS_IN_OUT const char** str) *str = "Failed"; } +void Hello::StringInOutRef(CS_IN_OUT const char*& str) +{ + if (strcmp(str, "Hello") == 0) + str = "StringInOutRef"; + else + str = "Failed"; +} + int unsafeFunction(const Bar& ret, char* testForString, void (*foo)(int)) { return ret.A; diff --git a/tests/Basic/Basic.h b/tests/Basic/Basic.h index 9f7318eb..cd3e992b 100644 --- a/tests/Basic/Basic.h +++ b/tests/Basic/Basic.h @@ -136,7 +136,7 @@ public: void StringOut(CS_OUT const char** str); void StringOutRef(CS_OUT const char*& str); void StringInOut(CS_IN_OUT const char** str); - //void StringInOutRef(CS_OUT const char*& str); + void StringInOutRef(CS_IN_OUT const char*& str); }; class DLL_API AbstractFoo