2009-01-30 4 views
11

Ich habe dieses C++ Code:Muss ich über Marshal.PtrToStructure gemarshallte Strukturen im nicht verwalteten Code löschen?

extern "C" __declspec(dllexport) VOID AllocateFoo(MY_DATA_STRUCTURE** foo) 
{ 
    *foo = new MY_DATA_STRUCTURE; 

    //do stuff to foo 
} 

Dann in C# rufe ich die Funktion so:

[DllImport("MyDll.dll")] 
static extern void AllocateFoo(out IntPtr pMyDataStruct); 

... 

MyDataStructure GetMyDataStructure() 
{ 
    IntPtr pData; 
    ManagedAllocateFooDelegate(out pData); 

    MyDataStructure foo = (MyDataStructure)Marshal.PtrToStructure(pData, typeof(MyDataStructure)); 
    return foo; 
} 

Wo MyDataStructure eine Struktur (nicht-Klasse), die in geeigneter Weise vermarshallten MY_DATA_STRUCTURE und Mitglieder entspricht.

Also Fragen: Muss ich pData speichern und dann wieder in nicht verwalteten Code freigeben, wenn MyDataStructure GC'd ist? MSDN sagt für Marshal.PtrToStructure (IntPtr, Type): "Marshalf Daten aus einem nicht verwalteten Speicherblock zu einem neu zugeordneten verwalteten Objekt des angegebenen Typs." In diesem Satz bedeutet "Marshall" "Kopie"? In diesem Fall müsste ich (IntPtr pData) beibehalten und dann an nicht verwalteten Code übergeben (im MyDataStructure-Destruktor), damit ich C++ "delete" machen kann?

Ich habe gesucht, aber ich kann keine ausreichend explizite Antwort dafür finden.

+0

Ihre nicht verwaltete Funktion, AllocateFoo, funktioniert nicht wie beschrieben. Sie benötigen eine zusätzliche Indirektionsstufe, um den Zeiger an den Aufrufer zurückzugeben. d. H. AllocateFoo (MY_DATA_STRUCTURE * * foo) { * foo = neu MY_DATA_STRUCTURE; } – GBegen

+0

Ja, Sie haben Recht! Mein tatsächlicher Code verwendet PMY_DATA_STRUCTURE *, ich werde den Beitrag bearbeiten. – Serguei

Antwort

10

Wie Erik sagte, der Marshal bedeutet Kopie, aber ich glaube nicht, dass er den Hauptpunkt Ihrer Frage beantwortet hat.

Müssen Sie den nativen Zeiger pData festhalten, bis die MyDataStructure GCed ist?

Nach dem Marshalling enthält Ihre MyDataStructure-Instanz foo eine Kopie der Struktur, auf die pData verweist. Sie müssen nicht länger an pData festhalten. Um einen Speicherverlust zu vermeiden, müssen Sie diese pData in eine andere nicht verwaltete Funktion übergeben, die sie löscht. Dies kann direkt nach dem Marshalling erfolgen, unabhängig davon, wie lange Sie an der MyDataStructure-Instanz festhalten.

7

Ja, in diesem Fall bedeutet Marshall Kopie; Daher müssen Sie den Speicher in nicht verwaltetem Code freigeben. Der gesamte Aufruf von PtrToStructure liest eine Anzahl von Bytes, die durch die Größe der Zielstruktur 'MyDataStructure' angegeben ist, von dem Speicherort, auf den pData zeigt.

Die Details hängen natürlich genau davon ab, wie "MyDataStructure" aussieht (verwenden Sie irgendwelche FieldOffset oder StructLayout Attribute in MyDataStructure) - aber das Ergebnis ist, dass die Rückkehr von PtrToStructure eine Kopie der Daten ist.

Wie zeigt in his answer, ich habe den Hauptpunkt Ihrer Frage nicht beantwortet. Ja, Sie müssen die nicht verwaltete Kopie Ihrer Struktur in nicht verwaltetem Code löschen, aber nein, Sie müssen pData nicht beibehalten - Sie können die nicht verwaltete Kopie löschen, sobald der Aufruf von PtrToStructure abgeschlossen ist.

PS: Ich habe meinen Beitrag bearbeitet, um diese Informationen zu enthalten, um die Antworten in einem Beitrag zu konsolidieren - wenn jemand diese Antwort upsendet, dann bitte auch GBegens Antwort für seinen Beitrag.