Я нашел проблему. Моя проблема в том, как я создаю / читаю массив структур. В исходной реализации C# ожидалось, что данный массив был массивом указателей на структуры, но нативный код создал массив с самими структурами.
Проблема может быть решена двумя различными подходами. Обновление кода C ++ для создания массива указателей на структуры:
void getEntries(NSDictionary* dictionary, Entry** &_entries, int &size) {
int count = (int) [dictionary count];
// Array of pointers! Structs will be malloc-ed individually on the loop.
Entry** entries = (Entry**) malloc(count * sizeof(Entry*) );
int i = 0;
for(id key in dictionary) {
id value = [dictionary objectForKey:key];
// It creates a pointer to the struct
entries[i] = (Entry*) malloc(sizeof(Entry));
entries[i]->key = Utils::mallocCharStr(key);
entries[i]->value = Utils::mallocCharStr(value);
++i;
}
_entries = entries;
size = count;
}
И способ обработки C# будет следующим:
public Dictionary<string, string> Convert()
{
var dic = new Dictionary<string, string>();
getEntries(NativeInstance, out IntPtr pUnmanagedArray, out int keysCount);
IntPtr[] pIntPtrArray = new IntPtr[keysCount];
// This was the original problem.
// Now it copies the native array pointers to individual IntPtr. Which now they point to individual structs.
Marshal.Copy(pUnmanagedArray, pIntPtrArray, 0, keysCount);
for (int i = 0; i < keysCount; i++)
{
Entry entry = Marshal.PtrToStructure<Entry>(pIntPtrArray[i]); // Magic!
dic.Add(entry.Key, entry.Value);
Marshal.FreeHGlobal(pIntPtrArray[i]); // Free the individual struct malloc
}
Marshal.FreeHGlobal(pUnmanagedArray); // Free native array of pointers malloc.
return dic;
}
==
Другое возможное решение - сохранить C ++ таким, каким он был в исходном вопросе. Таким образом, это означает, что нативный код создает массив структур (не указателей). Но затем необходимо обновить C# код , чтобы корректно сместить каждый элемент в массиве .
public Dictionary<string, string> Convert()
{
var dic = new Dictionary<string, string>();
getEntries(NativeInstance, out IntPtr pUnmanagedArray, out int keysCount);
// Note that we don't use Marshal.Copy(...).
// Every item in the array has an memory offset of the size of the struct, rather than the size of the pointer to a struct.
for (int i = 0; i < keysCount; i++)
{
// "Selects" the nth structure by offseting the original pointer element:
IntPtr pCurrent = pUnmanagedArray + i * Marshal.SizeOf(typeof(Entry));
Entry entry = Marshal.PtrToStructure<Entry>(pCurrent);
dic.Add(entry.Key, entry.Value);
}
// It only frees the array of struct itself because it contains the structs themselves.
Marshal.FreeHGlobal(pUnmanagedArray);
return dic;
}
Обратите внимание, что строки struct автоматически освобождаются при выполнении маршалинга automagi c .