2009-12-11 10 views
22

que tienen la siguiente estructura:Marshal.AllocHGlobal VS Marshal.AllocCoTaskMem, Marshal.SizeOf VS sizeof()

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
public struct WAVEHDR 
{ 
    internal IntPtr lpData; // pointer to locked data buffer 
    internal uint dwBufferLength; // length of data buffer 
    internal uint dwBytesRecorded; // used for input only 
    internal IntPtr dwUser; // for client's use 
    internal uint dwFlags; // assorted flags (see defines) 
    internal uint dwLoops; // loop control counter 
    internal IntPtr lpNext; // reserved for driver 
    internal IntPtr reserved; // reserved for driver 
} 

necesito para asignar memoria no administrado para almacenar una instancia de estructura anterior. Un puntero a esta estructura se pasará a waveOut funciones API de Win32 (waveOutPrepareHeader, waveOutWrite, waveOutUnprepareHeader).

  1. ¿Debo usar Marshal.AllocHGlobal() o Marshal.AllocCoTaskMem()? ¿Cuál es la diferencia?
  2. ¿Debo pasar sizeof(WAVEHDR) o Marshal.SizeOf(typeof(WAVEHDR)) al método de asignación de memoria? ¿Cuál es la diferencia?

NOTA de que es preciso fijar la memoria asignada.

Respuesta

38

Un programa de Windows siempre tiene al menos dos montones en el que se asigna memoria no administrada. Primero está el montón de procesos predeterminado, utilizado por Windows cuando necesita asignar memoria en nombre del programa. El segundo es un montón utilizado por la infraestructura COM para asignar. El .NET P/Invoke Marshaller supone que este montón fue utilizado por cualquier código no administrado cuya firma de función requiera la desasignación de memoria.

AllocHGlobal asigna desde el montón de procesos, AllocCoTaskMem asigna desde el montón COM.

Cuando escribe código de interoperabilidad no administrado, siempre debe evitar una situación en la que el código que asigna memoria no administrada no sea el mismo que el código que lo libera. Habría una buena posibilidad de que se use el desasignador equivocado. Esto es especialmente cierto para cualquier código que interopera con un programa C/C++. Dichos programas tienen su propio asignador que usa su propio montón, creado por el CRT al inicio. Desasignar tal memoria en otro código es imposible, no puede obtener de manera confiable el manejador de pila. Esta es una fuente muy común de problemas de P/Invoke, especialmente porque la función HeapFree() en XP y versiones anteriores ignoran silenciosamente solicitudes para liberar memoria que no estaba asignada en el montón correcto (filtrando la memoria asignada) pero Vista y Win7 bloquean el programa con una excepción

No hay necesidad de preocuparse por esto en su caso, las funciones de mmsystem API que está utilizando están limpias. Fueron diseñados para asegurar que el mismo código que asigna también desasigne. Esta es una razón por la que tiene que llamar waveInPrepareHeader(), que asigna buffers con el mismo código que en última instancia les desasigna. Probablemente con el montón de proceso predeterminado.

sólo es necesario para alojar la estructura WAVEHDR. Y usted es responsable de liberarlo cuando haya terminado con él. Las API de mmsystem no lo hacen por usted, sobre todo porque no pueden hacerlo de manera confiable. Por lo tanto, puede usar cualquiera de los dos asignadores, solo necesita asegurarse de llamar al método gratuito correspondiente. Todas las API de Windows funcionan de esta manera. Yo uso CoTaskMemAlloc() pero realmente no hay una preferencia. Solo que si estoy llamando al código mal diseñado, es ligeramente más probable usar el montón COM.

Nunca debe usar sizeof() en un escenario de interoperabilidad. Devuelve el tamaño gestionado del tipo de valor. Puede que no sea lo mismo después de que el intérprete de comandos P/Invoke haya traducido un tipo de estructura de acuerdo con las directivas [StructLayout] y [MarshalAs]. Solo Marshal.SizeOf() te da un valor correcto garantizado.


ACTUALIZACIÓN: hubo un gran cambio en VS2012. La biblioteca de tiempo de ejecución de C que se incluye ahora asigna desde el montón de proceso predeterminado en lugar de usar su propio montón. A largo plazo, eso hace que AllocHGlobal sea la vía más probable para el éxito.

+1

¿Hay alguna diferencia de rendimiento entre las dos funciones de asignación? – DxCK

+3

'AllocCoTaskMem' es más eficiente. 'AllocHGlobal' llama' LocalAlloc', que tiene la siguiente nota: "Las funciones locales tienen una sobrecarga mayor y proporcionan menos características que otras funciones de administración de memoria". Ver https://msdn.microsoft.com/en-us/library/windows/desktop/aa366723(v=vs.85).aspx – IamIC

2

1) Marshal.AllocHGlobal funcionará con seguridad. Sobre la base de la documentación para Marshal.AllocCoTaskMem, Marshal.AllocCoTaskMem debería funcionar también.

2) Use Marshal.SizeOf (typeof (WAVEHDR)). Although you can use the Marshal.SizeOf method, the value returned by this method is not always the same as the value returned by sizeof. Marshal.SizeOf returns the size after the type has been marshaled, whereas sizeof returns the size as it has been allocated by the common language runtime, including any padding.

1

2) Por lo que sé la sizeof sólo pueden utilizarse con tipos que tienen un tamaño predefinido en el tiempo de compilación.

Así que use Marshal.SizeOf(typeof(WAVEHDR)).

Cuestiones relacionadas