Convenciones de llamada no administradas

Las convenciones de llamada describe los detalles de bajo nivel sobre cómo se pasan los argumentos de método y los valores devueltos entre el llamador y el método llamado.

Es importante que la convención de llamada no administrada declarada en una declaración P/Invoke coincida con la convención de llamada no administrada usada por la implementación nativa. Los errores de coincidencia en las convenciones de llamada no administradas provocan daños en los datos y bloqueos irrecuperables que requieren aptitudes de depuración de bajo nivel para diagnosticar.

Convención de llamada predeterminada de la plataforma

La mayoría de las plataformas usan una convención de llamada canónica y una convención de llamada especificada explícitamente no es necesaria en la mayoría de los casos.

Para la arquitectura x86, la convención de llamada predeterminada es específica de la plataforma. Stdcall ("llamada estándar") es la convención de llamada predeterminada en Windows x86 y la usan la mayoría de las API de Win32. Cdecl es la convención de llamada predeterminada en Linux x86. Los puertos de Windows de las bibliotecas de código abierto que se originaron en Unix suelen usar la convención de llamada Cdecl incluso en Windows x86. Es necesario especificar explícitamente la convención de llamada Cdecl en declaraciones P/Invoke para la interoperabilidad con estas bibliotecas.

En el caso de las arquitecturas que no son x86, tanto Stdcall como Cdecl convenciones de llamada se tratan como la convención de llamada predeterminada de la plataforma canónica.

Especificación de convenciones de llamada en declaraciones P/Invoke administradas

Las convenciones de llamada se especifican mediante tipos del espacio de nombres System.Runtime.CompilerServices o sus combinaciones:

Ejemplos de convenciones de llamada especificadas explícitamente:

using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;

// P/Invoke declaration using SuppressGCTransition calling convention.
[LibraryImport("kernel32.dll")]
[UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSuppressGCTransition) })]
extern static ulong GetTickCount64();

// Unmanaged callback with Cdecl calling convention.
[UnmanagedCallersOnly(CallConvs = new Type[] { typeof(CallConvCdecl) })]
static unsafe int NativeCallback(void* context);

// Method returning function pointer with combination of Cdecl and MemberFunction calling conventions.
static unsafe delegate* unmanaged[Cdecl, MemberFunction]<int> GetHandler();

Especificación de convenciones de llamada en versiones anteriores de .NET

Las versiones de .NET Framework y .NET anteriores a .NET 5 se limitan a un subconjunto de convenciones de llamada que puede describir la enumeración CallingConvention.

Ejemplos de convenciones de llamada especificadas explícitamente:

using System.Runtime.InteropServices;

// P/Invoke declaration using Cdecl calling convention
[DllImport("ucrtbase.dll", CallingConvention=CallingConvention.Cdecl)]
static void* malloc(UIntPtr size);

// Delegate marshalled as callback with Cdecl calling convention
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void Callback(IntPtr context);

Consulte también