2011-11-20 11 views
6

Estoy intentando escribir un pinvoke para el método ITaskTrigger :: GetTriggerString (definido en http://msdn.microsoft.com/en-us/library/windows/desktop/aa381866(v=vs.85).aspx). Si nos fijamos en la página, dice que la persona que llama del método es responsable de liberar la memoria (a través de CoTaskMemFree) del LPWSTR al que se hace referencia mediante el primer argumento. Si bien podría hacerlo manualmente en .NET o podría escribir mi contador de referencias personalizadas utilizando ICustomMarshaler, me preguntaba si el uso del atributo MarshalAs (UnmanagedType.LPWStr) para ese argumento en particular liberará la memoria de manera apropiada.¿Usarás la memoria de limpieza MarshalAs (UnmanagedType.LPWStr)?

¿Alguien puede darnos una idea?

+0

Observe cómo funciona el tipo dinámico con COM Interop: esto puede hacer las cosas mucho más sencillas que el tipado estático y también se ocupa de la gestión de la memoria. – weismat

+0

¿Tiene alguna referencia para ese último bit? C# ya administra la memoria para la interoperabilidad COM, y siempre lo ha hecho. Los tipos dinámicos facilitan las cosas cuando se trata, por ejemplo, de una interfaz IDispatch, pero ¿tienen realmente características de gestión de memoria diferentes que los tipos de interoperabilidad estáticos? –

Respuesta

6

Lo primero es lo primero: está hablando de Interoperabilidad COM aquí (ITaskTrigger es una interfaz COM), no P/Invocar. Existen diferentes reglas de interoperabilidad para los dos, por lo que es importante mantenerlos en línea. Por ejemplo, deberá definir contenedores de interoperabilidad de C# para toda la interfaz, no solo el método que desee. Éstos deben comenzar: pinvoke.net

La respuesta corta es que estás de suerte, porque el CLR debería encargarse de las cosas adecuadamente.

La respuesta más larga implica los diferentes tipos de clasificación que hace el código de interoperabilidad COM, según los tipos de parámetros, las instrucciones y los atributos que agrega a sus firmas de interoperabilidad.

En este caso, el tipo de parámetro que obtendrá en la llamada es un parámetro "out string", con un atributo MarshalAs(UnmanagedType.LPWSTR). Cuando un servidor COM expone una llamada que tiene un parámetro "fuera" de LPWSTR tipo de cadena, suponiendo que el servidor mantiene su final de la transacción, asignará un búfer de memoria con CoTaskMemAlloc() y se lo devolverá. (Si era un tipo de cadena diferente, como BSTR, la llamada de asignación de memoria específica podría ser diferente, pero el concepto básico es el mismo.) En este punto, usted es responsable de limpiar esa memoria cuando ya no la necesita, usando la llamada correspondiente CoTaskMemFree().

Este es un tipo especial de operación que se llama un "cambio de referencia": el parámetro que va a enviar en el que ya es un parámetro de referencia, pero el servidor COM se va a sustituir con un diferente referencia. Una buena explicación para este proceso se encuentra en la sección "Propiedad de la memoria" de this MSDN magazine article. Como se puede ver en ese artículo, cuando el CLR recibe datos de un parámetro de "salida" en un tipo de referencia, reconoce que se está responsabilizando de liberar esa memoria. Al ordenar esa devolución de llamada al código administrado, utiliza el atributo MarshalAs para determinar que este es un puntero de tipo cadena LPWSTR en COM, y que, por lo tanto, debería haberse asignado usando CoTaskMemAlloc(). Después de crear una cadena administrada de los datos, llamará al CoTaskMemFree() en el buffer original en su nombre. Los datos que reciba serán totalmente administrados y no tendrá que lidiar con ningún problema de propiedad.

+1

¡Gracias por la respuesta! Eso lo aclara perfectamente. – wwahammy

+1

Muy buena explicación, gracias. –