Browse Source

Fixed marshalling of `const char**` types in C#.

Fixes issue #454.
pull/456/head
João Matos 10 years ago
parent
commit
a7443265a0
  1. 15
      src/AST/TypeExtensions.cs
  2. 35
      src/Generator/Generators/CSharp/CSharpMarshal.cs
  3. 18
      src/Generator/Generators/CSharp/CSharpTypePrinter.cs
  4. 18
      tests/CSharpTemp/CSharpTemp.h

15
src/AST/TypeExtensions.cs

@ -229,5 +229,20 @@ @@ -229,5 +229,20 @@
}
return finalPointee;
}
public static PointerType GetFinalPointer(this Type t)
{
var type = t as PointerType;
if (type == null)
return null;
var pointee = type.Desugar().GetPointee();
if (pointee.IsPointer())
return pointee.GetFinalPointer();
return type;
}
}
}

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

@ -142,20 +142,24 @@ namespace CppSharp.Generators.CSharp @@ -142,20 +142,24 @@ namespace CppSharp.Generators.CSharp
if (!VisitType(pointer, quals))
return false;
var param = Context.Parameter;
var isRefParam = param != null && (param.IsInOut || param.IsOut);
var pointee = pointer.Pointee.Desugar();
bool marshalPointeeAsString = CSharpTypePrinter.IsConstCharString(pointee) && isRefParam;
if (CSharpTypePrinter.IsConstCharString(pointer))
if (CSharpTypePrinter.IsConstCharString(pointer) || marshalPointeeAsString)
{
Context.Return.Write(MarshalStringToManaged(Context.ReturnVarName,
pointer.Pointee.Desugar() as BuiltinType));
pointer.GetFinalPointee() as BuiltinType));
return true;
}
var finalPointee = pointer.GetFinalPointee();
PrimitiveType primitive;
if (pointee.IsPrimitiveType(out primitive) || pointee.IsEnumType())
if (finalPointee.IsPrimitiveType(out primitive) || finalPointee.IsEnumType())
{
var param = Context.Parameter;
if (param != null && (param.IsOut || param.IsInOut))
if (isRefParam)
{
Context.Return.Write("_{0}", param.Name);
return true;
@ -386,18 +390,20 @@ namespace CppSharp.Generators.CSharp @@ -386,18 +390,20 @@ namespace CppSharp.Generators.CSharp
if (!VisitType(pointer, quals))
return false;
var param = Context.Parameter;
var isRefParam = param != null && (param.IsInOut || param.IsOut);
var pointee = pointer.Pointee.Desugar();
bool marshalPointeeAsString = CSharpTypePrinter.IsConstCharString(pointee) && isRefParam;
if ((pointee.IsPrimitiveType(PrimitiveType.Char) ||
pointee.IsPrimitiveType(PrimitiveType.WideChar)) &&
pointer.QualifiedPointee.Qualifiers.IsConst)
if (CSharpTypePrinter.IsConstCharString(pointer) || marshalPointeeAsString)
{
if (Context.Parameter.IsOut)
if (param.IsOut)
{
Context.Return.Write("IntPtr.Zero");
CSharpContext.ArgumentPrefix.Write("&");
}
else if (Context.Parameter.IsInOut)
else if (param.IsInOut)
{
Context.Return.Write(MarshalStringToUnmanaged(Context.Parameter.Name));
CSharpContext.ArgumentPrefix.Write("&");
@ -437,18 +443,17 @@ namespace CppSharp.Generators.CSharp @@ -437,18 +443,17 @@ namespace CppSharp.Generators.CSharp
return true;
}
var finalPointee = pointer.GetFinalPointee();
PrimitiveType primitive;
if (pointee.IsPrimitiveType(out primitive) || pointee.IsEnumType())
if (finalPointee.IsPrimitiveType(out primitive) || finalPointee.IsEnumType())
{
var param = Context.Parameter;
// From MSDN: "note that a ref or out parameter is classified as a moveable
// variable". This means we must create a local variable to hold the result
// and then assign this value to the parameter.
if (param.IsOut || param.IsInOut)
if (isRefParam)
{
var typeName = Type.TypePrinterDelegate(pointee);
var typeName = Type.TypePrinterDelegate(finalPointee);
if (param.IsInOut)
Context.SupportBefore.WriteLine("{0} _{1} = {1};", typeName, param.Name);

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

@ -192,9 +192,9 @@ namespace CppSharp.Generators.CSharp @@ -192,9 +192,9 @@ namespace CppSharp.Generators.CSharp
pointer.QualifiedPointee.Qualifiers.IsConst;
}
public static bool IsConstCharString(QualifiedType qualType)
public static bool IsConstCharString(Type type)
{
var desugared = qualType.Type.Desugar();
var desugared = type.Desugar();
if (!(desugared is PointerType))
return false;
@ -203,6 +203,13 @@ namespace CppSharp.Generators.CSharp @@ -203,6 +203,13 @@ namespace CppSharp.Generators.CSharp
return IsConstCharString(pointer);
}
public static bool IsConstCharString(QualifiedType qualType)
{
return IsConstCharString(qualType.Type);
}
bool AllowStrings = true;
public CSharpTypePrinterResult VisitPointerType(PointerType pointer,
TypeQualifiers quals)
{
@ -216,7 +223,7 @@ namespace CppSharp.Generators.CSharp @@ -216,7 +223,7 @@ namespace CppSharp.Generators.CSharp
var isManagedContext = ContextKind == CSharpTypePrinterContextKind.Managed;
if (IsConstCharString(pointer))
if (AllowStrings && IsConstCharString(pointer))
return isManagedContext ? "string" : "global::System.IntPtr";
var desugared = pointee.Desugar();
@ -240,7 +247,12 @@ namespace CppSharp.Generators.CSharp @@ -240,7 +247,12 @@ namespace CppSharp.Generators.CSharp
pointee.IsPrimitiveType(PrimitiveType.Void))
return "global::System.IntPtr";
// Do not allow strings inside primitive arrays case, else we'll get invalid types
// like string* for const char **.
AllowStrings = isRefParam;
var result = pointee.Visit(this, quals);
AllowStrings = true;
return !isRefParam && result.Type == "global::System.IntPtr" ? "void**" : result + "*";
}

18
tests/CSharpTemp/CSharpTemp.h

@ -403,3 +403,21 @@ template <> struct QIntegerForSize<4> { typedef uint32_t Unsigned; typedef int32 @@ -403,3 +403,21 @@ template <> struct QIntegerForSize<4> { typedef uint32_t Unsigned; typedef int32
template <> struct QIntegerForSize<8> { typedef uint64_t Unsigned; typedef int64_t Signed; };
typedef QIntegerForSize<Q_PROCESSOR_WORDSIZE>::Signed qregisterint;
typedef QIntegerForSize<Q_PROCESSOR_WORDSIZE>::Unsigned qregisteruint;
struct DLL_API TestPointers
{
void TestDoubleCharPointers(const char** names);
void TestTripleCharPointers(const char*** names);
const char** Names;
};
void TestPointers::TestDoubleCharPointers(const char** names)
{
}
void TestPointers::TestTripleCharPointers(const char*** names)
{
}

Loading…
Cancel
Save