2011-01-02 8 views
14

Vorrei iniziare dicendo che ho cercato e trovato descrizioni dell'uso di fixed {}, Marshal.AllocHGlobal() e GCHandle . Alloc() in tutto questo forum e in molti link sul web. Tuttavia, devo ancora trovare una spiegazione concisa su quando utilizzare la classe Marshal contro la classe GCHandle (con e senza usare fixed {}).Comprensione delle differenze tra l'uso di fixed {}, Marshal.AllocHGlobal() e GCHandle.Alloc()

Sto usando una libreria .NET di terze parti che ha un metodo chiamato Readline() in una classe "Buffer". Il manuale mostra il seguente prototipo di funzione:

bool ReadLine (int x1, int y1, int x2, int y2, System.IntPtr bufData, out int numRead);

con una descrizione di bufData che dice: ... L'area di memoria deve avere un numero di byte maggiore o uguale al tempo della lunghezza della linea il valore restituito dalla proprietà BytesPerPixel.

Ora più avanti nel manuale d'uso che fanno dare un esempio di accesso del buffer (che ho ottimizzato un po 'per il mio esempio specifico):

// Create an array large enough to hold one line from buffer 
int size = 640; 
byte[] dataLine = new byte[size * 2]; // 2 bytes per pixel 

// Pin the array to avoid Garbage collector moving it 
GCHandle dataLineHandle = GCHandle.Alloc(dataLine, GCHandleType.Pinned); 
IntPtr dataLineAddress = dataLineHandle.AddrOfPinnedObject(); 

e ho potuto seguire le indicazioni sopra "example" codice con:

// Read one line of buffer data 
success = buffer.ReadLine(0, 0, 639, 0, dataLineAddress, out numRead); 

// Unpin the array 
dataLineHandle.Free() 

che potrebbe essere la fine della storia (e devo ancora testare il codice di cui sopra), ma ho finito per googling la classe GCHandle che mi ha spinto verso il basso il percorso di .NET interoperab ility, PInvoke, ecc

Così le mie domande ... 1) Perché non posso usare:

IntPtr dataLineAddress = Marshal.AllocHGlobal(size * 2); 

e passare che in ReadLine()?

2) Posso utilizzare il seguente frammento di codice (estratto e ottimizzato dagli esempi sul web):

int size = 640; 
byte[] dataLine= new byte[size * 2]; // 2 bytes per pixel 

// prevent garbage collector from moving buffer around in memory 
fixed (byte* fixedDataLine = dataLine) 
{ 
    // get IntPtr representing address of first buffer element 
    IntPtr dataLineAddress= Marshal.UnsafeAddrOfPinnedArrayElement(fixedDataLine , 0); 
    success = buffer.ReadLine(0, 0, 639, 0, dataLineAddress, out numRead); 
} 

Mi sarebbe interessato in chiunque può mettere in luce le tecniche di cui sopra e segnalare i miei errori nell'implementazione, nonché sottolineare quando i metodi sopra indicati sono appropriati. Infine, anche se i metodi di cui sopra sono tutti validi, c'è una spinta generale negli ultimi anni verso un approccio o l'altro?

Grazie in anticipo !! Hyped

+0

Sembra un'API orribile. – SLaks

risposta

2

Bene, l'alternativa probabilmente funzionerà anche. Ma l'esempio Marshal.AllocHGlobal non è completo, ora hai i dati nella memoria non gestita. È ancora necessario lavorare per portarlo in un oggetto gestito (array) in modo da poterlo facilmente accedere, è necessario chiamare Marshal.Copy(). Inefficiente poiché copia i dati due volte. E non dimenticare di chiamare Marshal.FreeHGlobal().

L'esempio fisso fa la stessa cosa dell'esempio del fornitore, impegna implicitamente la memoria. L'imbarazzo è che l'API prende un IntPtr, non un byte *. Ed è necessario modificare le impostazioni di compilazione per consentire la parola chiave non sicura. Non è altrimenti più efficiente.

Non sei avanti in questo modo in modo diverso.

+0

Hans: se avessi una funzione DLL non gestita che stavo chiamando che richiedeva un puntatore byte a un blocco di memoria che avrebbe "riempito", c'è una preferenza nell'usare "Marshal" vs "GCHandle"? Grazie per la tua risposta sopra. – Hyped

+0

@Hyped - la tua preferenza dovrebbe * sempre * essere quella di consentire al marshaller P/Invoke di farlo. Questo è quasi sempre possibile. Dichiareresti l'argomento come una matrice nel tuo esempio. Come byte [] o PixelData [] dove PixelData è una struttura con due membri byte. –