Не могу маршалировать массив структур из C ++ в C # в Unity
Я пытаюсь передать массивstruct
с C ++ на сценарий Unity на C #. Когда я использую код в рабочей среде, размер массива будет сильно различаться, поэтому мне фактически нужно передать массив неизвестной длины.
Моя умная идея состояла в том, чтобы сохранить массив в куче и передать ссылку на этот массив в Unity. Я нашел сообщения StackOverflow о том, как это сделать. Но тогда Unity жалуется, что ссылка пуста.
Вот часть моего кода на C ++:
extern "C" struct S; // Not currently used.
struct S {
int i;
float f;
};
extern "C" bool helloWorld(S ** a, int * i);
S * s;
bool helloWorld(S ** a, int * i) {
s = new S[4];
for (int j = 0; j < 4; j++) {
s[j].i = j; // Fill in placeholder
s[j].f = (float) j; // data for now.
}
*a = s; // I don't know if this works.
*i = 4; // Works.
return true;
}
Я пробовал это сint
с вместоstruct
и это сработало.
Теперь мой код C #:
[StructLayout(LayoutKind.Sequential),Serializable]
public struct S {
int i;
float f;
};
void Start() {
IntPtr ptrNativeData = IntPtr.Zero;
int itemsLength = 0;
bool success = helloWorld(ref ptrNativeData, ref itemsLength);
if (!success) {
return;
}
S[] SArray = new S[itemsLength]; // Where the final data will be stored.
IntPtr[] SPointers = new IntPtr[itemsLength];
Debug.Log("Length: " + itemsLength); // Works!
Marshal.Copy(ptrNativeData, SPointers, 0, itemsLength); // Seems not to work.
for (int i = 0; i < itemsLength; i++) {
Debug.Log("Pointer: " + SPointers[i]); // SPointers[0] prints 0.
Marshal.PtrToStructure(SPointers[i], SArray[i]); // Crashes here. Boom.
}
}
[DllImport("TestUnity")]
private static extern bool helloWorld(ref IntPtr ptrResultVerts,
ref int resultVertLength);
Marshal.PtrToStructure
Инструкция говорит, что аргумент SPointers [i] является нулевым. Я проверил с помощью команды Debug.Log, и на самом деле он кажется нулевым: он печатает как 0.
Но я попробовал нечто подобное с массивомint
раньше, и это сработало. В чем я не уверен: моя проблема в C ++ или в C #? Я не передаю правильную информацию или неправильно обрабатываю?
Это было первое решение, которое я придумал в основном самостоятельно. Второе решение лучше.
Абсолютно благодаря Алексу Скалозубу, я понял это. Во время маршаллинга абстрагируется один уровень косвенности указателя. Итак, теперь мой код C ++ содержит:
S ** s; // Not a pointer to Ss, but a pointer to pointers to Ss.
bool helloWorld(S *** a, int * i) { // Pass a triple pointer.
s = new S * [4]; // Create array of pointers.
for (int j = 0; j < 4; j++) {
s[j] = new S; // Actually create each object.
s[j]->i = j;
s[j]->f = (float) j;
}
*a = s;
*i = 4;
return true;
}
И мой код C # содержит:
for (int i = 0; i < itemsLength; i++) {
Debug.Log("Pointer: " + SPointers[i]);
SArray[i] = (S) Marshal.PtrToStructure(SPointers[i], typeof(S));
}
И это все! Все данные передаются.
Теперь это оставляет меня с проблемой управления памятью:каждый отдельный объект, созданный в коде C ++, должен быть освобожден, Я знаю об этом, и я позабочусь об этом дальше.
Решение 2Смотрите проверенный ответ. Ответ Алекса намного лучше, поскольку он намного меньше использует ненужные указатели. Я использовал больше указателей, потому что я только что понял, как использовать их в C #.