Niezarządzane konwencje wywoływania
Konwencje wywoływania opisują szczegóły niskiego poziomu dotyczące sposobu przekazywania argumentów metody i zwracanych wartości między obiektem wywołującym a wywołaną metodą.
Ważne jest, aby niezarządzana konwencja wywoływania zadeklarowana w deklaracji P/Invoke była zgodna z niezarządzaną konwencją wywoływania używaną przez implementację natywną. Niezgodności w niezarządzanych konwencjach wywoływania prowadzą do uszkodzenia danych i krytycznych awarii, które wymagają umiejętności debugowania niskiego poziomu do diagnozowania.
Domyślna konwencja wywoływania platformy
Większość platform używa jednej konwencji kanonicznej wywoływania, a w większości przypadków jawnie określona konwencja wywoływania jest niepotrzebna.
W przypadku architektury x86 domyślna konwencja wywoływania jest specyficzna dla platformy. Stdcall
("wywołanie standardowe") jest domyślną konwencją wywoływania w systemie Windows x86 i jest używana przez większość interfejsów API Win32. Cdecl
to domyślna konwencja wywoływania w systemie Linux x86. Porty systemu Windows bibliotek typu open source pochodzące z systemu Unix często używają Cdecl
konwencji wywoływania nawet w systemie Windows x86. Należy jawnie określić konwencję Cdecl
wywoływania w deklaracjach P/Invoke na potrzeby współdziałania z tymi bibliotekami.
W przypadku architektur innych niż x86 konwencje Stdcall
Cdecl
wywoływania są traktowane jako domyślna konwencja wywoływania platformy kanonicznej.
Określanie konwencji wywoływania w zarządzanych deklaracjach P/Invoke
Konwencje wywoływania są określane przez typy w System.Runtime.CompilerServices
przestrzeni nazw lub ich kombinacje:
- CallConvCdecl
- CallConvFastcall
- CallConvMemberFunction
- CallConvStdcall
- CallConvSuppressGCTransition
- CallConvThiscall
Przykłady jawnie określonych konwencji wywoływania:
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();
Określanie konwencji wywoływania we wcześniejszych wersjach platformy .NET
Wersje .NET Framework i .NET wcześniejsze niż .NET 5 są ograniczone do podzestawu konwencji wywoływania, które mogą być opisane przez wyliczenie CallingConvention .
Przykłady jawnie określonych konwencji wywoływania:
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);