Wie kann ich marshall ein Zeiger auf einen Zeiger eines Arrays von Strukturen?
Meine C-Deklarationen sind wie folgt:
int myData(uint myHandle, tchar *dataName, long *Time, uint *maxData, DATASTRUCT **data);
typedef struct {
byte Rel;
__int64 Time;
char Validated;
unsigned char Data[1];
} DATASTRUCT ;
Mein C# - Deklarationen sind wie folgt:
[DllImport("myData.dll", EntryPoint = "myData")]
public static extern int myData(uint myHandle, [MarshalAs(UnmanagedType.LPTStr)] string dataName, out long Time, out uint maxData, ref DATASTRUCT[] data);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct DATASTRUCT
{
public sbyte Rel;
public long Time;
public byte Validated;
public double Data;
}
Ich dann rufen Sie die verwaltete Funktion wie folgt:
string dataToShow = "description";
long Time;
uint maxData; //How many structs will be returned, i.e. how much data is available
uint myHandle = 1;
DATASTRUCT[] dataInformation = new DATASTRUCT[3]; //doesn't matter what I specify as the array size?
myData(myHandle, dataToShow, out Time, out maxData, ref dataInformation);
Nach Ausführung der oben genannten Funktion wird erfolgreich zurück mit nur einer Struktur, obwohl es gibt 3 zurück. Warum ist das so?
Zusätzliche Informationen; ich habe versucht, übergeben Sie den Zeiger auf einen Zeiger eines Arrays von structs folgende Möglichkeiten:
- ref DATASTRUCT[] data; //Works but only returns one struct
- [Out, MarshalAs(UnmanagedType.LPArray)] DATASTRUCT[] data; //returns the number of defined structs with garbage
Wie ich es verstehe brauche ich zu tun, einige manuelle marshalling mit IntPtr
ich weiß nicht, wie das umzusetzen, dies jedoch, so dass jede Beratung wird gebeten.
- Wie ist die C-Funktion, die die Strukturen? Nutzen Sie das Eingabe-array als Puffer, oder generieren Sie neue Strukturen mit malloc?
- Oh, und du bist auch C# - Deklaration sieht falsch aus. Ein unsigned char wird nicht die gleiche Größe wie ein Doppelzimmer (1 vs 8 bytes)
- Leider ist die DLL-Bibliothek-Dokumentation nicht erklären, ob er reserviert Speicher für das struct oder nicht. Ich gehe davon aus, dass es nicht. Ich habe nicht die volle Verzögerung für
Data
es ist in der Tat eine variable char kann maximal 8 bytes und damit der Grund für marshalling es als Doppel -, diese variable definitiv die richtigen Ergebnisse werden zurückgegeben jedes mal, wenn ich es getestet haben. - Versuchen Sie, diese [Out, MarshalAs(UnmanagedType.LPArray,SizeParamIndex:=3)] aus DATASTRUCT[] Daten;
- Bekomme ich auch eine exception beim Aufruf dieser als
myData(myHandle, dataToShow, out Time, out maxData, out dataInformation);
entfernen derout
gibt eine ähnliche Ausgabe wie[Out, MarshalAs(UnmanagedType.LPArray)] DATASTRUCT[] data;
- Vergessen SizeParamIndex doesent Arbeit mit ref,out Check this stackoverflow.com/a/188396/629926
- bei der weiteren Untersuchung es scheint, als ob myData.dll reserviert den Speicher für die Strukturen.
- In diesem Fall ändern Sie einfach die parameter für einen IntPtr und Marschall der Rückkehr. Siehe meine Antwort.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Okay, es scheint, als ob Sie Ihr native Bibliothek stellt die Zuweisung, also wirklich alles, was Sie tun müssen, ist geben Sie einen Zeiger über die Sie Zugriff auf den zugewiesenen Daten.
Ändern Sie Ihr API-definition (Anmerkung, ich habe die maxData param uint, long 64 bit .NET und 32 bit im nativen.
Aus der Spitze von meinem Kopf ich kann mich nicht erinnern, wenn Sie das out-Schlüsselwort für den letzten parameter, aber ich denke so.
Dann rufen myData:
Nun, pAllocs zeigen sollte, zu nicht verwalteten Speicher, Marschall diese in verwalteten Speicher ist nicht allzu schwer:
Und jetzt sollten Sie haben eine Reihe von lokalen Strukturen.
Ein Punkt zu beachten
Sie möglicherweise benötigen, um Ihr Projekt zu kompilieren, wie x86, Standardisierung der Größe eines IntPtr, um 4 bytes (DWORD) statt AnyCPU Standard 8.
public IntPtr Data;
die zurückgegebenen Daten fürdata
scheint, wie Müll, wenn ich ihn wieder ändern zupublic double Data;
es gibt die Daten korrekt.Einen Zeiger auf einen Zeiger dargestellt werden können, in Ihrem dllimport Erklärung als ref IntPtr data, so Ihre Erklärung würde:
(Als beiseite, ich denke, eine lange, in C ist nur äquivalent zu einem int in C#. Lange in C# ist ein Int64, das wäre ein long long in C)
Marshalling Ihre DATASTRUCT[] an einen Typ IntPtr kann durchgeführt werden, indem die Klasse GCHandle-Klasse
Verwenden Sie die Marshal-Klasse und die StructureToPtr oder Kopieren Methoden, es wäre auch eine option, aber für die Zwecke, zu beweisen, das Konzept mindestens die Klasse GCHandle sollten den trick tun, es ist einfach nicht ideal für Szenarien, in denen der nicht verwalteten code führt lang andauernde Vorgänge, weil Sie angepinnt haben, dieses Objekt an Ort und Stelle und der GC kann sich nicht bewegen, bis Sie frei ist.
unsigned char Data[1];
wieder korrekte Werte an die ich glaube. Wie würde ich überprüfen, ob das aktuelle struct-Größe entspricht der C-code? Wie ich sagte, es ist definitiv Daten gibt, wie es gibt 1 struct ok, wenn mitref DATASTRUCT[] data;
public double Data;
wird davon ausgegangen, als falsch? Wenn ja, was sind Eure Empfehlungen für marshalling dieser Art, wenn man bedenkt, dass die DLL-Bibliothek docmentation erklärt, dass es "variable Größe, die ist gleich um 'datalength" in meinem Fall datalength ist gleich 8bytes. Auchunsigned char Data[1];
könnte auch ein Zeiger auf den Anfang der Zeichenkette desdatalength
Länge und enden bei NULL.