2008-10-09 7 views
25

Ich habe folgende Struktur in C++:Marshal C++ struct Array in C#

#define MAXCHARS 15 

typedef struct 
{ 
    char data[MAXCHARS]; 
    int prob[MAXCHARS]; 
} LPRData; 

Und eine Funktion, die ich p bin/in Berufung auf eine Reihe von drei dieser Strukturen zu erhalten:

void GetData(LPRData *data); 

in C++ ich tun würde, nur etwa so:

LPRData *Results; 
Results = (LPRData *)malloc(MAXRESULTS*sizeof(LPRData)); 
GetData(Results); 

Und es würde gut funktionieren, aber in C# scheine ich kann es nicht zur Arbeit zu kommen. Ich habe eine C# struct wie folgt erstellt:

public struct LPRData 
{ 

    /// char[15] 
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)] 
    public string data; 

    /// int[15] 
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)] 
    public int[] prob; 
} 

Und wenn ich ein Array von 3 derer initialisiert werden (und alle ihre Unterarrays) und in diese übergeben:

GetData(LPRData[] data); 

Es kehrt mit Erfolg zurück, aber die Daten im LPRData-Array haben sich nicht geändert.

Ich habe sogar versucht, einen rohen Byte-Array die Größe von 3 LPRData erstellen zu können und die in einen Funktionsprototyp wie dies passiert:

GetData (byte [] data);

Aber in diesem Fall werde ich die Zeichenfolge "Daten" aus der allerersten LPRData Struktur, aber nichts danach, einschließlich der "Prob" -Array von der gleichen LPRData.

Irgendwelche Ideen, wie man richtig damit umgeht?

Antwort

23

Ich würde versuchen, einige Attribute zu Ihrer Struktur decloration Zugabe

[StructLayout(LayoutKind.Sequential, Size=TotalBytesInStruct),Serializable] 
public struct LPRData 
{ 
/// char[15] 
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)] 
public string data; 

/// int[15] 
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)] 
public int[] prob; 
} 

* Anmerkung TotalBytesInStruct ist keine Variable

JaredPar darstellen soll ist auch richtig, dass die IntPtr-Klasse könnte hilfreich sein , aber es ist ziemlich lange her, seit ich PInvoke benutzt habe, also bin ich eingerostet.

+1

Ich habe diesen Ansatz verwendet, aber ich bekomme Ausnahmen in Mono, dass die Variablen auf Null-Referenzen gesetzt sind. Zum Beispiel ist "prob" null, also will es nicht funktionieren. Soll ich diese irgendwann neu schreiben, oder soll das irgendwie durch das Framework gehandhabt werden? Vielen Dank – swinefeaster

13

Ein Trick beim Umgang mit Zeigern ist, einfach ein IntPtr zu verwenden. Sie können dann Marshal.PtrToStructure auf dem Zeiger verwenden und basierend auf der Größe der Struktur erhöhen, um Ihre Ergebnisse zu erhalten.

static extern void GetData([Out] out IntPtr ptr); 

LPRData[] GetData() 
{ 
    IntPtr value; 
    LPRData[] array = new LPRData[3]; 
    GetData(out value); 
    for (int i = 0; i < array.Length; i++) 
    { 
     array[i] = Marshal.PtrToStructure(value, typeof(LPRData)); 
     value += Marshal.SizeOf(typeof(LPRData)); 
    } 
    return array; 
} 
+2

sollte Zeile 11: entweder '+ =' zu '=' und 'ToInt32' zu' ToInt64' ändern, wenn 64-Bit ausgeführt wird; oder, entferne die 'value.ToInt32()'? – maxwellb

+0

@maxwellb, ja. Der geschriebene Code ist nicht 64 Bit sicher. – JaredPar

+4

was ich wirklich verstehe, ist, dass Sie Inkrement-Zuweisung durch das Inkrement von pointer.toInt + sizeof (struct). Wäre das Inkrement nicht nur sizeof (struct)? – maxwellb

2

Haben Sie GetData Parameter mit OutAttribute markiert?

die InAttribute und OutAttribute Kombination ist besonders nützlich, wenn sie auf Arrays angewendet und formatiert, nicht-blitfähig Typen. Anrufer sehen die Änderungen, die ein Angerufener an diesen Typen nur durchführt, wenn Sie beide Attribute anwenden.

2

Ein ähnliches Thema wurde auf this question diskutiert, und die eine der Schlussfolgerungen war, dass die CharSet benannten Parameter auf CharSet.Ansi eingestellt werden müssen.Ansonsten würden wir ein wchar_t Array anstelle eines char Arrays erstellen. Somit wäre der korrekte Code wie folgt: