Description
Background and Motivation
The DllImportAttribute
used in P/Invoke scenarios relies on a built-in system of dynamic IL generation to support marshalling of arguments to to a native environment. A new attribute that would permit the static IL generation
is proposed. Scenario details and overall design can be found here.
Proposed API
The proposed shape for LibraryImportAttribute
is based on the existing DllImportAttribute
, but looks to remove the inconsistent or platform-specific aspects.
This attribute is intended to be emitted by the p/invoke source generator rather than added to the runtime libraries.
Related proposal: #46838
namespace System.Runtime.InteropServices
{
/// <summary>
/// Specifies how strings should be marshalled
/// </summary>
public enum StringMarshalling
{
None = 0,
Utf8, // UTF-8
Utf16, // UTF-16, machine-endian
}
/// <summary>
/// Attribute used to indicate a Source Generator should create a function for marshaling
/// arguments instead of relying on the CLR to generate an IL Stub at runtime.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class LibraryImportAttribute : Attribute
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="libraryName">Name of the library containing the import</param>
public LibraryImportAttribute(string libraryName);
/// <summary>
/// Library to load.
/// </summary>
public string LibraryName { get; }
/// <summary>
/// Indicates the name or ordinal of the entry point to be called.
/// </summary>
/// <see cref="System.Runtime.InteropServices.DllImportAttribute.EntryPoint"/>
public string? EntryPoint { get; set; }
/// <summary>
/// Indicates how to marshal string parameters to the method.
/// </summary>
/// <remarks>
/// If this field is specified, <see cref="MarshalStringsUsing" /> must not be specified.
/// </remarks>
public StringMarshalling StringMarshalling { get; set; }
/// <summary>
/// Indicates how to marshal string parameters to the method.
/// </summary>
/// <remarks>
/// If this field is specified, <see cref="StringMarshalling" /> must not be specified.
/// The type should be one that conforms to usage with the attributes:
/// <see cref="System.Runtime.InteropServices.MarshalUsingAttribute"/>
/// <see cref="System.Runtime.InteropServices.NativeMarshallingAttribute"/>
/// </remarks>
public Type? MarshalStringsUsing { get; set; }
/// <summary>
/// Indicates whether the callee sents an error (SetLastError on Windows or errorno
/// on other platforms) before returning from the attributed method.
/// </summary>
/// <see cref="System.Runtime.InteropServices.DllImportAttribute.SetLastError"/>
public bool SetLastError { get; set; }
}
}
Alternate names for the attribute:
ForeignFunctionAttribute
GeneratedDllImportAttribute
InteropImportAttribute
NativeLibraryImportAttribute
PInvokeImportAttribute
...
Usage Examples
Usage of LibraryImportAttribute
would be similar to that of DllImportAttribute
, but would also require a source generator be referenced during build. The attributed method and its containing types must also be partial
. The source generator can be found in DllImportGenerator.
[LibraryImport("NativeBinary")]
internal static partial int Sum(int a, int b);
[LibraryImport("NativeBinary", StringMarshalling = StringMarshalling.Utf16)]
internal static partial string GetValue(string name);
[LibraryImport("NativeBinary", MarshalStringsUsing = typeof(MyStringMarshal.Wtf8String))]
internal static partial string GetValue(string name);
namespace MyStringMarshal
{
struct Wtf8String { ... }
}
Analyzer/Generator diagnostics
- Fixer up for converting supported signatures from
DllImportAttribute
toLibraryImportAttribute
. - Generator will emit errors for invalid usage or missing support - prototyped diagnostics can be found here.
- Guidance for the Type to use with
MarshalStringsUsing
is covered by the diagnostics in Attributes and Analyzer Diagnostics to support custom struct marshalling in the DllImport Source Generator #46838
Risks
Attributes are typically static metadata so this will increase the amount of metadata for a compiled assembly. The DllImportAttribute
is actually a pseudo-attribute and does not have the same metadata cost as a typical .NET Attribute like the one proposed - note that the resulting generated code will vastly out-weigh the cost of this new metadata.
In terms of UX, a user would hit a build failure if one uses the attribute but doesn't reference a source code generator. There are also differences in compatibility/support between the built-in system and the proposed source generator - documented here - which users may hit. Users will get a generator diagnostic if trying to use the generator in these cases.