Convenzioni di chiamata non gestite
Le convenzioni di chiamata descrivono i dettagli di livello base sul modo in cui gli argomenti del metodo e i valori restituiti vengono passati tra il chiamante e il metodo chiamato.
È importante che la convenzione di chiamata non gestita dichiarata in una dichiarazione P/Invoke corrisponda alla convenzione di chiamata non gestita usata dall'implementazione nativa. Le mancate corrispondenze nelle convenzioni di chiamata non gestite causano danneggiamenti dei dati e arresti anomali irreversibili che richiedono competenze di debug di livello base per la diagnosi.
Convenzione di chiamata predefinita della piattaforma
La maggior parte delle piattaforme usa una convenzione di chiamata canonica e nella maggior parte dei casi non è necessaria una convenzione di chiamata specificata in modo esplicito.
Per l'architettura x86, la convenzione di chiamata predefinita è specifica della piattaforma. Stdcall
("chiamata standard") è la convenzione di chiamata predefinita in Windows x86 e viene usata dalla maggior parte delle API Win32. Cdecl
è la convenzione di chiamata predefinita in Linux x86. Le porte Windows delle librerie open source che hanno origine in Unix spesso usano la convenzione di chiamata Cdecl
anche in Windows x86. È necessario specificare in modo esplicito la convenzione di chiamata Cdecl
nelle dichiarazioni P/Invoke per l'interoperabilità con queste librerie.
Per le architetture non x86, entrambe le convenzioni di chiamata Stdcall
e Cdecl
vengono considerate come convenzione di chiamata canonica predefinita della piattaforma.
Specifica delle convenzioni di chiamata nelle dichiarazioni P/Invoke gestite
Le convenzioni di chiamata vengono specificate dai tipi nello spazio dei nomi System.Runtime.CompilerServices
o dalle relative combinazioni:
- CallConvCdecl
- CallConvFastcall
- CallConvMemberFunction
- CallConvStdcall
- CallConvSuppressGCTransition
- CallConvThiscall
Esempi di convenzioni di chiamata specificate in modo esplicito:
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();
Specifica delle convenzioni di chiamata nelle versioni precedenti di .NET
Le versioni di .NET Framework e .NET precedenti a .NET 5 sono limitate a un subset di convenzioni di chiamata che possono essere descritte dall'enumerazione CallingConvention.
Esempi di convenzioni di chiamata specificate in modo esplicito:
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);