Devo eliminare le strutture sottoposte a marshalling tramite Marshal.PtrToStructure in codice non gestito?
-
20-08-2019 - |
Domanda
Ho questo codice C ++:
extern "C" __declspec(dllexport) VOID AllocateFoo(MY_DATA_STRUCTURE** foo)
{
*foo = new MY_DATA_STRUCTURE;
//do stuff to foo
}
Quindi in C # chiamo la funzione così:
[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;
}
Dove MyDataStructure è una struttura (non di classe) che corrisponde a MY_DATA_STRUCTURE e i membri vengono raggruppati in modo appropriato.
Quindi domande: devo archiviare pData e poi rilasciarlo nuovamente in codice non gestito quando MyDataStructure è GC? MSDN dice per Marshal.PtrToStructure (IntPtr, Type): " Marshals i dati da un blocco di memoria non gestito a un oggetto gestito appena allocato del tipo specificato. " In quella frase fa & Quot; Marshall & Quot; significa " copia " ;? Nel qual caso dovrei conservare (IntPtr pData) e poi passarlo a codice non gestito (nel distruttore MyDataStructure) in modo da poter fare un C ++ & Quot; delete & Quot ;?
Ho cercato ma non riesco a trovare una risposta sufficientemente esplicita per questo.
Soluzione
Come ha detto Erik, il Maresciallo significa copia, ma non credo che abbia risposto al punto principale della tua domanda.
È necessario mantenere il puntatore nativo pData fino a quando MyDataStructure è GCed? No.
Una volta eseguito il marshalling, l'istanza MyDataStructure, foo, contiene una copia della struttura a cui punta pData. Non è più necessario conservare pData. Per evitare una perdita di memoria, è necessario passare quel pData in un'altra funzione non gestita che lo eliminerà e che può essere eseguita subito dopo il marshalling, indipendentemente dal tempo in cui si tiene l'istanza MyDataStructure.
Altri suggerimenti
Sì, in questo caso Marshall significa copia; pertanto, è necessario deallocare la memoria in codice non gestito. Tutta la chiamata a PtrToStructure fa leggere un numero di byte indicato dalla dimensione della struttura di destinazione "MyDataStructure" dalla posizione di memoria indicata da pData.
I dettagli ovviamente dipendono esattamente dall'aspetto di "MyDataStructure" (usi gli attributi FieldOffset o StructLayout in MyDataStructure) - ma il risultato finale è che il ritorno da PtrToStructure è una copia dei dati.
Come GBegen sottolinea in la sua risposta , non ho risposto al punto principale della tua domanda. Sì, dovrai eliminare la copia non gestita della tua struttura in codice non gestito, ma no, non è necessario conservare su pData: puoi eliminare la copia non gestita non appena termina la chiamata a PtrToStructure.
PS: ho modificato il mio post in modo da contenere queste informazioni in modo da consolidare le risposte in un post: se qualcuno vota questa risposta, si prega di valutare anche la risposta di GBegen per il suo contributo.