Nota
O acceso a esta páxina require autorización. Pode tentar iniciar sesión ou modificar os directorios.
O acceso a esta páxina require autorización. Pode tentar modificar os directorios.
.NET 7 incluye por primera vez un generador de código fuente para P/Invokes que reconoce en LibraryImportAttribute en el código de C#.
Cuando no se utiliza la generación de código fuente, el sistema de interoperabilidad integrado en el entorno de ejecución de .NET genera un stub de IL, una secuencia de instrucciones de IL que se compilan Just-In-Time (JIT) durante su ejecución para facilitar la transición del código administrado al no administrado. En el siguiente código se muestra un procedimiento para definir y llamar a P/Invoke en el que se usa este mecanismo:
[DllImport(
"nativelib",
EntryPoint = "to_lower",
CharSet = CharSet.Unicode)]
internal static extern string ToLower(string str);
// string lower = ToLower("StringToConvert");
El código auxiliar de IL controla la serialización de parámetros y valores devueltos y las llamadas a código no administrado, respetando la configuración de DllImportAttribute que afecta a cómo se debe invocar el código no administrado (por ejemplo, SetLastError). Dado que este código auxiliar de IL se genera en tiempo de ejecución, no está disponible para escenarios de compilación anticipada (AOT) o recorte de IL. La generación de IL supone un coste importante que se debe tener en cuenta para la serialización. Este coste se puede medir en términos de rendimiento de la aplicación y compatibilidad con posibles plataformas de destino que pueden no permitir la generación dinámica de código. El modelo de aplicación de la AOT nativa aborda los problemas de generación de código dinámico mediante la compilación previa de todo el código directamente en código nativo. El uso de DllImport no es una opción en plataformas que necesitan escenarios completos de AOT nativa y, por tanto, el uso de otros enfoques (por ejemplo, la generación de código fuente) resulta más adecuado. La depuración de la lógica de serialización en escenarios de DllImport tampoco es un tema menor.
El generador de origen P/Invoke, incluido con el SDK de .NET 7 y habilitado de forma predeterminada, busca LibraryImportAttribute en un método static y partial para desencadenar la generación de código fuente de marshalling en tiempo de compilación, lo que elimina la necesidad de generar un stub de IL en tiempo de ejecución y permite que la P/Invoke se inserte en línea. También se incluyen analizadores y solucionadores de código para ayudar con la migración desde el sistema integrado al generador de código fuente y con el uso en general.
Uso básico
LibraryImportAttribute está diseñado para usarse de manera similar a DllImportAttribute. Podemos convertir el ejemplo anterior para usar la generación de código fuente de P/Invoke mediante LibraryImportAttribute y marcando el método como partial en lugar de extern:
[LibraryImport(
"nativelib",
EntryPoint = "to_lower",
StringMarshalling = StringMarshalling.Utf16)]
internal static partial string ToLower(string str);
Durante la compilación, el generador de código fuente se desencadenará para generar una implementación del método ToLower que controla la serialización del parámetro string y el valor de devolución como UTF-16. Dado que ahora la serialización se genera mediante código fuente, la lógica se puede examinar y recorrer en un depurador.
MarshalAs
El generador de código fuente también respeta el atributo MarshalAsAttribute. El código anterior también se podría escribir así:
[LibraryImport(
"nativelib",
EntryPoint = "to_lower")]
[return: MarshalAs(UnmanagedType.LPWStr)]
internal static partial string ToLower(
[MarshalAs(UnmanagedType.LPWStr)] string str);
Algunas opciones de configuración de MarshalAsAttribute no se admiten. El generador de código fuente emitirá un error si intenta usar una configuración no admitida. Para obtener más información, consulte Diferencias respecto a DllImport.
Convención de llamada
Para especificar la convención de llamada, use UnmanagedCallConvAttribute, por ejemplo:
[LibraryImport(
"nativelib",
EntryPoint = "to_lower",
StringMarshalling = StringMarshalling.Utf16)]
[UnmanagedCallConv(
CallConvs = new[] { typeof(CallConvStdcall) })]
internal static partial string ToLower(string str);
Diferencias respecto a DllImport
LibraryImportAttribute está pensado para realizar una conversión sencilla desde DllImportAttribute en la mayoría de los casos, pero hay algunos cambios deliberados:
- CallingConvention no tiene ningún equivalente en LibraryImportAttribute. Se debe usar UnmanagedCallConvAttribute en su lugar.
- CharSet (para CharSet) se ha reemplazado por StringMarshalling (para StringMarshalling). ANSI se ha quitado y ahora UTF-8 está disponible como opción de primer nivel.
-
BestFitMapping y ThrowOnUnmappableChar no tienen equivalente. Estos campos solo eran relevantes al serializar una cadena ANSI en Windows. El código generado para serializar una cadena ANSI tendrá el comportamiento equivalente de
BestFitMapping=falseyThrowOnUnmappableChar=false. -
ExactSpelling no tiene equivalente. Este campo era una configuración centrada en Windows y no tenía ningún efecto en implementaciones que no son del sistema operativo de Windows. El nombre del método o EntryPoint debe reflejar la ortografía exacta del nombre del punto de entrada. Este campo tiene usos históricos relacionados con los sufijos
AyWutilizados en la programación de Win32. - PreserveSig no tiene equivalente. Este campo era una configuración centrada en Windows. El código generado siempre convierte la signatura directamente.
- El proyecto debe estar marcado como inseguro mediante AllowUnsafeBlocks.
También hay diferencias en la compatibilidad con algunas opciones de configuración en MarshalAsAttribute, en la serialización predeterminada de algunos tipos y en otros atributos relacionados con la interoperabilidad. Para obtener más información, consulte nuestra documentación sobre las diferencias de compatibilidad.