Browse Source

Added marshalling of parameters of type array of pointers.

Fixes https://github.com/mono/CppSharp/issues/932.

Signed-off-by: Dimitar Dobrev <dpldobrev@protonmail.com>
pull/943/head
Dimitar Dobrev 8 years ago
parent
commit
3d9cc3ab70
  1. 73
      src/Generator/Generators/CSharp/CSharpMarshal.cs
  2. 14
      src/Generator/Generators/CSharp/CSharpTypePrinter.cs
  3. 7
      tests/CSharp/CSharp.Tests.cs
  4. 5
      tests/CSharp/CSharp.cpp
  5. 2
      tests/CSharp/CSharp.h

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

@ -426,6 +426,7 @@ namespace CppSharp.Generators.CSharp
if (!VisitType(array, quals)) if (!VisitType(array, quals))
return false; return false;
var arrayType = array.Type.Desugar();
switch (array.SizeType) switch (array.SizeType)
{ {
case ArrayType.ArraySize.Constant: case ArrayType.ArraySize.Constant:
@ -447,8 +448,7 @@ namespace CppSharp.Generators.CSharp
supportBefore.WriteLine("if ({0} != null)", Context.ArgName); supportBefore.WriteLine("if ({0} != null)", Context.ArgName);
supportBefore.WriteStartBraceIndent(); supportBefore.WriteStartBraceIndent();
Class @class; Class @class;
var arrayType = array.Type.Desugar(); if (arrayType.TryGetClass(out @class) && @class.IsRefType)
if (array.Type.Desugar().TryGetClass(out @class) && @class.IsRefType)
{ {
supportBefore.WriteLine("if (value.Length != {0})", array.Size); supportBefore.WriteLine("if (value.Length != {0})", array.Size);
ThrowArgumentOutOfRangeException(); ThrowArgumentOutOfRangeException();
@ -458,7 +458,7 @@ namespace CppSharp.Generators.CSharp
{ {
supportBefore.WriteLineIndent( supportBefore.WriteLineIndent(
"*({1}.{2}*) &{0}[i * sizeof({1}.{2})] = *({1}.{2}*){3}[i].{4};", "*({1}.{2}*) &{0}[i * sizeof({1}.{2})] = *({1}.{2}*){3}[i].{4};",
Context.ReturnVarName, array.Type, Helpers.InternalStruct, Context.ReturnVarName, arrayType, Helpers.InternalStruct,
Context.ArgName, Helpers.InstanceIdentifier); Context.ArgName, Helpers.InstanceIdentifier);
} }
else else
@ -475,7 +475,7 @@ namespace CppSharp.Generators.CSharp
supportBefore.WriteLineIndent("{0}[i] = {1}[i]{2};", supportBefore.WriteLineIndent("{0}[i] = {1}[i]{2};",
Context.ReturnVarName, Context.ReturnVarName,
Context.ArgName, Context.ArgName,
array.Type.IsPointerToPrimitiveType(PrimitiveType.Void) arrayType.IsPointerToPrimitiveType(PrimitiveType.Void)
? ".ToPointer()" ? ".ToPointer()"
: string.Empty); : string.Empty);
} }
@ -484,7 +484,7 @@ namespace CppSharp.Generators.CSharp
} }
break; break;
case ArrayType.ArraySize.Incomplete: case ArrayType.ArraySize.Incomplete:
Context.Return.Write(Context.Parameter.Name); MarshalVariableArray(arrayType);
break; break;
default: default:
Context.Return.Write("null"); Context.Return.Write("null");
@ -493,21 +493,6 @@ namespace CppSharp.Generators.CSharp
return true; return true;
} }
private void ThrowArgumentOutOfRangeException()
{
Context.Before.WriteLineIndent(
"throw new ArgumentOutOfRangeException(\"{0}\", " +
"\"The dimensions of the provided array don't match the required size.\");",
Context.Parameter.Name);
}
public bool VisitDelegateType(FunctionType function, string type)
{
Context.Return.Write("{0} == null ? global::System.IntPtr.Zero : Marshal.GetFunctionPointerForDelegate({0})",
Context.Parameter.Name);
return true;
}
public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals) public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
{ {
if (!VisitType(pointer, quals)) if (!VisitType(pointer, quals))
@ -572,7 +557,7 @@ namespace CppSharp.Generators.CSharp
if (pointee is FunctionType) if (pointee is FunctionType)
{ {
var function = pointee as FunctionType; var function = pointee as FunctionType;
return VisitDelegateType(function, function.ToString()); return VisitDelegateType();
} }
Class @class; Class @class;
@ -700,7 +685,7 @@ namespace CppSharp.Generators.CSharp
FunctionType func; FunctionType func;
if (decl.Type.IsPointerTo(out func)) if (decl.Type.IsPointerTo(out func))
{ {
VisitDelegateType(func, typedef.Declaration.OriginalName); VisitDelegateType();
return true; return true;
} }
@ -855,6 +840,50 @@ namespace CppSharp.Generators.CSharp
return template.TemplatedFunction.Visit(this); return template.TemplatedFunction.Visit(this);
} }
private bool VisitDelegateType()
{
Context.Return.Write("{0} == null ? global::System.IntPtr.Zero : Marshal.GetFunctionPointerForDelegate({0})",
Context.Parameter.Name);
return true;
}
private void ThrowArgumentOutOfRangeException()
{
Context.Before.WriteLineIndent(
"throw new ArgumentOutOfRangeException(\"{0}\", " +
"\"The dimensions of the provided array don't match the required size.\");",
Context.Parameter.Name);
}
private void MarshalVariableArray(Type arrayType)
{
var intermediateArray = $"__{Context.Parameter.Name}";
var intermediateArrayType = typePrinter.PrintNative(arrayType);
const string intPtrType = CSharpTypePrinter.IntPtrType;
Context.Before.WriteLine($"{intermediateArrayType}[] {intermediateArray};");
Context.Before.WriteLine($"if (ReferenceEquals({Context.Parameter.Name}, null))");
Context.Before.WriteLineIndent($"{intermediateArray} = new[] {{ {intPtrType}.Zero }};");
Context.Before.WriteLine("else");
Context.Before.WriteStartBraceIndent();
Context.Before.WriteLine($@"{intermediateArray} = new {
intermediateArrayType}[{Context.Parameter.Name}.Length];");
Context.Before.WriteLine($"for (int i = 0; i < {intermediateArray}.Length; i++)");
Context.Before.WriteStartBraceIndent();
const string element = "__element";
Context.Before.WriteLine($"var {element} = {Context.Parameter.Name}[i];");
Context.Before.WriteLine($@"{intermediateArray}[i] = ReferenceEquals({
element}, null) ? {intPtrType}.Zero : {element}.{Helpers.InstanceIdentifier};");
Context.Before.WriteCloseBraceIndent();
Context.Before.WriteCloseBraceIndent();
Context.Return.Write(intermediateArray);
}
private readonly CSharpTypePrinter typePrinter; private readonly CSharpTypePrinter typePrinter;
} }
} }

14
src/Generator/Generators/CSharp/CSharpTypePrinter.cs

@ -111,11 +111,11 @@ namespace CppSharp.Generators.CSharp
arrayElemType = Context.TargetInfo.PointerWidth == 64 ? "long" : "int"; arrayElemType = Context.TargetInfo.PointerWidth == 64 ? "long" : "int";
// Do not write the fixed keyword multiple times for nested array types // Do not write the fixed keyword multiple times for nested array types
var fixedKeyword = array.Type is ArrayType ? string.Empty : "fixed "; var fixedKeyword = arrayType is ArrayType ? string.Empty : "fixed ";
return new TypePrinterResult return new TypePrinterResult
{ {
Type = $"{fixedKeyword}{arrayElemType}", Type = $"{fixedKeyword}{arrayElemType}",
NameSuffix = $"[{array.Size}]", NameSuffix = $"[{array.Size}]"
}; };
} }
@ -128,12 +128,10 @@ namespace CppSharp.Generators.CSharp
if (arrayType.IsPointerToPrimitiveType(PrimitiveType.Char)) if (arrayType.IsPointerToPrimitiveType(PrimitiveType.Char))
return "char**"; return "char**";
return string.Format("{0}{1}", array.Type.Visit(this), var arraySuffix = array.SizeType == ArrayType.ArraySize.Constant ||
array.SizeType == ArrayType.ArraySize.Constant ? "[]" : !arrayType.IsPrimitiveType() ? "[]" :
(ContextKind == TypePrinterContextKind.Managed ? "*" : string.Empty)); (ContextKind == TypePrinterContextKind.Managed ? "*" : string.Empty);
return $"{arrayType.Visit(this)}{arraySuffix}";
// C# only supports fixed arrays in unsafe sections
// and they are constrained to a set of built-in types.
} }
public override TypePrinterResult VisitFunctionType(FunctionType function, public override TypePrinterResult VisitFunctionType(FunctionType function,

7
tests/CSharp/CSharp.Tests.cs

@ -1060,6 +1060,13 @@ public unsafe class CSharpTests : GeneratorTestFixture
bar.Dispose(); bar.Dispose();
} }
[Test]
public void TestArrayParams()
{
Foo[] foos = { new Foo { A = 2 }, new Foo { A = 5 } };
Assert.That(CSharp.CSharp.TakeArrayOfPointersToObjects(foos), Is.EqualTo(7));
}
private class OverrideVirtualTemplate : VirtualTemplate<int> private class OverrideVirtualTemplate : VirtualTemplate<int>
{ {
public override int Function public override int Function

5
tests/CSharp/CSharp.cpp

@ -1391,3 +1391,8 @@ typedefedFuncPtr* TestDuplicateDelegate::testDuplicateDelegate(int a)
void InlineNamespace::FunctionInsideInlineNamespace() void InlineNamespace::FunctionInsideInlineNamespace()
{ {
} }
int takeArrayOfPointersToObjects(Foo* arrayOfPointersToObjects[])
{
return arrayOfPointersToObjects[0]->A + arrayOfPointersToObjects[1]->A;
}

2
tests/CSharp/CSharp.h

@ -1236,3 +1236,5 @@ inline namespace InlineNamespace
{ {
DLL_API void FunctionInsideInlineNamespace(); DLL_API void FunctionInsideInlineNamespace();
} }
DLL_API int takeArrayOfPointersToObjects(Foo* arrayOfPointersToObjects[]);

Loading…
Cancel
Save