Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
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 mogą prowadzić do uszkodzenia danych i poważnych awarii, które wymagają umiejętności debugowania na niskim poziomie do skutecznej diagnozy.
Domyślna platformowa konwencja wywoływania
Większość platform korzysta z jednej kanonicznej konwencji wywoływania, dlatego w większości przypadków nie ma potrzeby jawnego określania konwencji wywoływania.
W przypadku architektury x86 domyślna konwencja wywoływania jest specyficzna dla platformy.
Stdcall ("wywołanie standardowe") jest domyślną konwencją wywoływania w Windows x86 i jest używana przez większość interfejsów API Win32.
Cdecl to domyślna konwencja wywoływania w systemie Linux x86. Windowsowe porty bibliotek open source, które wywodzą się z systemu Unix, często używają konwencji wywoływania Cdecl 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, które nie są x86, zarówno konwencje Stdcall, jak i Cdecl wywoływania są traktowane jako domyślna konwencja wywoływania platformy.
Kiedy można pominąć konwencję wywoływania
W architekturach x64, ARM i ARM64 istnieje tylko jedna konwencja wywoływania, dlatego określenie jednej jawnie jest niepotrzebne. Podczas określania konwencji wywoływania należy to zrobić tylko w przypadku systemu Windows x86 (32-bit), gdzie występują różnice między `Stdcall` a `Cdecl`.
- ✔️ Należy jawnie określić konwencję wywoływania podczas pracy z Windows x86.
- ✔️ Nie pomijaj konwencji wywoływania dla architektur x64, ARM i ARM64 — atrybut nie ma wpływu na te architektury.
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 .NET
.NET Framework i wersje .NET wcześniejsze niż .NET 5 są ograniczone do podzbioru konwencji wywoływania, które można opisać za pomocą wyliczenia 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);