Comienza bastante fácil. El marshaller de pinvoke primero llama a LoadLibrary y le pasa el nombre de DLL que usted especificó, la propiedad DllImportAttribute.Value. En su caso, user32.dll ya está cargado porque se carga por el iniciador de .NET, su recuento de referencia se incrementa. Pero normalmente el cargador de Windows obtiene la DLL asignada en el espacio de direcciones del proceso para que se puedan llamar las funciones exportadas.
El siguiente es GetProcAddress para obtener la dirección de la función para llamar, la propiedad DllImportAttribute.EntryPoint. El marshaller hace un par de intentos a menos que uses ExactSpelling. Un nombre de función como "foo" se prueba de varias maneras posibles, foo y fooW o fooA. Detalles desagradables de implementación de Win32 relacionados con la diferencia entre los caracteres Unicode y Ansi. La propiedad CharSet es importante aquí.
Ahora necesito agitar las manos un poco porque se pone complicado. El Marshal construye un marco de pila, configurando los argumentos que necesitan pasar a la función exportada. Esto requiere un código de bajo nivel, cuidadosamente excluido de las miradas indiscretas. Tómese el valor nominal de que realiza el tipo de traducciones que admite la clase Marshal para convertir entre tipos administrados y no administrados. La propiedad DllImportAttribute.CallingConvention importa aquí porque eso determina qué valor de argumento debe colocarse donde para que la función llamada pueda leerlo correctamente.
A continuación, configura un manejador de excepciones SEH para que las excepciones de hardware generadas por el código llamado se puedan capturar y traducir a una excepción administrada. El que genera el más común, AccessViolationException. Y otros.
A continuación, empuja una cookie especial en la pila para indicar que el código no administrado está a punto de comenzar a usar la pila. Esto evita que el recolector de basura se meta en marcos de pila no gestionados e interprete los punteros que encuentra allí como referencias de objetos gestionados. Puede volver a ver esta cookie en la pila de llamadas del depurador, [Transición de administrado a nativo].
A continuación, solo una llamada indirecta a la dirección de función que se encuentra con GetProcAddress(). Eso hace que se ejecute el código no administrado.
Después de la llamada, es posible que sea necesario realizar una limpieza para liberar la memoria que se asignó para pasar los argumentos no administrados. El valor de retorno podría necesitar ser traducido nuevamente a un valor administrado. Y eso es todo, suponiendo que nada desagradable sucediera, la ejecución continúa en la siguiente declaración del código administrado.
Es posible que desee crear un envoltorio alrededor del componente no administrado, e implementar la interfaz 'IDisposable', de una forma más limpia de deslocalizarlo. El recolector de basura llama a la función definida en esta interfaz para evitar que se "olvide" limpiar. –
Puede envolverlo en IDisposable, pero asegúrese de llamar a Dispose o anular el finalizador. Simplemente implementar IDispose no es suficiente, el GC no llama a Dispose, sino a Object.Finalize (ver http://stackoverflow.com/questions/45036/will-the-gc-call-disposable-dispose-for-me) – pstrjds