-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Background and Motivation
The UnmanagedCallersOnlyAttribute provides an extensible mechanism to define native calling conventions on a .NET method. This enables users to author functions that are callable in a native environment. A symmetrical need arises for functions that are defined in native code but declared to be called in a .NET environment. These native function declarations are done using DllImportAttribute.
This approach complements UnmanagedCallersOnlyAttribute and aligns with the reuse of the CallConv* types under the System.Runtime.CompilerServices namespace.
Proposed API
If the user specifies the CallingConvention.Winapi (the default) on the DllImportAttribute the following attribute will be queried.
namespace System.Runtime.InteropServices
{
+ /// <summary>
+ /// Provides an equivalent to <see cref="UnmanagedCallersOnlyAttribute"/> for native
+ /// functions declared in .NET.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Method)]
+ public class UnmanagedCalleeAttribute : Attribute
+ {
+ public UnmanagedCalleeAttribute() { }
+
+ /// <summary>
+ /// Types indicating calling conventions for the unmanaged callee.
+ /// </summary>
+ /// <remarks>
+ /// If <c>null</c>, the semantics are identical to <c>CallingConvention.Winapi</c>.
+ /// </remarks>
+ public Type[]? CallConvs;
+ }
}Usage Examples
P/Invoke
Using the defaults, all 3 of the following declarations are the same.
[DllImport("nativelib")]
static extern int Func(IntPtr a, nint val);
[DllImport("nativelib", CallingConvention = CallingConvention.Winapi)]
static extern int Func(IntPtr a, nint val);
[UnmanagedCallee]
[DllImport("nativelib")]
static extern int Func(IntPtr a, nint val);Some calling conventions can be declared in multiple ways.
[DllImport("nativelib", CallingConvention = CallingConvention.Cdecl)]
static extern int Func(IntPtr a, nint val);
[UnmanagedCallee(CallConvs = new[] { typeof(CallConvCdecl) })]
[DllImport("nativelib")]
static extern int Func(IntPtr a, nint val);
[UnmanagedCallee(CallConvs = new[] { typeof(CallConvCdecl) })]
[DllImport("nativelib", CallingConvention = CallingConvention.Winapi)]
static extern int Func(IntPtr a, nint val);Future calling conventions would be enabled without updating the CallingConvention enum. Examples in C# and VB.NET.
[UnmanagedCallee(CallConvs = new[] { typeof(CallConvVectorCall) })]
[DllImport("nativelib")]
static extern int Func(IntPtr a, nint val);<UnmanagedCallee(CallConvs := New Type() { GetType(CallConvVectorCall) })>
<DllImport("nativelib")>
Public Shared Function Func(a As IntPtr, val As IntPtr) As Integer
End FunctionThis proposal provides an alternative mechanism to support Native Varargs in #48796.
COM style interface - Not proposed but example of how the attribute could evolve.
To enable this scenario the attribute would be updated with the following: [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
Using the defaults, all 3 of the following declarations are the same on Windows.
[ComVisible(true)]
[Guid("C509A1C1-A6C9-4229-89CE-10B53CF8271B")]
interface IFoo
{
int Call(ref SomeType valuetype);
}
[ComVisible(true)]
[Guid("C509A1C1-A6C9-4229-89CE-10B53CF8271B")]
[UnmanagedCallee]
interface IFoo
{
int Call(ref SomeType valuetype);
}
[ComVisible(true)]
[Guid("C509A1C1-A6C9-4229-89CE-10B53CF8271B")]
[UnmanagedCallee(CallConvs = new[] { typeof(CallConvStdCall), typeof(CallConvMemberInstance) })]
interface IFoo
{
int Call(ref SomeType valuetype);
}Alternative Designs
Provide an enum to trigger off for reading the new attribute.
namespace System.Runtime.InteropServices
{
public enum CallingConvention
{
+ /// <summary>
+ /// Instructs the runtime to consult the <see cref="UnmanagedCalleeAttribute"/>.
+ /// </summary>
+ UnmanagedCallee = 7
}
}Alternative name proposed could be CallingConvention.UnmanagedCallConv.