Aufbauend von meinem marshalling helloworld question, ich renne Probleme in Marshalling ein Array in C bis C# zugeordnet. Ich habe Stunden damit verbracht zu recherchieren, wo ich vielleicht falsch liege, aber alles, was ich versucht habe, endet mit Fehlern wie AccessViolationException.Marshalling C-Array in C# - Einfach HelloWorld
Die Funktion, die das Erstellen eines Arrays in C behandelt, ist unten.
__declspec(dllexport) int __cdecl import_csv(char *path, struct human ***persons, int *numPersons)
{
int res;
FILE *csv;
char line[1024];
struct human **humans;
csv = fopen(path, "r");
if (csv == NULL) {
return errno;
}
*numPersons = 0; // init to sane value
/*
* All I'm trying to do for now is get more than one working.
* Starting with 2 seems reasonable. My test CSV file only has 2 lines.
*/
humans = calloc(2, sizeof(struct human *));
if (humans == NULL)
return ENOMEM;
while (fgets(line, 1024, csv)) {
char *tmp = strdup(line);
struct human *person;
humans[*numPersons] = calloc(1, sizeof(*person));
person = humans[*numPersons]; // easier to work with
if (person == NULL) {
return ENOMEM;
}
person->contact = calloc(1, sizeof(*(person->contact)));
if (person->contact == NULL) {
return ENOMEM;
}
res = parse_human(line, person);
if (res != 0) {
return res;
}
(*numPersons)++;
}
(*persons) = humans;
fclose(csv);
return 0;
}
Der C# -Code:
IntPtr humansPtr = IntPtr.Zero;
int numHumans = 0;
HelloLibrary.import_csv(args[0], ref humansPtr, ref numHumans);
HelloLibrary.human[] humans = new HelloLibrary.human[numHumans];
IntPtr[] ptrs = new IntPtr[numHumans];
IntPtr aIndex = (IntPtr)Marshal.PtrToStructure(humansPtr, typeof(IntPtr));
// Populate the array of IntPtr
for (int i = 0; i < numHumans; i++)
{
ptrs[i] = new IntPtr(aIndex.ToInt64() +
(Marshal.SizeOf(typeof(IntPtr)) * i));
}
// Marshal the array of human structs
for (int i = 0; i < numHumans; i++)
{
humans[i] = (HelloLibrary.human)Marshal.PtrToStructure(
ptrs[i],
typeof(HelloLibrary.human));
}
// Use the marshalled data
foreach (HelloLibrary.human human in humans)
{
Console.WriteLine("first:'{0}'", human.first);
Console.WriteLine("last:'{0}'", human.last);
HelloLibrary.contact_info contact = (HelloLibrary.contact_info)Marshal.
PtrToStructure(human.contact, typeof(HelloLibrary.contact_info));
Console.WriteLine("cell:'{0}'", contact.cell);
Console.WriteLine("home:'{0}'", contact.home);
}
Die erste human struct
wird vermarshallten in Ordnung. Ich erhalte die Zugriffsverletzungsausnahmen nach dem ersten. Ich habe das Gefühl, dass ich etwas vermisse mit Marshalling-Strukturen mit Struktur-Zeigern in ihnen. Ich hoffe, ich habe einen einfachen Fehler, den ich übersehen habe. Siehst du etwas falsch mit diesem Code?
Siehe diese GitHub gist für die vollständige Quelle.
Danke! Ich schreibe Code wie diesen, weil ich es plattformübergreifend betreiben muss. Der C-Code ist eine Bibliothek, die sowohl auf Embedded- und Desktop-Linux als auch auf Windows ausgeführt wird. Ich biete eine CLI unter Linux, aber Windows benötigt eine GUI und ich bevorzuge C# für GUIs unter Windows. Ich bin ziemlich neu in der Verwendung von C-Code in C#, daher kenne ich nicht alle Best Practices. Dies war ein trivialisiertes Beispiel meines tatsächlichen Codes, wo ich eine Funktion zur Verfügung stelle, um den in C zugewiesenen Speicher freizugeben. –