非受控呼叫慣例
呼叫慣例描述關於方法引數和傳回值如何在呼叫端與呼叫方法之間傳遞的低層級詳細資料。
在 P/Invoke 宣告中宣告的非受控呼叫慣例,務必符合原生實作所使用的非受控呼叫慣例。 非受控呼叫慣例的不相符會導致資料毀壞和嚴重損毀,需要低層級偵錯技能來診斷。
平台預設呼叫慣例
大部分的平台都使用一個標準呼叫慣例,而且在大部分情況下,不需要明確指定的呼叫慣例。
針對 x86 結構,預設的呼叫慣例是平台特定的。 Stdcall
(「標準呼叫」) 是 Windows x86 上的預設呼叫慣例,大部分的 WIN32 API 都會使用它。 Cdecl
是 Linux x86 上的預設呼叫慣例。 源自 Unix 的開放原始碼程式庫 Windows 連接埠,即使在 Windows x86 上也使用 Cdecl
呼叫慣例。 必須在 P/Invoke 宣告中明確指定 Cdecl
呼叫慣例,以便使用這些程式庫進行 Interop。
針對非 x86 結構,Stdcall
和 Cdecl
呼叫慣例都視為標準平台預設呼叫慣例。
在受控 P/Invoke 宣告中指定呼叫慣例
呼叫慣例是由 System.Runtime.CompilerServices
命名空間中的型別或其組合所指定:
- CallConvCdecl
- CallConvFastcall
- CallConvMemberFunction
- CallConvStdcall
- CallConvSuppressGCTransition
- CallConvThiscall
明確指定呼叫慣例的範例:
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();
在舊版 .NET 中指定呼叫慣例
.NET Framework 和 .NET 5 之前的 .NET 版本僅限於可由 CallingConvention 列舉來描述的呼叫慣例子集。
明確指定呼叫慣例的範例:
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);