Bagikan melalui


Konvensi panggilan tidak terkelola

Konvensi panggilan menjelaskan detail tingkat rendah tentang bagaimana argumen metode dan nilai pengembalian diteruskan antara pemanggil dan metode yang disebut.

Penting bahwa konvensi panggilan yang tidak dikelola dideklarasikan dalam deklarasi P/Invoke cocok dengan konvensi panggilan yang tidak dikelola yang digunakan oleh implementasi asli. Ketidakcocokan dalam konvensi pemanggilan yang tidak terkelola dapat menyebabkan kerusakan data dan crash fatal yang memerlukan keterampilan debugging tingkat rendah untuk mendiagnosis.

Konvensi panggilan platform bawaan

Sebagian besar platform menggunakan satu konvensi panggilan kanonis dan konvensi panggilan yang ditentukan secara eksplisit tidak perlu dalam banyak kasus.

Untuk arsitektur x86, konvensi panggilan default adalah spesifik platform. Stdcall ("panggilan standar") adalah konvensi panggilan default pada Windows x86 dan digunakan oleh sebagian besar API Win32. Cdecl adalah konvensi panggilan default di Linux x86. Windows port pustaka sumber terbuka yang berasal dari Unix sering menggunakan konvensi panggilan Cdecl bahkan pada Windows x86. Anda harus secara eksplisit menentukan Cdecl konvensi panggilan dalam deklarasi P/Invoke untuk menggunakan pustaka ini.

Untuk arsitektur non-x86, baik konvensi panggilan Stdcall dan Cdecl diperlakukan sebagai konvensi panggilan default platform yang kanonis.

Ketika Anda dapat menghilangkan konvensi panggilan

Pada arsitektur x64, ARM, dan ARM64, hanya ada satu konvensi panggilan, jadi menentukan satu secara eksplisit tidak perlu. Anda hanya perlu menentukan konvensi panggilan saat menargetkan Windows x86 (32-bit), di mana Stdcall dan Cdecl berbeda.

  • ✔️ DO menentukan konvensi panggilan secara eksplisit saat menargetkan Windows x86.
  • ✔️ HILANGKAN konvensi panggilan pada x64, ARM, dan ARM64 — atribut tidak berpengaruh pada arsitektur ini.

Menentukan konvensi pemanggilan dalam deklarasi P/Invoke yang dikelola

Konvensi panggilan ditentukan oleh jenis di System.Runtime.CompilerServices namespace atau kombinasinya:

Contoh konvensi panggilan yang ditentukan secara eksplisit:

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();

Menentukan konvensi panggilan di versi .NET sebelumnya

.NET Framework dan versi .NET sebelum .NET 5 dibatasi pada subset konvensi panggilan yang dapat dijelaskan oleh enumerasi CallingConvention.

Contoh konvensi panggilan yang ditentukan secara eksplisit:

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);

Lihat juga