Kann Array von Stucts von C ++ nach C # in Unity nicht marshallen

Ich versuche, ein Array von @ zu übergebstructs von C ++ zu einem Unity-Skript in C #. Wenn ich den Code in der Produktion verwende, variiert die Größe des Arrays stark, sodass ich effektiv ein Array unbekannter Länge übergeben muss.

Meine clevere Idee war es, das Array auf dem Heap zu speichern und einen Verweis auf dieses Array an Unity zu übergeben. Ich habe StackOverflow-Beiträge dazu gefunden. Aber dann beschwert sich Unity, dass eine Referenz null ist.

Hier ist ein Teil meines C ++ - Codes:

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

Ich habe das mit @ versucints stattstructs und es hat funktioniert.

Jetzt ist mein C # -Code:

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

DasMarshal.PtrToStructureie @ -Anweisung besagt, dass das SPointers [i] -Argument null ist. Ich habe es mit dem Debug.Log-Befehl überprüft und tatsächlich scheint es null zu sein: Es wird als 0 ausgegeben.

Aber ich habe etwas Ähnliches mit einem Array von @ versucints früher und das hat funktioniert. Was ich mir nicht sicher bin ist: Liegt mein Problem in C ++ oder in C #? Übergebe ich nicht die richtigen Informationen oder verarbeite ich die richtigen Informationen falsch?

Lösung 1

Dies war die erste Lösung, die ich mir größtenteils selbst ausgedacht habe. Die zweite Lösung ist besser.

ank Alex Skalozub habe ich es herausgefunden. Eine Ebene der Zeiger-Indirektion wird beim Marshalling abstrahiert. Also jetzt enthält mein C ++ - Code:

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

Und mein C # -Code enthält:

for (int i = 0; i < itemsLength; i++) {
  Debug.Log("Pointer: " + SPointers[i]);
  SArray[i] = (S) Marshal.PtrToStructure(SPointers[i], typeof(S));
}

Und das ist es! Alle Daten werden übertragen.

Jetzt habe ich ein Problem mit der Speicherverwaltung:jedes einzelne Objekt, das im C ++ - Code erstellt wurde, muss freigegeben werden. Ich bin mir dessen bewusst und werde mich als nächstes darum kümmern.

Lösung 2

Siehe die überprüfte Antwort. Die Antwort von Alex ist viel besser, da unnötige Zeiger weniger verwendet werden. Ich habe mehr Zeiger verwendet, weil ich gerade herausgefunden habe, wie man sie in C # verwendet.

Antworten auf die Frage(4)

Ihre Antwort auf die Frage