diff --git a/build/Helpers.lua b/build/Helpers.lua index 5311f2e9..40e519d8 100644 --- a/build/Helpers.lua +++ b/build/Helpers.lua @@ -165,7 +165,7 @@ end function SetupManagedProject() language "C#" location ("%{wks.location}/projects") - buildoptions {"/langversion:7.2"} + buildoptions {"/langversion:7.3"} buildoptions {"/platform:".._OPTIONS["arch"]} dotnetframework "4.7.2" diff --git a/src/Generator/Generators/CSharp/CSharpMarshal.cs b/src/Generator/Generators/CSharp/CSharpMarshal.cs index e7409ad4..c51b9c5d 100644 --- a/src/Generator/Generators/CSharp/CSharpMarshal.cs +++ b/src/Generator/Generators/CSharp/CSharpMarshal.cs @@ -73,61 +73,45 @@ namespace CppSharp.Generators.CSharp Context.MarshalKind != MarshalKind.ReturnVariableArray) goto case ArrayType.ArraySize.Incomplete; - var supportBefore = Context.Before; - string value = Generator.GeneratedIdentifier("value"); var arrayType = array.Type.Desugar(); - supportBefore.WriteLine($"{arrayType}[] {value} = null;"); - supportBefore.WriteLine($"if ({Context.ReturnVarName} != null)"); - supportBefore.WriteOpenBraceAndIndent(); - supportBefore.WriteLine($"{value} = new {arrayType}[{array.Size}];"); if (CheckIfArrayCanBeCopiedUsingMemoryCopy(array)) + Context.Return.Write($"CppSharp.Runtime.MarshalUtil.GetArray<{arrayType}>({Context.ReturnVarName}, {array.Size})"); + else if (array.Type.IsPrimitiveType(PrimitiveType.Char) && Context.Context.Options.MarshalCharAsManagedChar) + Context.Return.Write($"CppSharp.Runtime.MarshalUtil.GetCharArray({Context.ReturnVarName}, {array.Size})"); + else if (array.Type.IsPointerToPrimitiveType(PrimitiveType.Void)) + Context.Return.Write($"CppSharp.Runtime.MarshalUtil.GetIntPtrArray({Context.ReturnVarName}, {array.Size})"); + else { - var arraySizeInBytes = array.GetSizeInBytes(); - var fixedArray = Generator.GeneratedIdentifier($"{value}fixed"); - supportBefore.WriteLine($"fixed (void* {fixedArray} = {value})"); - supportBefore.WriteLineIndent( - $"System.Buffer.MemoryCopy((void*){Context.ReturnVarName}, {fixedArray}, {arraySizeInBytes}, {arraySizeInBytes});"); - } - else { + string value = Generator.GeneratedIdentifier("value"); + var supportBefore = Context.Before; + supportBefore.WriteLine($"{arrayType}[] {value} = null;"); + supportBefore.WriteLine($"if ({Context.ReturnVarName} != null)"); + supportBefore.WriteOpenBraceAndIndent(); + supportBefore.WriteLine($"{value} = new {arrayType}[{array.Size}];"); + supportBefore.WriteLine($"for (int i = 0; i < {array.Size}; i++)"); - if (array.Type.IsPointerToPrimitiveType(PrimitiveType.Void)) - supportBefore.WriteLineIndent($@"{value}[i] = new global::System.IntPtr({ - Context.ReturnVarName}[i]);"); - else + var finalArrayType = arrayType.GetPointee() ?? arrayType; + Class @class; + if ((finalArrayType.TryGetClass(out @class)) && @class.IsRefType) { - - var finalArrayType = arrayType.GetPointee() ?? arrayType; - Class @class; - if ((finalArrayType.TryGetClass(out @class)) && @class.IsRefType) - { - if (arrayType == finalArrayType) - supportBefore.WriteLineIndent( - "{0}[i] = {1}.{2}(*(({1}.{3}*)&({4}[i * sizeof({1}.{3})])));", - value, array.Type, Helpers.CreateInstanceIdentifier, - Helpers.InternalStruct, Context.ReturnVarName); - else - supportBefore.WriteLineIndent( - $@"{value}[i] = {finalArrayType}.{Helpers.CreateInstanceIdentifier}(({ - typePrinter.IntPtrType}) {Context.ReturnVarName}[i]);"); - } + if (arrayType == finalArrayType) + supportBefore.WriteLineIndent( + "{0}[i] = {1}.{2}(*(({1}.{3}*)&({4}[i * sizeof({1}.{3})])));", + value, array.Type, Helpers.CreateInstanceIdentifier, + Helpers.InternalStruct, Context.ReturnVarName); else - { - if (arrayType.IsPrimitiveType(PrimitiveType.Bool) && Context.MarshalKind == MarshalKind.NativeField) - supportBefore.WriteLineIndent($@"{value}[i] = { - Context.ReturnVarName}[i] != 0;"); - else if (arrayType.IsPrimitiveType(PrimitiveType.Char) && - Context.Context.Options.MarshalCharAsManagedChar) - supportBefore.WriteLineIndent($@"{value}[i] = global::System.Convert.ToChar({ - Context.ReturnVarName}[i]);"); - else - supportBefore.WriteLineIndent($@"{value}[i] = { - Context.ReturnVarName}[i];"); - } + supportBefore.WriteLineIndent( + $@"{value}[i] = {finalArrayType}.{Helpers.CreateInstanceIdentifier}(({ + typePrinter.IntPtrType}) {Context.ReturnVarName}[i]);"); } - } - supportBefore.UnindentAndWriteCloseBrace(); - Context.Return.Write(value); + else + { + supportBefore.WriteLineIndent($@"{value}[i] = {Context.ReturnVarName}[i];"); + } + supportBefore.UnindentAndWriteCloseBrace(); + Context.Return.Write(value); + } break; case ArrayType.ArraySize.Incomplete: // const char* and const char[] are the same so we can use a string diff --git a/src/Runtime/MarshalUtil.cs b/src/Runtime/MarshalUtil.cs index ea880d2f..eaac75ec 100644 --- a/src/Runtime/MarshalUtil.cs +++ b/src/Runtime/MarshalUtil.cs @@ -30,5 +30,30 @@ namespace CppSharp.Runtime return encoding.GetString((byte*)str, byteCount); } + + public static T[] GetArray(void* array, int size) where T : unmanaged + { + if (array == null) + return null; + var result = new T[size]; + fixed (void* fixedResult = result) + Buffer.MemoryCopy(array, fixedResult, sizeof(T) * size, sizeof(T) * size); + return result; + } + + public static char[] GetCharArray(sbyte* array, int size) + { + if (array == null) + return null; + var result = new char[size]; + for (var i = 0; i < size; ++i) + result[i] = Convert.ToChar(array[i]); + return result; + } + + public static IntPtr[] GetIntPtrArray(IntPtr* array, int size) + { + return GetArray(array, size); + } } } diff --git a/tests/CSharp/CSharp.Tests.cs b/tests/CSharp/CSharp.Tests.cs index 17e36b79..081b4b91 100644 --- a/tests/CSharp/CSharp.Tests.cs +++ b/tests/CSharp/CSharp.Tests.cs @@ -748,6 +748,7 @@ public unsafe class CSharpTests : GeneratorTestFixture Assert.That(StaticVariables.IntArray, Is.EqualTo(new[] { 1020304050 , 1526374850 })); Assert.That(StaticVariables.FloatArray, Is.EqualTo(new[] { 0.5020f, 0.6020f })); Assert.That(StaticVariables.BoolArray, Is.EqualTo(new[] { false, true })); + Assert.That(StaticVariables.VoidPtrArray, Is.EqualTo(new IntPtr[] { new IntPtr(0x10203040), new IntPtr(0x40302010) })); } [Test] diff --git a/tests/CSharp/CSharp.cpp b/tests/CSharp/CSharp.cpp index cf0b9b8c..5141c808 100644 --- a/tests/CSharp/CSharp.cpp +++ b/tests/CSharp/CSharp.cpp @@ -1414,6 +1414,7 @@ const char StaticVariables::ChrArray[2] { 'A', 'B' }; const int StaticVariables::IntArray[2] { 1020304050, 1526374850 }; const float StaticVariables::FloatArray[2] { 0.5020f, 0.6020f }; const bool StaticVariables::BoolArray[2] { false, true }; +const void* StaticVariables::VoidPtrArray[2] { (void*)0x10203040, (void*)0x40302010 }; TestString::TestString() : unicodeConst(L"ქართული ენა"), unicode(0) { diff --git a/tests/CSharp/CSharp.h b/tests/CSharp/CSharp.h index 4558d4c2..958fcf71 100644 --- a/tests/CSharp/CSharp.h +++ b/tests/CSharp/CSharp.h @@ -1117,6 +1117,7 @@ public: static const int IntArray[2]; static const float FloatArray[2]; static const bool BoolArray[2]; + static const void* VoidPtrArray[2]; }; static constexpr double ConstexprCreateDoubleValue(double value) {