2009-01-30 4 views
11

Ho questo codice C++:Devo eliminare le strutture sottoposte a marshalling tramite Marshal.PtrToStructure nel codice non gestito?

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

    //do stuff to foo 
} 

Poi 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 classe) che corrisponde alla MY_DATA_STRUCTURE e membri sono marshalling appropriato.

Quindi domande: devo memorizzare pData e poi rilasciarlo di nuovo nel codice non gestito quando MyDataStructure è GC'd? MSDN dice per Marshal.PtrToStructure (IntPtr, Type): "Esegue il marshaling dei dati da un blocco di memoria non gestito a un oggetto gestito appena assegnato del tipo specificato." In questa frase "Marshall" significa "copia"? In tal caso, dovrei conservare (IntPtr pData) e poi passarlo a codice non gestito (nel distruttore MyDataStructure) in modo da poter eseguire un "delete" C++?

Ho cercato ma non riesco a trovare una risposta sufficientemente esplicita per questo.

+0

La tua funzione non gestita, AllocateFoo, non funziona come scritto. È necessario un livello aggiuntivo di riferimento indiretto per riportare il puntatore al chiamante. e, AllocateFoo (MY_DATA_STRUCTURE * * foo) { * foo = new MY_DATA_STRUCTURE; } – GBegen

+0

Sì hai ragione! Il mio codice attuale utilizza PMY_DATA_STRUCTURE *, modifico il post. – Serguei

risposta

10

Come ha detto Erik, il maresciallo significa copia, ma non penso che abbia risposto al punto principale della tua domanda.

È necessario mantenere il puntatore nativo pData finché MyDataStructure non è GCed?

Una volta eseguito il marshalling, l'istanza MyDataStructure, foo, contiene una copia della struttura indicata da pData. Non hai più bisogno di aggrapparti a pData. Per evitare una perdita di memoria, è necessario passare tale pData a un'altra funzione non gestita che la eliminerà e che può essere eseguita subito dopo il marshalling, indipendentemente dalla durata dell'istanza MyDataStructure.

7

Sì, in questo caso, Marshall significa copia; quindi, devi deallocare la tua memoria nel 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 puntata da pData.

I dettagli naturalmente dipendono esattamente da cosa appare "MyDataStructure" (si utilizzano gli attributi FieldOffset o StructLayout in MyDataStructure), ma il risultato finale è che il ritorno da PtrToStructure è una copia dei dati.

As indica his answer, non ho risposto al punto principale della domanda. Sì, sarà necessario eliminare la copia non gestita della struttura nel codice non gestito, ma no, non è necessario tenere premuto pData: è possibile eliminare la copia non gestita non appena viene completata la chiamata a PtrToStructure.

PS: ho modificato il mio post per contenere queste informazioni in modo da consolidare le risposte in un solo post - se qualcuno ha risposto a questa risposta, si prega di invitare anche la risposta di GBegen per il suo contributo.