Nihlus/AdvancedDLSupport

Implement solution for marshalling collection-like types

Nihlus opened this issue · 0 comments

C# has multiple types and ways of expressing a linear collection of finite data (that is, a type that contains n instances of some type T). Passing this collection to native code typically requires the user to contain it in an array, pin it, and acquire a pointer to the first element of the array.

Traditional P/Invoke allows a user to pass an array directly, and performs these operations under the hood. ADL does the same.

However, in both cases, the user must supply the length of the array themselves in some other parameter to the function. This parameter is typically placed directly before or after the pointer parameter, and is a numeric type.

Describe the solution you'd like
ADL could simplify this by allowing collections to be passed on their own, without requiring an additional parameter, and instead generate this parameter automatically. This behaviour would be opt-in by way of a parameter attribute, which would also contain additional hinting information about the generation scheme. As an example,

interface ILibrary
{
    void DoSomethingWithArray
    (
        [CollectionMarshalling(typeof(UIntPtr), LengthParameterPosition.Before)]
        string[] myArray
    );
}

would be valid syntax, and generate a native signature matching

void DoSomethingWithArray(size_t collectionLength, char** myArray);

Conceivably, this could also extend to any type implementing ICollection<T> (which would firstly construct an array from the type, or use GetPinnableReference to pin it), as well as Span<T> and Memory<T>.

Describe alternatives you've considered
At present, the methods described in the preamble are the only available alternatives.

Additional context
OpenTK would benefit from this features, as it has a number of signatures following this pattern.

This issue supersedes #71, as it incorporates that feature request.