2012-04-04 11 views
10

Tengo un complemento de C# que utiliza una DLL de C++ por separado. La única referencia a esa DLL es desde el plugin en sí. La aplicación principal carga todos los complementos en su propio AppDomain y descarga este AppDomain cuando se descarga el complemento.C++ DLL no se descarga con AppDomain

He comprobado, y definitivamente veo la memoria de la aplicación caer cuando descargo el complemento. También puedo eliminar todos los ensamblados administrados que se cargaron. El problema es que cuando trato de eliminar el archivo DLL nativo sigo obteniendo acceso denegado hasta que cierro toda la aplicación.

He estado mirando esto por un tiempo, pero todavía no puedo entender por qué solo esta DLL permanece en la memoria.

Respuesta

18

Los AppDomains son una construcción de código administrado puro. Nada de eso existe en el código nativo, y Windows tampoco tiene idea al respecto. Entonces, el alcance de una DLL nativa cargada es el proceso. Técnicamente, el marshaller de Pinvoke podría referenciar el conteo de la DLL y hacer un seguimiento exacto de qué AppDomain desencadenó la carga de la DLL. Sin embargo, no puede decir si se está ejecutando algún código nativo que use esa DLL. Código nativo que podría iniciarse mediante una llamada hecha desde el código en otro AppDomain, posiblemente indirectamente a través de un delegado clasificado.

Claramente el desastre golpea si el administrador AppDomain descarga una DLL que se usa de esa manera, eso es desagradable e imposible de diagnosticar AccessViolation. Particularmente desagradable, ya que puede desencadenarse mucho tiempo después de que se descargó AppDomain.

Así que el Marshaller no implementa ese tipo de conteo, la DLL permanece cargada. Solo usted puede proporcionar la garantía de que esto no puede suceder, usted tiene cierto grado de control sobre exactamente qué código se ejecuta en el DLL y cómo se inicia. Usted puede forzar la DLL para descargar, pero requiere un hack. Pinvoke LoadLibrary() usted mismo para obtener un control de la DLL. Y pinvoke FreeLibrary() dos veces para descargarlo por la fuerza. Ni Windows ni el CLR no pueden ver que estás haciendo trampa. Usted debe asegurarse de que la DLL no se puede utilizar después de esto.

+3

+1 buen truco :-) – Yahia

+0

¡Hola, solo quería decir gracias por la respuesta muy clara! – user472875

5

AFAIK (bajo la campana) DLL nativas necesitan ser cargados a través de Win32 API LoadLibrary ... que los carga directamente en la memoria de proceso - en caso de una aplicación de .NET que no es específico de un AppDomain ... LoadLibrary sabe absolutamente nada sobre AppDomain (que es puramente-NET específico) ... descargando así el AppDomain no necesariamente descargar archivos DLL nativos ...

discusiones interesantes con respecto a esta situación:

si se puede cambiar la aplicación de la correspondiente plug-in, entonces sería poner en práctica "el enlace en tiempo nativo" que resolvería el problema que se ve:

Cuestiones relacionadas