Marshalling C array in C # - Simple HelloWorld

Changing my marshalling helloworld question, I ran into problems sorting an array allocated in C to C #. I spent several hours researching where I might be wrong, but everything I tried ends up with errors like AccessViolationException .

The function that handles array creation in C is below.

__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; } 

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); } 

The first human struct gets fined. I get access violation exceptions after the first. I feel like I'm missing something with the help of structured structures with structure pointers inside them. Hope I have some simple error that I am missing. Do you see something wrong with this code?

See the GitHub gist for a complete source.

+6
source share
1 answer
  // Populate the array of IntPtr 

This is where you did wrong. You are returning a pointer to an array of pointers. You got the first correct one by actually reading the value of the pointer from the array. But then your for () loop got it wrong, just adding 4 (or 8) to the first pointer value. Instead of reading them from an array. Fix:

  IntPtr[] ptrs = new IntPtr[numHumans]; // Populate the array of IntPtr for (int i = 0; i < numHumans; i++) { ptrs[i] = (IntPtr)Marshal.PtrToStructure(humansPtr, typeof(IntPtr)); humansPtr = new IntPtr(humansPtr.ToInt64() + IntPtr.Size); } 

Or much cleaner, since marshaling of arrays of simple types is already supported:

  IntPtr[] ptrs = new IntPtr[numHumans]; Marshal.Copy(humansPtr, ptrs, 0, numHumans); 

I found the error using Debug + Windows + Memory + Memory 1. Put peoplePtr in the Address field, switching to a 4-byte integer representation and noticing that the C code is doing it right. Then it quickly became clear that ptrs [] does not contain the values ​​that I saw in the memory window.

Not sure why you are writing such code other than mental exercise. This is the wrong way to do this, for example, you completely ignore the need to release memory again. This is very nontrivial. Parsing CSV files in C # is pretty simple and as fast as in C, it is an I / O binding, not an execution. You can easily avoid these almost impossible debugging errors and get a lot of help from the .NET Framework.

+2
source

All Articles