c# .net pinvoke unmanaged managed

c# - ¿Qué sucede exactamente durante una “transición administrada a nativa”?



.net pinvoke (5)

Entiendo que el CLR necesita hacer cálculos en algunos casos, pero digamos que tengo:

using System.Runtime.InteropServices; using System.Security; [SuppressUnmanagedCodeSecurity] static class Program { [DllImport("kernel32.dll", SetLastError = false)] static extern int GetVersion(); static void Main() { for (; ; ) GetVersion(); } }

Cuando entro en este programa con un depurador, siempre veo:

Dado que no es necesario realizar un cálculo de referencias (¿verdad?), ¿Podría alguien explicar lo que realmente está sucediendo en esta "transición gestionada a nativa" y por qué es necesario?


Además de la capa de cálculo de referencias, que es responsable de convertir los parámetros para usted y de averiguar las convenciones de llamadas, el tiempo de ejecución debe hacer algunas otras cosas para mantener el estado interno consistente.

El contexto de seguridad debe verificarse para asegurarse de que el código de llamada tenga acceso a métodos nativos. El marco de la pila administrada actual debe guardarse, de modo que el tiempo de ejecución pueda hacer un recorrido de la pila para cosas como la depuración y el manejo de excepciones (sin mencionar el código nativo que llama a una devolución de llamada administrada). Los bits de estado internos deben configurarse para indicar que actualmente estamos ejecutando código nativo.

Además, es posible que los registros deban guardarse, dependiendo de lo que se deba rastrear y de los cuales la convención de llamadas garantiza que se restaurarán. Las raíces de GC que están en los registros (locales) pueden necesitar estar marcadas de alguna manera para que no se recojan los residuos durante el método nativo.

Por lo tanto, principalmente se trata del manejo de la pila y el cálculo de tipo, con algunas cosas de seguridad incorporadas. Aunque no es una gran cantidad de cosas, representará una barrera significativa para evitar métodos nativos más pequeños. Por ejemplo, tratar de P / Invocar en una biblioteca matemática optimizada rara vez resulta en una ganancia de rendimiento, ya que la sobrecarga es suficiente para negar cualquiera de los beneficios potenciales. Algunos resultados de perfiles de rendimiento se discuten here .


Me doy cuenta de que esto ha sido respondido, pero me sorprende que nadie haya sugerido que muestres el código externo en la ventana de depuración. Si hace clic con el botón derecho en la línea [Native to Managed Transition] y marca la opción Show External Code , verá exactamente qué métodos .NET se están llamando en la transición. Esto puede darle una mejor idea. Aquí hay un ejemplo:


Primero debe configurarse la pila de llamadas para que pueda ocurrir un STDCALL. Esta es la convención de llamada para Win32.

A continuación, el tiempo de ejecución empujará un llamado marco de ejecución. Hay muchos tipos diferentes de marcos: aserciones de seguridad, regiones protegidas por GC, llamadas de código nativo, ...

El tiempo de ejecución utiliza un marco de este tipo para rastrear el código que actualmente se está ejecutando. Esto tiene implicaciones para una recolección de basura potencialmente concurrente y probablemente otras cosas. También ayuda al depurador.

Así que no mucho está sucediendo aquí en realidad. Es un camino de código bastante delgado.


Realmente no puedo ver mucho que sería necesario hacer. Sospecho que es principalmente informativo, para indicarle que parte de su pila de llamadas muestra funciones nativas, y también para indicar que el IDE y el depurador pueden comportarse de manera diferente en esa transición (dado que el código administrado se maneja de manera muy diferente en el depurador, y algunas características que esperas pueden no funcionar)

Pero supongo que debería poder averiguarlo simplemente inspeccionando el desmontaje alrededor de la transición. A ver si hace algo inusual.


Ya que estás llamando a un dll. Necesita salir del entorno gestionado. Se va al núcleo de windows. Estás rompiendo la barrera .net y entrando en el código de Windows que no funciona igual que .NET.