Browse Source

Fix IntPtr array marshalling bug and move hard to read code to CppSharp.Runtime (#1446)

pull/1447/head
josetr 5 years ago committed by GitHub
parent
commit
832e4e9eb0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      build/Helpers.lua
  2. 78
      src/Generator/Generators/CSharp/CSharpMarshal.cs
  3. 25
      src/Runtime/MarshalUtil.cs
  4. 1
      tests/CSharp/CSharp.Tests.cs
  5. 1
      tests/CSharp/CSharp.cpp
  6. 1
      tests/CSharp/CSharp.h

2
build/Helpers.lua

@ -165,7 +165,7 @@ end @@ -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"

78
src/Generator/Generators/CSharp/CSharpMarshal.cs

@ -73,61 +73,45 @@ namespace CppSharp.Generators.CSharp @@ -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

25
src/Runtime/MarshalUtil.cs

@ -30,5 +30,30 @@ namespace CppSharp.Runtime @@ -30,5 +30,30 @@ namespace CppSharp.Runtime
return encoding.GetString((byte*)str, byteCount);
}
public static T[] GetArray<T>(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<IntPtr>(array, size);
}
}
}

1
tests/CSharp/CSharp.Tests.cs

@ -748,6 +748,7 @@ public unsafe class CSharpTests : GeneratorTestFixture @@ -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]

1
tests/CSharp/CSharp.cpp

@ -1414,6 +1414,7 @@ const char StaticVariables::ChrArray[2] { 'A', 'B' }; @@ -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)
{

1
tests/CSharp/CSharp.h

@ -1117,6 +1117,7 @@ public: @@ -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) {

Loading…
Cancel
Save