调用约定 描述方法参数和返回值在调用方和被调用方法之间传递的方式的低级别详细信息。
重要的是,P/Invoke 声明中的非托管调用约定必须与本机实现中使用的非托管调用约定相匹配。 非托管调用约定中的不匹配会导致数据损坏和严重崩溃,这些崩溃需要低级别的调试技能进行诊断。
平台默认调用约定
大多数平台使用一个规范调用约定,在大多数情况下,不需要显式指定的调用约定。
对于 x86 体系结构,默认调用约定特定于平台。 
              Stdcall (“标准调用”)是 Windows x86 上的默认调用约定,它由大多数 Win32 API 使用。 
              Cdecl 是 Linux x86 上的默认调用约定。 源自 Unix 的开放源代码库的 Windows 端口通常使用Cdecl调用约定,即使在 Windows x86 上也是如此。 必须在 P/Invoke 声明中显式指定 Cdecl 调用约定,以便与这些库互作。
对于非 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);