2011-01-02 14 views
14

Permítanme comenzar diciendo que he buscado y encontrado descripciones del uso de {} fijo, Marshal.AllocHGlobal() y GCHandle .Aloc() a través de este foro y en muchos enlaces en la web. Sin embargo, todavía tengo que encontrar una explicación concisa sobre cuándo usar la clase Marshal frente a la clase GCHandle (con y sin utilizar fixed {}).Comprender la diferencia entre el uso de {} fijo, Marshal.AllocHGlobal() y GCHandle.Alloc()

Estoy usando una biblioteca .NET de terceros que tiene un método llamado Readline() en una clase "Buffer". El manual muestra el siguiente prototipo de función:

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

con una descripción de bufData que dice: ... El área de memoria debe tener un número de bytes mayores o iguales a la longitud por la línea el valor devuelto por la propiedad BytesPerPixel.

Ahora más adelante en el manual del usuario que hacen dar un ejemplo de acceso a la memoria intermedia (que he retocado un poco para mi ejemplo específico):

// 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(); 

y pude seguir las indicaciones anteriores "ejemplo" código con:

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

// Unpin the array 
dataLineHandle.Free() 

Ese podría ser el final de la historia (y todavía tengo que probar el código anterior), pero terminé googlear la clase GCHandle la que me llevó por el camino de .NET interoperab ility, PInvoke, etc.

Así que mis preguntas ... 1) ¿Por qué no puedo usar:

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

y pasar eso en ReadLine()?

2) ¿Puedo utilizar el siguiente fragmento de código (extraído y ajustado a partir de ejemplos en la 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); 
} 

Estaría interesado en nadie puede arrojar luz sobre las técnicas anteriores y señalar mis errores en la implementación, así como señalar cuándo los métodos anteriores son apropiados. Finalmente, incluso si los métodos anteriores son todos válidos, ¿hay un impulso general en los últimos años hacia un enfoque u otro?

Gracias de antemano! Hyped

+0

Eso suena como una horrible API. – SLaks

Respuesta

2

Bueno, la alternativa probablemente también funcione. Pero la muestra Marshal.AllocHGlobal no está completa, ahora tiene los datos en la memoria no administrada. Aún necesita trabajar para obtenerlo en un objeto administrado (matriz) para que pueda acceder fácilmente, debe llamar a Marshal.Copy(). Ineficiente ya que copia los datos dos veces. Y no te olvides de llamar a Marshal.FreeHGlobal().

La muestra fija hace lo mismo que la muestra del proveedor, implícitamente fija la memoria. La incomodidad aquí es que la API toma un IntPtr, no un byte *. Y debe cambiar la configuración de compilación para permitir la palabra clave insegura. No es de otra manera más eficiente.

No se adelanta al hacer esto de manera diferente.

+0

Hans - si tuviera una función DLL no administrada a la que llamaba que requiriera un puntero de byte para un bloque de memoria que "llenaría", ¿hay alguna preferencia sobre el uso de "Marshal" frente a "GCHandle"? Gracias por su respuesta anterior. – Hyped

+0

@Hyped - su preferencia debe * siempre * ser permitir que el P/Invoke Marshaller lo haga. Eso es casi siempre posible. Deberías declarar el argumento como una matriz en tu ejemplo. Como byte [] o PixelData [] donde PixelData es una estructura con dos miembros de byte. –

Cuestiones relacionadas