Marshalling C-Strukturen zu C #

8

Angenommen, ich habe eine Struktur:

%Vor%

und eine C ++ Funktion:

%Vor%

Zuerst - meine IDE. Ich verwende Visual Studio 2010 und erstelle eine C # (4.0) -Anwendung. Der C ++ Teil ist auch in VS2010 eingebaut.

Ich weiß, wie man eine DLL von C / C ++ - Code erstellt und sie in C # -Anwendungen verwendet, aber bis heute habe ich nur primitive Argumente verwendet und gebe Werte zurück wie:

%Vor%

Heute muss ich ein Array von structs übergeben (wie im obigen Beispiel) .. und vielleicht auch eins zurück ..

Wie kann ich eine C # -Klasse in eine C-Struktur "übersetzen" (und umgekehrt) ??

    
Queequeg 30.11.2011, 19:27
quelle

2 Antworten

8

Die Struktur kann wie folgt deklariert werden:

%Vor%

Als nächstes müssen Sie auf einer Aufrufkonvention beruhigen. Ihr C ++ Code wird fast sicher mit cdecl kompiliert. Bleiben wir dabei.

Die erste Funktion ist einfach von C # aus aufzurufen:

%Vor%

Beachten Sie, dass Sie SetLastError nicht hier verwenden sollten - das ist für Windows-API-Funktionen. Und es ist nicht nötig, CharSet zu setzen, da hier kein Text vorhanden ist.

Nun, für another werden die Dinge komplexer. Wenn Sie den Speicher im C # -Code reservieren können, dann ist das definitiv der Weg zu gehen.

%Vor%

Auf der C # -Seite deklarieren Sie es wie folgt:

%Vor%

und nenne es so

%Vor%

Wenn Sie nicht auf der C # -Seite des Zauns reservieren möchten, dann tun Sie das wie folgt:

  1. Geben Sie einen Zeiger aus dem C ++ - Code zurück und weisen Sie ihn mit CoTaskMemAlloc .
  2. zu
  3. Deklarieren Sie in C # den Rückgabewert der importierten Funktion als IntPtr .
  4. Verwenden Sie Marshal.PtrToStructure und einige Zeigerarithmetik, um das Rückgabearray in ein C # -Array zu marshalieren.
  5. Rufen Sie Marshal.FreeCoTaskMem auf, um den im nativen Modul zugewiesenen Speicher freizugeben.

Aber wenn Sie meinen Rat brauchen, versuchen Sie, das Array im verwalteten Code zuzuordnen.

    
David Heffernan 30.11.2011, 19:45
quelle
3

Es sollte so einfach sein:

%Vor%

Die Probleme, auf die Sie möglicherweise stoßen, wären, wenn in der C-Version der Struktur und möglicherweise im Strukturlayout ein Packen ausgeführt wird. Wenn das Layout nicht übereinstimmt, möchten Sie es möglicherweise in LayoutKind.Explicit ändern und das Attribut [FieldOffset(0)] für jedes Feld verwenden. C hätte auch keine Ahnung, die Länge des Vertices-Arrays wurde überschritten. Wenn sich das ändert, möchten Sie das an die Methode weiterleiten.

Um ein Array zurück zu bekommen:

%Vor%

Der Marshaler behandelt alle Speicherprobleme beim Übergeben von Argumenten in, aber beim Zurückgeben des Arrays kann er nichts tun. Da der Speicher auf dem nicht verwalteten Heap zugeordnet ist, hat der GC keine Ahnung davon, und Sie werden mit einem Speicherverlust enden. Der Marshaller kopiert einfach die systemeigenen Strukturen in das Array der verwalteten Struktur, kann jedoch den Speicher, den Sie zugewiesen haben, nicht mit malloc freigeben.

Der einfachste Weg, um es zu umgehen, wenn Sie den C ++ - Code ändern können, wäre, die Signatur von another zu ändern, um ein Array von Vertices (und die Länge des Arrays) aufzunehmen, anstatt eins zurückzugeben. Ich muss keinen Code für dich schreiben, der das tut, @DavidHeffernan hat dies bereits in seiner Antwort getan, dem Teil der Pause.

    
Christopher Currens 30.11.2011 19:36
quelle

Tags und Links