1
0
Fork 0
mirror of https://github.com/VSadov/Satori.git synced 2025-06-08 11:37:04 +09:00

Update design and expose new attributes for the CustomTypeMarshaller support (#71682)

This commit is contained in:
Jeremy Koritzinsky 2022-07-06 09:35:51 -07:00 committed by GitHub
parent a6d5f6b161
commit c99b5b067c
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 415 additions and 381 deletions

View file

@ -154,9 +154,6 @@ csharp_space_between_square_brackets = false
# License header # License header
file_header_template = Licensed to the .NET Foundation under one or more agreements.\nThe .NET Foundation licenses this file to you under the MIT license. file_header_template = Licensed to the .NET Foundation under one or more agreements.\nThe .NET Foundation licenses this file to you under the MIT license.
# Marshaller type must have CustomTypeMarshallerAttribute attribute
dotnet_diagnostic.SYSLIB1056.severity = silent
# C++ Files # C++ Files
[*.{cpp,h,in}] [*.{cpp,h,in}]
curly_bracket_next_line = true curly_bracket_next_line = true

View file

@ -97,114 +97,94 @@ namespace System.Runtime.InteropServices.Marshalling;
- Ref = In | Out, - Ref = In | Out,
- } - }
+
+
+ /// <summary> + /// <summary>
+ /// Define features for a custom type marshaller. + /// An enumeration representing the different marshalling scenarios in our marshalling model.
+ /// </summary> + /// </summary>
+ [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class)] + public enum MarshalMode
+ public sealed class CustomTypeMarshallerFeaturesAttribute : Attribute
+ { + {
+ /// <summary> + /// <summary>
+ /// Desired caller buffer size for the marshaller. + /// All scenarios. A marshaller specified with this scenario will be used if there is not a specific
+ /// marshaller specified for a given usage scenario.
+ /// </summary> + /// </summary>
+ public int BufferSize { get; set; } + Default,
+ /// <summary>
+ /// By-value and <c>in</c> parameters in managed-to-unmanaged scenarios, like P/Invoke.
+ /// </summary>
+ ManagedToUnmanagedIn,
+ /// <summary>
+ /// <c>ref</c> parameters in managed-to-unmanaged scenarios, like P/Invoke.
+ /// </summary>
+ ManagedToUnmanagedRef,
+ /// <summary>
+ /// <c>out</c> parameters in managed-to-unmanaged scenarios, like P/Invoke.
+ /// </summary>
+ ManagedToUnmanagedOut,
+ /// <summary>
+ /// By-value and <c>in</c> parameters in unmanaged-to-managed scenarios, like Reverse P/Invoke.
+ /// </summary>
+ UnmanagedToManagedIn,
+ /// <summary>
+ /// <c>ref</c> parameters in unmanaged-to-managed scenarios, like Reverse P/Invoke.
+ /// </summary>
+ UnmanagedToManagedRef,
+ /// <summary>
+ /// <c>out</c> parameters in unmanaged-to-managed scenarios, like Reverse P/Invoke.
+ /// </summary>
+ UnmanagedToManagedOut,
+ /// <summary>
+ /// Elements of arrays passed with <c>in</c> or by-value in interop scenarios.
+ /// </summary>
+ ElementIn,
+ /// <summary>
+ /// Elements of arrays passed with <c>ref</c> or passed by-value with both <see cref="InAttribute"/> and <see cref="OutAttribute" /> in interop scenarios.
+ /// </summary>
+ ElementRef,
+ /// <summary>
+ /// Elements of arrays passed with <c>out</c> or passed by-value with only <see cref="OutAttribute" /> in interop scenarios.
+ /// </summary>
+ ElementOut
+ } + }
+ +
+
+ /// <summary> + /// <summary>
+ /// Base class attribute for custom marshaller attributes. + /// Attribute to indicate an entry point type for defining a marshaller.
+ /// </summary> + /// </summary>
+ /// <remarks> + [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true)]
+ /// Use a base class here to allow doing ManagedToUnmanagedMarshallersAttribute.GenericPlaceholder, etc. without having 3 + separate placeholder types. + public sealed class CustomMarshallerAttribute : Attribute
+ /// For the following attribute types, any marshaller types that are provided will be validated by an analyzer to have the + correct members to prevent
+ /// developers from accidentally typoing a member like Free() and causing memory leaks.
+ /// </remarks>
+ public abstract class CustomUnmanagedTypeMarshallersAttributeBase : Attribute
+ { + {
+ /// <summary> + /// <summary>
+ /// Create a <see cref="CustomMarshallerAttribute"/> instance.
+ /// </summary>
+ /// <param name="managedType">Managed type to marshal.</param>
+ /// <param name="marshalMode">Marshalling mode.</param>
+ /// <param name="marshallerType">Type used for marshalling.</param>
+ public CustomMarshallerAttribute(Type managedType, MarshalMode marshalMode, Type marshallerType)
+ {
+ ManagedType = managedType;
+ MarshalMode = marshalMode;
+ MarshallerType = marshallerType;
+ }
+
+ public Type ManagedType { get; }
+
+ public MarshalMode MarshalMode { get; }
+
+ public Type MarshallerType { get; }
+
+ /// <summary>
+ /// Placeholder type for generic parameter + /// Placeholder type for generic parameter
+ /// </summary> + /// </summary>
+ public sealed class GenericPlaceholder { } + public struct GenericPlaceholder
+ {
+ }
+ } + }
+ +
+ /// <summary> + /// <summary>
+ /// Specify marshallers used in the managed to unmanaged direction (that is, P/Invoke) + /// Specifies that this marshaller entry-point type is a contiguous collection marshaller.
+ /// </summary> + /// </summary>
+ [AttributeUsage(AttributeTargets.Class)] + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
+ public sealed class ManagedToUnmanagedMarshallersAttribute : CustomUnmanagedTypeMarshallersAttributeBase + public sealed class ContiguousCollectionMarshallerAttribute : Attribute
+ {
+ /// <summary>
+ /// Create instance of <see cref="ManagedToUnmanagedMarshallersAttribute"/>.
+ /// </summary>
+ /// <param name="managedType">Managed type to marshal</param>
+ public ManagedToUnmanagedMarshallersAttribute(Type managedType) { }
+
+ /// <summary>
+ /// Marshaller to use when a parameter of the managed type is passed by-value or with the <c>in</c> keyword.
+ /// </summary>
+ public Type? InMarshaller { get; set; }
+
+ /// <summary>
+ /// Marshaller to use when a parameter of the managed type is passed by-value or with the <c>ref</c> keyword.
+ /// </summary>
+ public Type? RefMarshaller { get; set; }
+
+ /// <summary>
+ /// Marshaller to use when a parameter of the managed type is passed by-value or with the <c>out</c> keyword.
+ /// </summary>
+ public Type? OutMarshaller { get; set; }
+ }
+
+ /// <summary>
+ /// Specify marshallers used in the unmanaged to managed direction (that is, Reverse P/Invoke)
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Class)]
+ public sealed class UnmanagedToManagedMarshallersAttribute : CustomUnmanagedTypeMarshallersAttributeBase
+ {
+ /// <summary>
+ /// Create instance of <see cref="UnmanagedToManagedMarshallersAttribute"/>.
+ /// </summary>
+ /// <param name="managedType">Managed type to marshal</param>
+ public UnmanagedToManagedMarshallersAttribute(Type managedType) { }
+
+ /// <summary>
+ /// Marshaller to use when a parameter of the managed type is passed by-value or with the <c>in</c> keyword.
+ /// </summary>
+ public Type? InMarshaller { get; set; }
+
+ /// <summary>
+ /// Marshaller to use when a parameter of the managed type is passed by-value or with the <c>ref</c> keyword.
+ /// </summary>
+ public Type? RefMarshaller { get; set; }
+
+ /// <summary>
+ /// Marshaller to use when a parameter of the managed type is passed by-value or with the <c>out</c> keyword.
+ /// </summary>
+ public Type? OutMarshaller { get; set; }
+ }
+
+ /// <summary>
+ /// Specify marshaller for array-element marshalling and default struct field marshalling.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Class)]
+ public sealed class ElementMarshallerAttribute : CustomUnmanagedTypeMarshallersAttributeBase
+ {
+ /// <summary>
+ /// Create instance of <see cref="ElementMarshallerAttribute"/>.
+ /// </summary>
+ /// <param name="managedType">Managed type to marshal</param>
+ /// <param name="elementMarshaller">Marshaller type to use for marshalling <paramref name="managedType"/>.</param>
+ public ElementMarshallerAttribute(Type managedType, Type elementMarshaller) { }
+ }
+
+ /// <summary>
+ /// Specifies that a particular generic parameter is the collection element's unmanaged type.
+ /// </summary>
+ /// <remarks>
+ /// If this attribute is provided on a generic parameter of a marshaller, then the generator will assume
+ /// that it is a linear collection marshaller.
+ /// </remarks>
+ [AttributeUsage(AttributeTargets.GenericParameter)]
+ public sealed class ElementUnmanagedTypeAttribute : Attribute
+ { + {
+ } + }
``` ```
@ -264,9 +244,9 @@ The element type of the `Span` for the caller-allocated buffer can be any type t
[UnmanagedToManagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(ManagedToNative))] [UnmanagedToManagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(ManagedToNative))]
static class TMarshaller<T, U, V...> static class TMarshaller<T, U, V...>
{ {
[CustomTypeMarshallerFeatures(BufferSize = 0x200)]
public static class ManagedToNative public static class ManagedToNative
{ {
public static int BufferSize { get; }
public static TNative ConvertToUnmanaged(TManaged managed, Span<byte> callerAllocatedBuffer); // Can throw exceptions public static TNative ConvertToUnmanaged(TManaged managed, Span<byte> callerAllocatedBuffer); // Can throw exceptions
public static void Free(TNative unmanaged); // Optional. Should not throw exceptions public static void Free(TNative unmanaged); // Optional. Should not throw exceptions
@ -294,7 +274,7 @@ static class TMarshaller<T, U, V...>
### Stateless Unmanaged->Managed with Guaranteed Unmarshalling ### Stateless Unmanaged->Managed with Guaranteed Unmarshalling
This shape directs the generator to emit the `ConvertToManagedGuaranteed` call in the "GuaranteedUnmarshal" phase of marshalling. This shape directs the generator to emit the `ConvertToManagedFinally` call in the "GuaranteedUnmarshal" phase of marshalling.
```csharp ```csharp
[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(NativeToManaged))] [ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(NativeToManaged))]
@ -303,7 +283,7 @@ static class TMarshaller<T, U, V...>
{ {
public static class NativeToManaged public static class NativeToManaged
{ {
public static TManaged ConvertToManagedGuaranteed(TNative unmanaged); // Should not throw exceptions public static TManaged ConvertToManagedFinally(TNative unmanaged); // Should not throw exceptions
public static void Free(TNative unmanaged); // Optional. Should not throw exceptions public static void Free(TNative unmanaged); // Optional. Should not throw exceptions
} }
@ -347,7 +327,7 @@ static class TMarshaller<T, U, V...>
public TNative ToUnmanaged(); // Can throw exceptions. public TNative ToUnmanaged(); // Can throw exceptions.
public void NotifyInvokeSucceeded(); // Optional. Should not throw exceptions. public void OnInvoked(); // Optional. Should not throw exceptions.
public void Free(); // Should not throw exceptions. public void Free(); // Should not throw exceptions.
} }
@ -363,9 +343,9 @@ The element type of the `Span` for the caller-allocated buffer can be any type t
[UnmanagedToManagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(ManagedToNative))] [UnmanagedToManagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(ManagedToNative))]
static class TMarshaller<T, U, V...> static class TMarshaller<T, U, V...>
{ {
[CustomTypeMarshallerFeatures(BufferSize = 0x200)]
public struct ManagedToNative // Can be ref struct public struct ManagedToNative // Can be ref struct
{ {
public static int BufferSize { get; }
public ManagedToNative(); // Optional, can throw exceptions. public ManagedToNative(); // Optional, can throw exceptions.
public void FromManaged(TManaged managed, Span<byte> buffer); // Can throw exceptions. public void FromManaged(TManaged managed, Span<byte> buffer); // Can throw exceptions.
@ -376,7 +356,7 @@ static class TMarshaller<T, U, V...>
public TNative ToUnmanaged(); // Can throw exceptions. public TNative ToUnmanaged(); // Can throw exceptions.
public void NotifyInvokeSucceeded(); // Optional. Should not throw exceptions. public void OnInvoked(); // Optional. Should not throw exceptions.
public void Free(); // Should not throw exceptions. public void Free(); // Should not throw exceptions.
} }
@ -418,7 +398,7 @@ static class TMarshaller<T, U, V...>
public void FromUnmanaged(TNative native); // Should not throw exceptions. public void FromUnmanaged(TNative native); // Should not throw exceptions.
public TManaged ToManagedGuaranteed(); // Should not throw exceptions. public TManaged ToManagedFinally(); // Should not throw exceptions.
public void Free(); // Should not throw exceptions. public void Free(); // Should not throw exceptions.
} }
@ -455,7 +435,7 @@ struct TCollection<T, U, V...>
} }
``` ```
A collection marshaller for a managed type will have similar generics handling as the value marshaller case; however, there is one difference. A collection marshaller must have an additional generic parameter with the `ElementUnmanagedTypeAttribute`. This parameter can optionally be constrained to `: unmanaged` (but the system will not require this). The attributed parameter will be filled in with a generics-compatible representation of the unmanaged type for the collection's element type (`nint` will be used when the native type is a pointer type). A collection marshaller must have the `ContiguousCollectionMarshallerAttribute` applied to the entry-point type. A collection marshaller for a managed type will have similar generics handling as the value marshaller case; however, there is one difference. A collection marshaller must have an additional generic parameter at the end of the generic parameter list. This parameter can optionally be constrained to `: unmanaged` (but the system will not require this). The additional parameter will be filled in with a generics-compatible representation of the unmanaged type for the collection's element type (`nint` will be used when the native type is a pointer type).
The type `TNative` can be any `unmanaged` type. It represents whatever unmanaged type the marshaller marshals the managed type to. The type `TNative` can be any `unmanaged` type. It represents whatever unmanaged type the marshaller marshals the managed type to.
@ -463,9 +443,11 @@ The type `TNative` can be any `unmanaged` type. It represents whatever unmanaged
### Stateless Managed->Unmanaged ### Stateless Managed->Unmanaged
```csharp ```csharp
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(ManagedToNative))] [CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))]
[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(ManagedToNative))] [CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.UnmanagedToManagedOut, typeof(ManagedToNative))]
static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged [CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ElementIn, typeof(ManagedToNative))]
[ContiguousCollectionMarshaller]
static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement : unmanaged
{ {
public static class ManagedToNative public static class ManagedToNative
{ {
@ -487,13 +469,14 @@ static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> w
The element type of the `Span` for the caller-allocated buffer can be any type that guarantees any alignment requirements, including `TUnmanagedElement`. The element type of the `Span` for the caller-allocated buffer can be any type that guarantees any alignment requirements, including `TUnmanagedElement`.
```csharp ```csharp
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(ManagedToNative))] [CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))]
[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(ManagedToNative))] [CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ElementIn, typeof(ManagedToNative))]
static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged [ContiguousCollectionMarshaller]
static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement : unmanaged
{ {
[CustomTypeMarshallerFeatures(BufferSize = 0x200)]
public static class ManagedToNative public static class ManagedToNative
{ {
public static int BufferSize { get; }
public static TNative AllocateContainerForUnmanagedElements(TCollection managed, Span<TOther> buffer, out int numElements); // Can throw exceptions public static TNative AllocateContainerForUnmanagedElements(TCollection managed, Span<TOther> buffer, out int numElements); // Can throw exceptions
public static ReadOnlySpan<TManagedElement> GetManagedValuesSource(TCollection managed); // Can throw exceptions public static ReadOnlySpan<TManagedElement> GetManagedValuesSource(TCollection managed); // Can throw exceptions
@ -511,9 +494,11 @@ static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> w
### Stateless Unmanaged->Managed ### Stateless Unmanaged->Managed
```csharp ```csharp
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(NativeToManaged))] [CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))]
[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(NativeToManaged))] [CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.UnmanagedToManagedIn, typeof(NativeToManaged))]
static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged [CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ElementOut, typeof(NativeToManaged))]
[ContiguousCollectionMarshaller]
static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement : unmanaged
{ {
public static class NativeToManaged public static class NativeToManaged
{ {
@ -531,16 +516,16 @@ static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> w
### Stateless Unmanaged->Managed with Guaranteed Unmarshalling ### Stateless Unmanaged->Managed with Guaranteed Unmarshalling
This shape directs the generator to emit the `ConvertToManagedGuaranteed` call in the "GuaranteedUnmarshal" phase of marshalling. This shape directs the generator to emit the `ConvertToManagedFinally` call in the "GuaranteedUnmarshal" phase of marshalling.
```csharp ```csharp
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(NativeToManaged))] [CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))]
[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(NativeToManaged))] [ContiguousCollectionMarshaller]
static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement : unmanaged
{ {
public static class NativeToManaged public static class NativeToManaged
{ {
public static TCollection AllocateContainerForManagedElementsGuaranteed(TNative unmanaged, int length); // Should not throw exceptions other than OutOfMemoryException. public static TCollection AllocateContainerForManagedElementsFinally(TNative unmanaged, int length); // Should not throw exceptions other than OutOfMemoryException.
public static Span<TManagedElement> GetManagedValuesDestination(T[] managed) => managed; // Can throw exceptions public static Span<TManagedElement> GetManagedValuesDestination(T[] managed) => managed; // Can throw exceptions
@ -554,10 +539,11 @@ static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> w
### Stateless Bidirectional ### Stateless Bidirectional
```csharp ```csharp
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), RefMarshaller = typeof(Bidirectional))] [CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedRef, typeof(Bidirectional))]
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), RefMarshaller = typeof(Bidirectional))] [CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.UnmanagedToManagedRef, typeof(Bidirectional))]
[ElementMarshaller(typeof(TManaged<,,,...>), typeof(Bidirectional))] [CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ElementRef, typeof(Bidirectional))]
static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged [ContiguousCollectionMarshaller]
static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement : unmanaged
{ {
public static class Bidirectional public static class Bidirectional
{ {
@ -572,9 +558,10 @@ static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> w
### Stateful Managed->Unmanaged ### Stateful Managed->Unmanaged
```csharp ```csharp
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(ManagedToNative))] [CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))]
[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(ManagedToNative))] [CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.UnmanagedToManagedOut, typeof(ManagedToNative))]
static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged [ContiguousCollectionMarshaller]
static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement : unmanaged
{ {
public struct ManagedToNative // Can be ref struct public struct ManagedToNative // Can be ref struct
{ {
@ -592,7 +579,7 @@ static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> w
public static ref TOther GetPinnableReference(TCollection collection); // Optional. Can throw exceptions. Result pinnned and passed to Invoke. public static ref TOther GetPinnableReference(TCollection collection); // Optional. Can throw exceptions. Result pinnned and passed to Invoke.
public void NotifyInvokeSucceeded(); // Optional. Should not throw exceptions. public void OnInvoked(); // Optional. Should not throw exceptions.
} }
} }
@ -602,13 +589,14 @@ static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> w
The element type of the `Span` for the caller-allocated buffer can be any type that guarantees any alignment requirements. The element type of the `Span` for the caller-allocated buffer can be any type that guarantees any alignment requirements.
```csharp ```csharp
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(ManagedToNative))] [CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))]
[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(ManagedToNative))] [ContiguousCollectionMarshaller]
static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement : unmanaged
{ {
[CustomTypeMarshallerFeatures(BufferSize = 0x200)]
public struct ManagedToNative // Can be ref struct public struct ManagedToNative // Can be ref struct
{ {
public static int BufferSize { get; }
public ManagedToNative(); // Optional, can throw exceptions. public ManagedToNative(); // Optional, can throw exceptions.
public void FromManaged(TCollection collection, Span<TBuffer> buffer); // Can throw exceptions. public void FromManaged(TCollection collection, Span<TBuffer> buffer); // Can throw exceptions.
@ -623,7 +611,7 @@ static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> w
public static ref TOther GetPinnableReference(TCollection collection); // Optional. Can throw exceptions. Result pinnned and passed to Invoke. public static ref TOther GetPinnableReference(TCollection collection); // Optional. Can throw exceptions. Result pinnned and passed to Invoke.
public void NotifyInvokeSucceeded(); // Optional. Should not throw exceptions. public void OnInvoked(); // Optional. Should not throw exceptions.
} }
} }
@ -632,9 +620,10 @@ static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> w
### Stateful Unmanaged->Managed ### Stateful Unmanaged->Managed
```csharp ```csharp
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(NativeToManaged))] [CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))]
[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(NativeToManaged))] [CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.UnmanagedToManagedIn, typeof(NativeToManaged))]
static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged [ContiguousCollectionMarshaller]
static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement : unmanaged
{ {
public struct NativeToManaged // Can be ref struct public struct NativeToManaged // Can be ref struct
{ {
@ -657,9 +646,9 @@ static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> w
### Stateful Unmanaged->Managed with Guaranteed Unmarshalling ### Stateful Unmanaged->Managed with Guaranteed Unmarshalling
```csharp ```csharp
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(NativeToManaged))] [CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))]
[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(NativeToManaged))] [ContiguousCollectionMarshaller]
static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement : unmanaged
{ {
public struct NativeToManaged // Can be ref struct public struct NativeToManaged // Can be ref struct
{ {
@ -671,7 +660,7 @@ static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> w
public Span<TManagedElement> GetManagedValuesDestination(int length); // Can throw exceptions. public Span<TManagedElement> GetManagedValuesDestination(int length); // Can throw exceptions.
public TCollection ToManagedGuaranteed(); // Can throw exceptions public TCollection ToManagedFinally(); // Can throw exceptions
public void Free(); // Optional. Should not throw exceptions. public void Free(); // Optional. Should not throw exceptions.
} }
@ -681,9 +670,10 @@ static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> w
### Stateful Bidirectional ### Stateful Bidirectional
```csharp ```csharp
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), RefMarshaller = typeof(Bidirectional))] [CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedRef, typeof(Bidirectional))]
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), RefMarshaller = typeof(Bidirectional))] [CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.UnmanagedToManagedRef, typeof(Bidirectional))]
static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged [ContiguousCollectionMarshaller]
static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement : unmanaged
{ {
public struct Bidirectional // Can be ref struct public struct Bidirectional // Can be ref struct
{ {
@ -702,7 +692,7 @@ There's a few optional members in the above shapes. This section explains what t
The `Free` method on each shape supports releasing any unmanaged (or managed in the stateful shapes) resources. This method is optional as the `Free` method is required to be called in a `finally` clause and emitting a `try-finally` block with only method calls to empty methods puts a lot of stress on the JIT to inline all of the methods and realize that they are no-ops to remove the `finally` clause. Additionally, just having the `try-finally` block wrapping the main code can cause some de-optimizations. The `Free` method on each shape supports releasing any unmanaged (or managed in the stateful shapes) resources. This method is optional as the `Free` method is required to be called in a `finally` clause and emitting a `try-finally` block with only method calls to empty methods puts a lot of stress on the JIT to inline all of the methods and realize that they are no-ops to remove the `finally` clause. Additionally, just having the `try-finally` block wrapping the main code can cause some de-optimizations.
### NotifyInvokeSucceeded method ### OnInvoked method
This method is called after a stub successfully invokes the target code (unmanaged code in a P/Invoke scenario, managed code in a Reverse P/Invoke scenario). As this method would be called in a very large majority of cases in P/Invoke-style scenarios and has only limited utility (its main use is to provide a good place to call `GC.KeepAlive` that does not require a `try-finally` block), we decided to make it optional. This method is called after a stub successfully invokes the target code (unmanaged code in a P/Invoke scenario, managed code in a Reverse P/Invoke scenario). As this method would be called in a very large majority of cases in P/Invoke-style scenarios and has only limited utility (its main use is to provide a good place to call `GC.KeepAlive` that does not require a `try-finally` block), we decided to make it optional.
@ -731,7 +721,7 @@ The marshaller type must be an entry-point marshaller type as defined above and
- The type must either be: - The type must either be:
- Non-generic - Non-generic
- A closed generic - A closed generic
- An open generic with as many generic parameters with compatible constraints as the managed type (excluding up to one generic parameter with the `ElementUnmanagedTypeAttribute`) - An open generic with as many generic parameters with compatible constraints as the managed type (excluding one generic parameter if the marshaller has the `ContiguousCollectionMarshallerAttribute` attribute)
- If used in `NativeMarshallingAttribute`, the type should be at least as visible as the managed type. - If used in `NativeMarshallingAttribute`, the type should be at least as visible as the managed type.
Passing size info for parameters will be based to the [V1 design](SpanMarshallers.md#providing-additional-data-for-collection-marshalling) and the properties/fields on `MarshalUsingAttribute` will remain unchanged. Passing size info for parameters will be based to the [V1 design](SpanMarshallers.md#providing-additional-data-for-collection-marshalling) and the properties/fields on `MarshalUsingAttribute` will remain unchanged.

View file

@ -69,8 +69,6 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition="'$(NetCoreAppCurrentTargetFrameworkMoniker)' == '$(TargetFrameworkMoniker)' and '$(IncludeLibraryImportGeneratorSources)' != 'false'"> <ItemGroup Condition="'$(NetCoreAppCurrentTargetFrameworkMoniker)' == '$(TargetFrameworkMoniker)' and '$(IncludeLibraryImportGeneratorSources)' != 'false'">
<Compile Include="$(LibrariesProjectRoot)System.Runtime.InteropServices/tests/Ancillary.Interop/CustomMarshallerAttribute.cs" />
<Compile Include="$(LibrariesProjectRoot)System.Runtime.InteropServices/tests/Ancillary.Interop/Scenario.cs" />
</ItemGroup> </ItemGroup>
</Target> </Target>

View file

@ -49,7 +49,7 @@ namespace System.DirectoryServices.Protocols
public int packageListLength; public int packageListLength;
#if NET7_0_OR_GREATER #if NET7_0_OR_GREATER
[CustomMarshaller(typeof(SEC_WINNT_AUTH_IDENTITY_EX), Scenario.ManagedToUnmanagedIn, typeof(Marshaller))] [CustomMarshaller(typeof(SEC_WINNT_AUTH_IDENTITY_EX), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller))]
internal static class Marshaller internal static class Marshaller
{ {
public static Native ConvertToUnmanaged(SEC_WINNT_AUTH_IDENTITY_EX managed) public static Native ConvertToUnmanaged(SEC_WINNT_AUTH_IDENTITY_EX managed)

View file

@ -40,7 +40,7 @@ internal static partial class Interop
internal uint nStartPage; internal uint nStartPage;
#if NET7_0_OR_GREATER #if NET7_0_OR_GREATER
[CustomMarshaller(typeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW), Scenario.Default, typeof(Marshaller))] [CustomMarshaller(typeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW), MarshalMode.Default, typeof(Marshaller))]
public static class Marshaller public static class Marshaller
{ {
public static Native ConvertToUnmanaged(CRYPTUI_VIEWCERTIFICATE_STRUCTW managed) => new(managed); public static Native ConvertToUnmanaged(CRYPTUI_VIEWCERTIFICATE_STRUCTW managed) => new(managed);
@ -152,7 +152,7 @@ internal static partial class Interop
internal IntPtr hSelectedCertStore; internal IntPtr hSelectedCertStore;
#if NET7_0_OR_GREATER #if NET7_0_OR_GREATER
[CustomMarshaller(typeof(CRYPTUI_SELECTCERTIFICATE_STRUCTW), Scenario.Default, typeof(Marshaller))] [CustomMarshaller(typeof(CRYPTUI_SELECTCERTIFICATE_STRUCTW), MarshalMode.Default, typeof(Marshaller))]
public static class Marshaller public static class Marshaller
{ {
public static Native ConvertToUnmanaged(CRYPTUI_SELECTCERTIFICATE_STRUCTW managed) => new(managed); public static Native ConvertToUnmanaged(CRYPTUI_SELECTCERTIFICATE_STRUCTW managed) => new(managed);

View file

@ -56,7 +56,7 @@ internal static partial class Interop
uint modifiers); uint modifiers);
#if NET7_0_OR_GREATER #if NET7_0_OR_GREATER
[CustomMarshaller(typeof(StringBuilder), Scenario.ManagedToUnmanagedIn, typeof(SimpleStringBufferMarshaller))] [CustomMarshaller(typeof(StringBuilder), MarshalMode.ManagedToUnmanagedIn, typeof(SimpleStringBufferMarshaller))]
private static unsafe class SimpleStringBufferMarshaller private static unsafe class SimpleStringBufferMarshaller
{ {
public static void* ConvertToUnmanaged(StringBuilder builder) public static void* ConvertToUnmanaged(StringBuilder builder)

View file

@ -262,7 +262,7 @@ internal static partial class Interop
[MarshalAs(UnmanagedType.Bool)] [MarshalAs(UnmanagedType.Bool)]
public bool AutoLoginIfChallenged; public bool AutoLoginIfChallenged;
#if NET7_0_OR_GREATER #if NET7_0_OR_GREATER
[CustomMarshaller(typeof(WINHTTP_AUTOPROXY_OPTIONS), Scenario.Default, typeof(Marshaller))] [CustomMarshaller(typeof(WINHTTP_AUTOPROXY_OPTIONS), MarshalMode.Default, typeof(Marshaller))]
public static class Marshaller public static class Marshaller
{ {
public static Native ConvertToUnmanaged(WINHTTP_AUTOPROXY_OPTIONS managed) => new(managed); public static Native ConvertToUnmanaged(WINHTTP_AUTOPROXY_OPTIONS managed) => new(managed);

View file

@ -28,7 +28,7 @@ internal static partial class Interop
private ushort wReserved1; private ushort wReserved1;
private ushort dwSupport; private ushort dwSupport;
#if NET7_0_OR_GREATER #if NET7_0_OR_GREATER
[CustomMarshaller(typeof(WAVEOUTCAPS), Scenario.Default, typeof(Marshaller))] [CustomMarshaller(typeof(WAVEOUTCAPS), MarshalMode.Default, typeof(Marshaller))]
public static class Marshaller public static class Marshaller
{ {
public static Native ConvertToUnmanaged(WAVEOUTCAPS managed) => new(managed); public static Native ConvertToUnmanaged(WAVEOUTCAPS managed) => new(managed);

View file

@ -75,7 +75,7 @@ internal static partial class Interop
internal byte[] MulticastAddress; // IP address of group. internal byte[] MulticastAddress; // IP address of group.
internal int InterfaceIndex; // Local interface index. internal int InterfaceIndex; // Local interface index.
[CustomMarshaller(typeof(IPv6MulticastRequest), Scenario.Default, typeof(Marshaller))] [CustomMarshaller(typeof(IPv6MulticastRequest), MarshalMode.Default, typeof(Marshaller))]
public static class Marshaller public static class Marshaller
{ {
public static Native ConvertToUnmanaged(IPv6MulticastRequest managed) => new(managed); public static Native ConvertToUnmanaged(IPv6MulticastRequest managed) => new(managed);

View file

@ -703,7 +703,7 @@ namespace Microsoft.Win32
public uint Type; public uint Type;
#if NET7_0_OR_GREATER #if NET7_0_OR_GREATER
[CustomMarshaller(typeof(EvtStringVariant), Scenario.Default, typeof(Marshaller))] [CustomMarshaller(typeof(EvtStringVariant), MarshalMode.Default, typeof(Marshaller))]
public static class Marshaller public static class Marshaller
{ {
public static Native ConvertToUnmanaged(EvtStringVariant managed) => new(managed); public static Native ConvertToUnmanaged(EvtStringVariant managed) => new(managed);

View file

@ -188,7 +188,7 @@ internal static partial class Interop
internal int fwType; internal int fwType;
#if NET7_0_OR_GREATER #if NET7_0_OR_GREATER
[CustomMarshaller(typeof(DOCINFO), Scenario.ManagedToUnmanagedIn, typeof(Marshaller))] [CustomMarshaller(typeof(DOCINFO), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller))]
public static class Marshaller public static class Marshaller
{ {
public static Native ConvertToUnmanaged(DOCINFO managed) => new(managed); public static Native ConvertToUnmanaged(DOCINFO managed) => new(managed);

View file

@ -872,10 +872,12 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\AnsiStringMarshaller.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\AnsiStringMarshaller.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\ArrayMarshaller.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\ArrayMarshaller.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\BStrStringMarshaller.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\BStrStringMarshaller.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\CustomMarshallerAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\CustomTypeMarshallerAttribute.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\CustomTypeMarshallerAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\CustomTypeMarshallerDirection.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\CustomTypeMarshallerDirection.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\CustomTypeMarshallerFeatures.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\CustomTypeMarshallerFeatures.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\CustomTypeMarshallerKind.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\CustomTypeMarshallerKind.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\MarshalMode.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\MarshalUsingAttribute.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\MarshalUsingAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\NativeMarshallingAttribute.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\NativeMarshallingAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\PointerArrayMarshaller.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshalling\PointerArrayMarshaller.cs" />

View file

@ -0,0 +1,48 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable enable
namespace System.Runtime.InteropServices.Marshalling
{
/// <summary>
/// Attribute to indicate an entry point type for defining a marshaller.
/// </summary>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true)]
public sealed class CustomMarshallerAttribute : Attribute
{
/// <summary>
/// Create a <see cref="CustomMarshallerAttribute"/> instance.
/// </summary>
/// <param name="managedType">Managed type to marshal.</param>
/// <param name="marshalMode">The marshalling mode this attribute applies to.</param>
/// <param name="marshallerType">Type used for marshalling.</param>
public CustomMarshallerAttribute(Type managedType, MarshalMode marshalMode, Type marshallerType)
{
ManagedType = managedType;
MarshalMode = marshalMode;
MarshallerType = marshallerType;
}
/// <summary>
/// The managed type to marshal.
/// </summary>
public Type ManagedType { get; }
/// <summary>
/// The marshalling mode this attribute applies to.
/// </summary>
public MarshalMode MarshalMode { get; }
/// <summary>
/// Type used for marshalling.
/// </summary>
public Type MarshallerType { get; }
/// <summary>
/// Placeholder type for generic parameter
/// </summary>
public struct GenericPlaceholder
{
}
}
}

View file

@ -4,22 +4,17 @@
#if MICROSOFT_INTEROP_SOURCEGENERATION #if MICROSOFT_INTEROP_SOURCEGENERATION
namespace Microsoft.Interop namespace Microsoft.Interop
#else #else
namespace System.Runtime.InteropServices namespace System.Runtime.InteropServices.Marshalling
#endif #endif
{ {
/// <summary> /// <summary>
/// An enumeration representing the different marshalling scenarios in our marshalling model. /// An enumeration representing the different marshalling modes in our marshalling model.
/// </summary> /// </summary>
#if LIBRARYIMPORT_GENERATOR_TEST || MICROSOFT_INTEROP_SOURCEGENERATION public enum MarshalMode
public
#else
internal
#endif
enum Scenario
{ {
/// <summary> /// <summary>
/// All scenarios. A marshaller specified with this scenario will be used if there is not a specific /// All modes. A marshaller specified with this mode will be used if there is not a specific
/// marshaller specified for a given usage scenario. /// marshaller specified for a given usage mode.
/// </summary> /// </summary>
Default, Default,
/// <summary> /// <summary>

View file

@ -500,6 +500,13 @@ namespace Microsoft.Interop.Analyzers
if (!hasCustomTypeMarshallerAttribute) if (!hasCustomTypeMarshallerAttribute)
{ {
if (ManualTypeMarshallingHelper.HasEntryPointMarshallerAttribute(entryType))
{
// TEMPORARY: Don't analyze V2 analyzers in this method for now.
// We'll add support soon, but for now just don't emit warnings to use the V1 marshaller design
// when using the V2 design.
return;
}
context.ReportDiagnostic( context.ReportDiagnostic(
attributeData.CreateDiagnostic( attributeData.CreateDiagnostic(
NativeTypeMustHaveCustomTypeMarshallerAttributeRule, NativeTypeMustHaveCustomTypeMarshallerAttributeRule,

View file

@ -358,13 +358,13 @@ namespace Microsoft.Interop
// Since the char type in an array will not be part of the P/Invoke signature, we can // Since the char type in an array will not be part of the P/Invoke signature, we can
// use the regular blittable marshaller in all cases. // use the regular blittable marshaller in all cases.
new CharMarshallingGeneratorFactory(generatorFactory, useBlittableMarshallerForUtf16: true), new CharMarshallingGeneratorFactory(generatorFactory, useBlittableMarshallerForUtf16: true),
new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, Scenario.ElementIn, Scenario.ElementRef, Scenario.ElementOut)); new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, MarshalMode.ElementIn, MarshalMode.ElementRef, MarshalMode.ElementOut));
// We don't need to include the later generator factories for collection elements // We don't need to include the later generator factories for collection elements
// as the later generator factories only apply to parameters. // as the later generator factories only apply to parameters.
generatorFactory = new AttributedMarshallingModelGeneratorFactory( generatorFactory = new AttributedMarshallingModelGeneratorFactory(
generatorFactory, generatorFactory,
elementFactory, elementFactory,
new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, Scenario.ManagedToUnmanagedIn, Scenario.ManagedToUnmanagedRef, Scenario.ManagedToUnmanagedOut)); new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, MarshalMode.ManagedToUnmanagedIn, MarshalMode.ManagedToUnmanagedRef, MarshalMode.ManagedToUnmanagedOut));
generatorFactory = new ByValueContentsMarshalKindValidator(generatorFactory); generatorFactory = new ByValueContentsMarshalKindValidator(generatorFactory);
} }

View file

@ -24,32 +24,32 @@ namespace Microsoft.Interop
MarshallingInfo? CollectionElementMarshallingInfo); MarshallingInfo? CollectionElementMarshallingInfo);
public readonly record struct CustomTypeMarshallers( public readonly record struct CustomTypeMarshallers(
ImmutableDictionary<Scenario, CustomTypeMarshallerData> Scenarios) ImmutableDictionary<MarshalMode, CustomTypeMarshallerData> Modes)
{ {
public CustomTypeMarshallerData GetScenarioOrDefault(Scenario scenario) public CustomTypeMarshallerData GetModeOrDefault(MarshalMode mode)
{ {
CustomTypeMarshallerData data; CustomTypeMarshallerData data;
if (Scenarios.TryGetValue(scenario, out data)) if (Modes.TryGetValue(mode, out data))
return data; return data;
if (Scenarios.TryGetValue(Scenario.Default, out data)) if (Modes.TryGetValue(MarshalMode.Default, out data))
return data; return data;
// TODO: Hard failure based on previous implementation // TODO: Hard failure based on previous implementation
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
public bool TryGetScenarioOrDefault(Scenario scenario, out CustomTypeMarshallerData data) public bool TryGetModeOrDefault(MarshalMode mode, out CustomTypeMarshallerData data)
{ {
if (Scenarios.TryGetValue(scenario, out data)) if (Modes.TryGetValue(mode, out data))
return true; return true;
return Scenarios.TryGetValue(Scenario.Default, out data); return Modes.TryGetValue(MarshalMode.Default, out data);
} }
public bool IsDefinedOrDefault(Scenario scenario) public bool IsDefinedOrDefault(MarshalMode mode)
{ {
return Scenarios.ContainsKey(scenario) || Scenarios.ContainsKey(Scenario.Default); return Modes.ContainsKey(mode) || Modes.ContainsKey(MarshalMode.Default);
} }
} }
@ -73,7 +73,7 @@ namespace Microsoft.Interop
public static bool IsLinearCollectionEntryPoint(INamedTypeSymbol entryPointType) public static bool IsLinearCollectionEntryPoint(INamedTypeSymbol entryPointType)
{ {
return entryPointType.IsGenericType return entryPointType.IsGenericType
&& entryPointType.TypeParameters.Last().GetAttributes().Any(attr => attr.AttributeClass.ToDisplayString() == TypeNames.ElementUnmanagedTypeAttribute); && entryPointType.GetAttributes().Any(attr => attr.AttributeClass.ToDisplayString() == TypeNames.ContiguousCollectionMarshallerAttribute);
} }
public static bool HasEntryPointMarshallerAttribute(ITypeSymbol entryPointType) public static bool HasEntryPointMarshallerAttribute(ITypeSymbol entryPointType)
@ -116,7 +116,7 @@ namespace Microsoft.Interop
// We expect a callback for getting the element marshalling info when handling linear collection marshalling // We expect a callback for getting the element marshalling info when handling linear collection marshalling
Debug.Assert(!isLinearCollectionMarshalling || getMarshallingInfoForElement is not null); Debug.Assert(!isLinearCollectionMarshalling || getMarshallingInfoForElement is not null);
Dictionary<Scenario, CustomTypeMarshallerData> scenarios = new(); Dictionary<MarshalMode, CustomTypeMarshallerData> modes = new();
foreach (AttributeData attr in attrs) foreach (AttributeData attr in attrs)
{ {
Debug.Assert(attr.ConstructorArguments.Length == 3); Debug.Assert(attr.ConstructorArguments.Length == 3);
@ -136,7 +136,7 @@ namespace Microsoft.Interop
&& !compilation.HasImplicitConversion(managedType, managedTypeInst)) && !compilation.HasImplicitConversion(managedType, managedTypeInst))
return false; return false;
var marshallerScenario = (Scenario)attr.ConstructorArguments[1].Value!; var marshalMode = (MarshalMode)attr.ConstructorArguments[1].Value!;
ITypeSymbol? marshallerTypeOnAttr = attr.ConstructorArguments[2].Value as ITypeSymbol; ITypeSymbol? marshallerTypeOnAttr = attr.ConstructorArguments[2].Value as ITypeSymbol;
if (marshallerTypeOnAttr is null) if (marshallerTypeOnAttr is null)
@ -168,51 +168,51 @@ namespace Microsoft.Interop
} }
// TODO: We can probably get rid of MarshallingDirection and just use Scenario instead // TODO: We can probably get rid of MarshallingDirection and just use Scenario instead
MarshallingDirection direction = marshallerScenario switch MarshallingDirection direction = marshalMode switch
{ {
Scenario.Default MarshalMode.Default
=> MarshallingDirection.Bidirectional, => MarshallingDirection.Bidirectional,
Scenario.ManagedToUnmanagedIn MarshalMode.ManagedToUnmanagedIn
or Scenario.UnmanagedToManagedOut or MarshalMode.UnmanagedToManagedOut
=> MarshallingDirection.ManagedToUnmanaged, => MarshallingDirection.ManagedToUnmanaged,
Scenario.ManagedToUnmanagedOut MarshalMode.ManagedToUnmanagedOut
or Scenario.UnmanagedToManagedIn or MarshalMode.UnmanagedToManagedIn
=> MarshallingDirection.UnmanagedToManaged, => MarshallingDirection.UnmanagedToManaged,
Scenario.ManagedToUnmanagedRef MarshalMode.ManagedToUnmanagedRef
or Scenario.UnmanagedToManagedRef or MarshalMode.UnmanagedToManagedRef
=> MarshallingDirection.Bidirectional, => MarshallingDirection.Bidirectional,
Scenario.ElementIn MarshalMode.ElementIn
or Scenario.ElementRef or MarshalMode.ElementRef
or Scenario.ElementOut or MarshalMode.ElementOut
=> MarshallingDirection.Bidirectional, => MarshallingDirection.Bidirectional,
_ => throw new UnreachableException() _ => throw new UnreachableException()
}; };
// TODO: Report invalid shape for scenario // TODO: Report invalid shape for mode
// Skip checking for bidirectional support for Default scenario - always take / store marshaller data // Skip checking for bidirectional support for Default mode - always take / store marshaller data
CustomTypeMarshallerData? data = GetMarshallerDataForType(marshallerType, direction, managedType, isLinearCollectionMarshalling, compilation, getMarshallingInfoForElement); CustomTypeMarshallerData? data = GetMarshallerDataForType(marshallerType, direction, managedType, isLinearCollectionMarshalling, compilation, getMarshallingInfoForElement);
// TODO: Should we fire a diagnostic for duplicated scenarios or just take the last one? // TODO: Should we fire a diagnostic for duplicated modes or just take the last one?
if (data is null if (data is null
|| scenarios.ContainsKey(marshallerScenario)) || modes.ContainsKey(marshalMode))
{ {
continue; continue;
} }
scenarios.Add(marshallerScenario, data.Value); modes.Add(marshalMode, data.Value);
} }
if (scenarios.Count == 0) if (modes.Count == 0)
return false; return false;
marshallers = new CustomTypeMarshallers() marshallers = new CustomTypeMarshallers()
{ {
Scenarios = scenarios.ToImmutableDictionary() Modes = modes.ToImmutableDictionary()
}; };
return true; return true;
@ -392,10 +392,10 @@ namespace Microsoft.Interop
} }
else else
{ {
// Native type is the first parameter of ConvertToManaged or ConvertToManagedGuaranteed // Native type is the first parameter of ConvertToManaged or ConvertToManagedFinally
if (methods.ToManagedGuaranteed is not null) if (methods.ToManagedFinally is not null)
{ {
nativeType = methods.ToManagedGuaranteed.Parameters[0].Type; nativeType = methods.ToManagedFinally.Parameters[0].Type;
} }
else if (methods.ToManaged is not null) else if (methods.ToManaged is not null)
{ {

View file

@ -22,7 +22,7 @@ namespace Microsoft.Interop
ToManaged = 0x10, ToManaged = 0x10,
GuaranteedUnmarshal = 0x20, GuaranteedUnmarshal = 0x20,
Free = 0x40, Free = 0x40,
NotifyInvokeSucceeded = 0x80, OnInvoked = 0x80,
} }
public static class ShapeMemberNames public static class ShapeMemberNames
@ -36,7 +36,7 @@ namespace Microsoft.Interop
public static class Stateless public static class Stateless
{ {
public const string ConvertToManaged = nameof(ConvertToManaged); public const string ConvertToManaged = nameof(ConvertToManaged);
public const string ConvertToManagedGuaranteed = nameof(ConvertToManagedGuaranteed); public const string ConvertToManagedFinally = nameof(ConvertToManagedFinally);
public const string ConvertToUnmanaged = nameof(ConvertToUnmanaged); public const string ConvertToUnmanaged = nameof(ConvertToUnmanaged);
} }
@ -47,11 +47,11 @@ namespace Microsoft.Interop
public const string ToUnmanaged = nameof(ToUnmanaged); public const string ToUnmanaged = nameof(ToUnmanaged);
// Unmanaged to managed // Unmanaged to managed
public const string ToManaged = nameof(ToManaged); public const string ToManaged = nameof(ToManaged);
public const string ToManagedGuaranteed = nameof(ToManagedGuaranteed); public const string ToManagedFinally = nameof(ToManagedFinally);
public const string FromUnmanaged = nameof(FromUnmanaged); public const string FromUnmanaged = nameof(FromUnmanaged);
// Optional features // Optional features
public const string Free = nameof(Free); public const string Free = nameof(Free);
public const string NotifyInvokeSucceeded = nameof(NotifyInvokeSucceeded); public const string OnInvoked = nameof(OnInvoked);
} }
} }
@ -66,7 +66,7 @@ namespace Microsoft.Interop
// Unmanaged to managed // Unmanaged to managed
public const string AllocateContainerForManagedElements = nameof(AllocateContainerForManagedElements); public const string AllocateContainerForManagedElements = nameof(AllocateContainerForManagedElements);
public const string AllocateContainerForManagedElementsGuaranteed = nameof(AllocateContainerForManagedElementsGuaranteed); public const string AllocateContainerForManagedElementsFinally = nameof(AllocateContainerForManagedElementsFinally);
public const string GetManagedValuesDestination = nameof(GetManagedValuesDestination); public const string GetManagedValuesDestination = nameof(GetManagedValuesDestination);
public const string GetUnmanagedValuesSource = nameof(GetUnmanagedValuesSource); public const string GetUnmanagedValuesSource = nameof(GetUnmanagedValuesSource);
} }
@ -82,11 +82,11 @@ namespace Microsoft.Interop
public const string GetManagedValuesDestination = nameof(GetManagedValuesDestination); public const string GetManagedValuesDestination = nameof(GetManagedValuesDestination);
public const string GetUnmanagedValuesSource = nameof(GetUnmanagedValuesSource); public const string GetUnmanagedValuesSource = nameof(GetUnmanagedValuesSource);
public const string ToManaged = nameof(ToManaged); public const string ToManaged = nameof(ToManaged);
public const string ToManagedGuaranteed = nameof(ToManagedGuaranteed); public const string ToManagedFinally = nameof(ToManagedFinally);
public const string FromUnmanaged = nameof(FromUnmanaged); public const string FromUnmanaged = nameof(FromUnmanaged);
// Optional features // Optional features
public const string Free = nameof(Free); public const string Free = nameof(Free);
public const string NotifyInvokeSucceeded = nameof(NotifyInvokeSucceeded); public const string OnInvoked = nameof(OnInvoked);
} }
} }
} }
@ -98,7 +98,7 @@ namespace Microsoft.Interop
public IMethodSymbol? ToUnmanaged; public IMethodSymbol? ToUnmanaged;
public IMethodSymbol? ToUnmanagedWithBuffer; public IMethodSymbol? ToUnmanagedWithBuffer;
public IMethodSymbol? ToManaged; public IMethodSymbol? ToManaged;
public IMethodSymbol? ToManagedGuaranteed; public IMethodSymbol? ToManagedFinally;
// Linear collection // Linear collection
public IMethodSymbol? ManagedValuesSource; public IMethodSymbol? ManagedValuesSource;
@ -142,7 +142,7 @@ namespace Microsoft.Interop
// Unmanaged -> Managed // Unmanaged -> Managed
IMethodSymbol? allocateManaged = LinearCollection.AllocateContainerForManagedElements(marshallerType, managedType); IMethodSymbol? allocateManaged = LinearCollection.AllocateContainerForManagedElements(marshallerType, managedType);
IMethodSymbol? allocateManagedGuaranteed = LinearCollection.AllocateContainerForManagedElementsGuaranteed(marshallerType, managedType, spanOfT); IMethodSymbol? allocateManagedGuaranteed = LinearCollection.AllocateContainerForManagedElementsFinally(marshallerType, managedType, spanOfT);
IMethodSymbol? managedDestination = LinearCollection.GetManagedValuesDestination(marshallerType, managedType, spanOfT); IMethodSymbol? managedDestination = LinearCollection.GetManagedValuesDestination(marshallerType, managedType, spanOfT);
IMethodSymbol? unmanagedSource = LinearCollection.GetUnmanagedValuesSource(marshallerType, readOnlySpanOfT); IMethodSymbol? unmanagedSource = LinearCollection.GetUnmanagedValuesSource(marshallerType, readOnlySpanOfT);
if ((allocateManaged is not null || allocateManagedGuaranteed is not null) if ((allocateManaged is not null || allocateManagedGuaranteed is not null)
@ -158,7 +158,7 @@ namespace Microsoft.Interop
methods = methods with methods = methods with
{ {
ToManaged = allocateManaged, ToManaged = allocateManaged,
ToManagedGuaranteed = allocateManagedGuaranteed, ToManagedFinally = allocateManagedGuaranteed,
ManagedValuesDestination = managedDestination, ManagedValuesDestination = managedDestination,
UnmanagedValuesSource = unmanagedSource UnmanagedValuesSource = unmanagedSource
}; };
@ -178,8 +178,8 @@ namespace Microsoft.Interop
if (toManaged is not null) if (toManaged is not null)
shape |= MarshallerShape.ToManaged; shape |= MarshallerShape.ToManaged;
IMethodSymbol? toManagedGuaranteed = Value.ConvertToManagedGuaranteed(marshallerType, managedType); IMethodSymbol? toManagedFinally = Value.ConvertToManagedFinally(marshallerType, managedType);
if (toManagedGuaranteed is not null) if (toManagedFinally is not null)
shape |= MarshallerShape.GuaranteedUnmarshal; shape |= MarshallerShape.GuaranteedUnmarshal;
methods = methods with methods = methods with
@ -187,7 +187,7 @@ namespace Microsoft.Interop
ToUnmanaged = toUnmanaged, ToUnmanaged = toUnmanaged,
ToUnmanagedWithBuffer = toUnmanagedWithBuffer, ToUnmanagedWithBuffer = toUnmanagedWithBuffer,
ToManaged = toManaged, ToManaged = toManaged,
ToManagedGuaranteed = toManagedGuaranteed ToManagedFinally = toManagedFinally
}; };
} }
@ -275,10 +275,10 @@ namespace Microsoft.Interop
&& SymbolEqualityComparer.Default.Equals(managedType, m.ReturnType)); && SymbolEqualityComparer.Default.Equals(managedType, m.ReturnType));
} }
internal static IMethodSymbol? ConvertToManagedGuaranteed(ITypeSymbol type, ITypeSymbol managedType) internal static IMethodSymbol? ConvertToManagedFinally(ITypeSymbol type, ITypeSymbol managedType)
{ {
// static TManaged ConvertToManagedGuaranteed(TNative unmanaged) // static TManaged ConvertToManagedFinally(TNative unmanaged)
return type.GetMembers(ShapeMemberNames.Value.Stateless.ConvertToManagedGuaranteed) return type.GetMembers(ShapeMemberNames.Value.Stateless.ConvertToManagedFinally)
.OfType<IMethodSymbol>() .OfType<IMethodSymbol>()
.FirstOrDefault(m => m is { IsStatic: true, Parameters.Length: 1, ReturnsVoid: false } .FirstOrDefault(m => m is { IsStatic: true, Parameters.Length: 1, ReturnsVoid: false }
&& SymbolEqualityComparer.Default.Equals(managedType, m.ReturnType)); && SymbolEqualityComparer.Default.Equals(managedType, m.ReturnType));
@ -349,9 +349,9 @@ namespace Microsoft.Interop
&& managedType.IsConstructedFromEqualTypes(m.ReturnType)); && managedType.IsConstructedFromEqualTypes(m.ReturnType));
} }
internal static IMethodSymbol? AllocateContainerForManagedElementsGuaranteed(ITypeSymbol type, ITypeSymbol managedType, ITypeSymbol spanOfT) internal static IMethodSymbol? AllocateContainerForManagedElementsFinally(ITypeSymbol type, ITypeSymbol managedType, ITypeSymbol spanOfT)
{ {
// static TCollection AllocateContainerForManagedElementsGuaranteed(TNative unmanaged, int length); // static TCollection AllocateContainerForManagedElementsFinally(TNative unmanaged, int length);
return type.GetMembers(ShapeMemberNames.LinearCollection.Stateless.AllocateContainerForManagedElements) return type.GetMembers(ShapeMemberNames.LinearCollection.Stateless.AllocateContainerForManagedElements)
.OfType<IMethodSymbol>() .OfType<IMethodSymbol>()
.FirstOrDefault(m => m is { IsStatic: true, Parameters.Length: 2, ReturnsVoid: false } .FirstOrDefault(m => m is { IsStatic: true, Parameters.Length: 2, ReturnsVoid: false }
@ -392,7 +392,7 @@ namespace Microsoft.Interop
public IMethodSymbol? FromUnmanaged { get; init; } public IMethodSymbol? FromUnmanaged { get; init; }
public IMethodSymbol? ToUnmanaged { get; init; } public IMethodSymbol? ToUnmanaged { get; init; }
public IMethodSymbol? Free { get; init; } public IMethodSymbol? Free { get; init; }
public IMethodSymbol? NotifyInvokeSucceeded { get; init; } public IMethodSymbol? OnInvoked { get; init; }
} }
public static (MarshallerShape shape, MarshallerMethods methods) GetShapeForType(ITypeSymbol marshallerType, ITypeSymbol managedType, Compilation compilation) public static (MarshallerShape shape, MarshallerMethods methods) GetShapeForType(ITypeSymbol marshallerType, ITypeSymbol managedType, Compilation compilation)
@ -431,11 +431,11 @@ namespace Microsoft.Interop
} }
IMethodSymbol toManaged = GetToManagedMethod(marshallerType, managedType); IMethodSymbol toManaged = GetToManagedMethod(marshallerType, managedType);
IMethodSymbol toManagedGuaranteed = GetToManagedGuaranteedMethod(marshallerType, managedType); IMethodSymbol toManagedFinally = GetToManagedFinallyMethod(marshallerType, managedType);
IMethodSymbol fromUnmanaged = GetFromUnmanagedMethod(marshallerType, unmanagedType); IMethodSymbol fromUnmanaged = GetFromUnmanagedMethod(marshallerType, unmanagedType);
if ((toManaged, toManagedGuaranteed) is not (null, null) && fromUnmanaged is not null) if ((toManaged, toManagedFinally) is not (null, null) && fromUnmanaged is not null)
{ {
if (toManagedGuaranteed is not null) if (toManagedFinally is not null)
{ {
shape |= MarshallerShape.GuaranteedUnmarshal; shape |= MarshallerShape.GuaranteedUnmarshal;
} }
@ -447,7 +447,7 @@ namespace Microsoft.Interop
{ {
FromUnmanaged = fromUnmanaged, FromUnmanaged = fromUnmanaged,
ToManaged = toManaged, ToManaged = toManaged,
ToManagedGuranteed = toManagedGuaranteed ToManagedGuranteed = toManagedFinally
}; };
} }
@ -458,11 +458,11 @@ namespace Microsoft.Interop
methods = methods with { Free = free }; methods = methods with { Free = free };
} }
IMethodSymbol notifyInvokeSucceeded = GetNotifyInvokeSucceededMethod(marshallerType); IMethodSymbol OnInvoked = GetOnInvokedMethod(marshallerType);
if (notifyInvokeSucceeded is not null) if (OnInvoked is not null)
{ {
shape |= MarshallerShape.NotifyInvokeSucceeded; shape |= MarshallerShape.OnInvoked;
methods = methods with { NotifyInvokeSucceeded = notifyInvokeSucceeded }; methods = methods with { OnInvoked = OnInvoked };
} }
if (GetStatelessGetPinnableReference(marshallerType, managedType) is not null) if (GetStatelessGetPinnableReference(marshallerType, managedType) is not null)
@ -531,9 +531,9 @@ namespace Microsoft.Interop
&& SymbolEqualityComparer.Default.Equals(managedType, m.ReturnType)); && SymbolEqualityComparer.Default.Equals(managedType, m.ReturnType));
} }
private static IMethodSymbol? GetToManagedGuaranteedMethod(ITypeSymbol type, ITypeSymbol managedType) private static IMethodSymbol? GetToManagedFinallyMethod(ITypeSymbol type, ITypeSymbol managedType)
{ {
return type.GetMembers(ShapeMemberNames.Value.Stateful.ToManagedGuaranteed) return type.GetMembers(ShapeMemberNames.Value.Stateful.ToManagedFinally)
.OfType<IMethodSymbol>() .OfType<IMethodSymbol>()
.FirstOrDefault(m => m is { IsStatic: false, Parameters.Length: 0, ReturnsVoid: false, ReturnsByRef: false, ReturnsByRefReadonly: false } .FirstOrDefault(m => m is { IsStatic: false, Parameters.Length: 0, ReturnsVoid: false, ReturnsByRef: false, ReturnsByRefReadonly: false }
&& SymbolEqualityComparer.Default.Equals(managedType, m.ReturnType)); && SymbolEqualityComparer.Default.Equals(managedType, m.ReturnType));
@ -587,9 +587,9 @@ namespace Microsoft.Interop
.FirstOrDefault(m => m is { IsStatic: false, Parameters.Length: 0, ReturnsVoid: true }); .FirstOrDefault(m => m is { IsStatic: false, Parameters.Length: 0, ReturnsVoid: true });
} }
private static IMethodSymbol? GetNotifyInvokeSucceededMethod(ITypeSymbol type) private static IMethodSymbol? GetOnInvokedMethod(ITypeSymbol type)
{ {
return type.GetMembers(ShapeMemberNames.Value.Stateful.NotifyInvokeSucceeded) return type.GetMembers(ShapeMemberNames.Value.Stateful.OnInvoked)
.OfType<IMethodSymbol>() .OfType<IMethodSymbol>()
.FirstOrDefault(m => m is { IsStatic: false, Parameters.Length: 0, ReturnsVoid: true }); .FirstOrDefault(m => m is { IsStatic: false, Parameters.Length: 0, ReturnsVoid: true });
} }

View file

@ -13,7 +13,7 @@ using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
namespace Microsoft.Interop namespace Microsoft.Interop
{ {
public readonly record struct AttributedMarshallingModelOptions(bool RuntimeMarshallingDisabled, Scenario InScenario, Scenario RefScenario, Scenario OutScenario); public readonly record struct AttributedMarshallingModelOptions(bool RuntimeMarshallingDisabled, MarshalMode InMode, MarshalMode RefMode, MarshalMode OutMode);
public class AttributedMarshallingModelGeneratorFactory : IMarshallingGeneratorFactory public class AttributedMarshallingModelGeneratorFactory : IMarshallingGeneratorFactory
{ {
@ -214,15 +214,15 @@ namespace Microsoft.Interop
CustomTypeMarshallerData marshallerData; CustomTypeMarshallerData marshallerData;
if (info.IsManagedReturnPosition) if (info.IsManagedReturnPosition)
{ {
marshallerData = marshalInfo.Marshallers.GetScenarioOrDefault(Options.OutScenario); marshallerData = marshalInfo.Marshallers.GetModeOrDefault(Options.OutMode);
} }
else else
{ {
marshallerData = info.RefKind switch marshallerData = info.RefKind switch
{ {
RefKind.None or RefKind.In => marshalInfo.Marshallers.GetScenarioOrDefault(Options.InScenario), RefKind.None or RefKind.In => marshalInfo.Marshallers.GetModeOrDefault(Options.InMode),
RefKind.Ref => marshalInfo.Marshallers.GetScenarioOrDefault(Options.RefScenario), RefKind.Ref => marshalInfo.Marshallers.GetModeOrDefault(Options.RefMode),
RefKind.Out => marshalInfo.Marshallers.GetScenarioOrDefault(Options.OutScenario), RefKind.Out => marshalInfo.Marshallers.GetModeOrDefault(Options.OutMode),
_ => throw new MarshallingNotSupportedException(info, context) _ => throw new MarshallingNotSupportedException(info, context)
}; };
} }
@ -334,7 +334,7 @@ namespace Microsoft.Interop
{ {
// Marshalling out or return parameter, but no out marshaller is specified // Marshalling out or return parameter, but no out marshaller is specified
if ((info.RefKind == RefKind.Out || info.IsManagedReturnPosition) if ((info.RefKind == RefKind.Out || info.IsManagedReturnPosition)
&& !marshalInfo.Marshallers.IsDefinedOrDefault(Options.OutScenario)) && !marshalInfo.Marshallers.IsDefinedOrDefault(Options.OutMode))
{ {
throw new MarshallingNotSupportedException(info, context) throw new MarshallingNotSupportedException(info, context)
{ {
@ -343,7 +343,7 @@ namespace Microsoft.Interop
} }
// Marshalling ref parameter, but no ref marshaller is specified // Marshalling ref parameter, but no ref marshaller is specified
if (info.RefKind == RefKind.Ref && !marshalInfo.Marshallers.IsDefinedOrDefault(Options.RefScenario)) if (info.RefKind == RefKind.Ref && !marshalInfo.Marshallers.IsDefinedOrDefault(Options.RefMode))
{ {
throw new MarshallingNotSupportedException(info, context) throw new MarshallingNotSupportedException(info, context)
{ {
@ -353,7 +353,7 @@ namespace Microsoft.Interop
// Marshalling in parameter, but no in marshaller is specified // Marshalling in parameter, but no in marshaller is specified
if (info.RefKind == RefKind.In if (info.RefKind == RefKind.In
&& !marshalInfo.Marshallers.IsDefinedOrDefault(Options.InScenario)) && !marshalInfo.Marshallers.IsDefinedOrDefault(Options.InMode))
{ {
throw new MarshallingNotSupportedException(info, context) throw new MarshallingNotSupportedException(info, context)
{ {
@ -365,7 +365,7 @@ namespace Microsoft.Interop
if (!info.IsByRef if (!info.IsByRef
&& !info.IsManagedReturnPosition && !info.IsManagedReturnPosition
&& context.SingleFrameSpansNativeContext && context.SingleFrameSpansNativeContext
&& !(marshalInfo.IsPinnableManagedType || marshalInfo.Marshallers.IsDefinedOrDefault(Options.InScenario))) && !(marshalInfo.IsPinnableManagedType || marshalInfo.Marshallers.IsDefinedOrDefault(Options.InMode)))
{ {
throw new MarshallingNotSupportedException(info, context) throw new MarshallingNotSupportedException(info, context)
{ {

View file

@ -74,7 +74,7 @@ namespace Microsoft.Interop
(string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info); (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info);
// <managedIdentifier> = <marshallerType>.ConvertToManagedGuaranteed(<nativeIdentifier>); // <managedIdentifier> = <marshallerType>.ConvertToManagedFinally(<nativeIdentifier>);
yield return ExpressionStatement( yield return ExpressionStatement(
AssignmentExpression( AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression, SyntaxKind.SimpleAssignmentExpression,
@ -82,7 +82,7 @@ namespace Microsoft.Interop
InvocationExpression( InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
_marshallerTypeSyntax, _marshallerTypeSyntax,
IdentifierName(ShapeMemberNames.Value.Stateless.ConvertToManagedGuaranteed)), IdentifierName(ShapeMemberNames.Value.Stateless.ConvertToManagedFinally)),
ArgumentList(SingletonSeparatedList( ArgumentList(SingletonSeparatedList(
Argument(IdentifierName(nativeIdentifier))))))); Argument(IdentifierName(nativeIdentifier)))))));
} }
@ -324,7 +324,7 @@ namespace Microsoft.Interop
(string managedIdentifier, _) = context.GetIdentifiers(info); (string managedIdentifier, _) = context.GetIdentifiers(info);
// <managedIdentifier> = <marshaller>.ToManagedGuaranteed(); // <managedIdentifier> = <marshaller>.ToManagedFinally();
yield return ExpressionStatement( yield return ExpressionStatement(
AssignmentExpression( AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression, SyntaxKind.SimpleAssignmentExpression,
@ -332,7 +332,7 @@ namespace Microsoft.Interop
InvocationExpression( InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
IdentifierName(context.GetAdditionalIdentifier(info, MarshallerIdentifier)), IdentifierName(context.GetAdditionalIdentifier(info, MarshallerIdentifier)),
IdentifierName(ShapeMemberNames.Value.Stateful.ToManagedGuaranteed)), IdentifierName(ShapeMemberNames.Value.Stateful.ToManagedFinally)),
ArgumentList()))); ArgumentList())));
} }
@ -438,15 +438,15 @@ namespace Microsoft.Interop
public IEnumerable<StatementSyntax> GenerateNotifyForSuccessfulInvokeStatements(TypePositionInfo info, StubCodeContext context) public IEnumerable<StatementSyntax> GenerateNotifyForSuccessfulInvokeStatements(TypePositionInfo info, StubCodeContext context)
{ {
if (!_shape.HasFlag(MarshallerShape.NotifyInvokeSucceeded)) if (!_shape.HasFlag(MarshallerShape.OnInvoked))
yield break; yield break;
// <marshaller>.NotifyInvokeSucceeded(); // <marshaller>.OnInvoked();
yield return ExpressionStatement( yield return ExpressionStatement(
InvocationExpression( InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
IdentifierName(context.GetAdditionalIdentifier(info, MarshallerIdentifier)), IdentifierName(context.GetAdditionalIdentifier(info, MarshallerIdentifier)),
IdentifierName(ShapeMemberNames.Value.Stateful.NotifyInvokeSucceeded)), IdentifierName(ShapeMemberNames.Value.Stateful.OnInvoked)),
ArgumentList())); ArgumentList()));
} }
} }

View file

@ -627,7 +627,7 @@ namespace Microsoft.Interop
else if (type is INamedTypeSymbol namedManagedType) else if (type is INamedTypeSymbol namedManagedType)
{ {
// Entry point type for linear collection marshalling must have the arity of the managed type + 1 // Entry point type for linear collection marshalling must have the arity of the managed type + 1
// for the [ElementUnmanagedType] placeholder // for the element unmanaged type placeholder
if (entryPointType.Arity != namedManagedType.Arity + 1) if (entryPointType.Arity != namedManagedType.Arity + 1)
{ {
_diagnostics.ReportInvalidMarshallingAttributeInfo(attrData, nameof(SR.MarshallerEntryPointTypeMustMatchArity), entryPointType.ToDisplayString(), type.ToDisplayString()); _diagnostics.ReportInvalidMarshallingAttributeInfo(attrData, nameof(SR.MarshallerEntryPointTypeMustMatchArity), entryPointType.ToDisplayString(), type.ToDisplayString());

View file

@ -17,8 +17,8 @@
Link="Production\CustomTypeMarshallerFeatures.cs" /> Link="Production\CustomTypeMarshallerFeatures.cs" />
<Compile Include="$(CoreLibSharedDir)System\Runtime\InteropServices\StringMarshalling.cs" <Compile Include="$(CoreLibSharedDir)System\Runtime\InteropServices\StringMarshalling.cs"
Link="Production\StringMarshalling.cs" /> Link="Production\StringMarshalling.cs" />
<Compile Include="..\..\tests\Ancillary.Interop\Scenario.cs" <Compile Include="$(CoreLibSharedDir)\System\Runtime\InteropServices\Marshalling\MarshalMode.cs"
Link="Production\Scenario.cs" /> Link="Production\MarshalMode.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -18,7 +18,7 @@ namespace Microsoft.Interop
public const string CustomMarshallerAttribute = "System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute"; public const string CustomMarshallerAttribute = "System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute";
public const string CustomMarshallerAttributeGenericPlaceholder = CustomMarshallerAttribute + ".GenericPlaceholder"; public const string CustomMarshallerAttributeGenericPlaceholder = CustomMarshallerAttribute + ".GenericPlaceholder";
public const string ElementUnmanagedTypeAttribute = "System.Runtime.InteropServices.Marshalling.ElementUnmanagedTypeAttribute"; public const string ContiguousCollectionMarshallerAttribute = "System.Runtime.InteropServices.Marshalling.ContiguousCollectionMarshallerAttribute";
public const string AnsiStringMarshaller = "System.Runtime.InteropServices.Marshalling.AnsiStringMarshaller"; public const string AnsiStringMarshaller = "System.Runtime.InteropServices.Marshalling.AnsiStringMarshaller";
public const string BStrStringMarshaller = "System.Runtime.InteropServices.Marshalling.BStrStringMarshaller"; public const string BStrStringMarshaller = "System.Runtime.InteropServices.Marshalling.BStrStringMarshaller";

View file

@ -2169,6 +2169,19 @@ namespace System.Runtime.InteropServices.Marshalling
public string? ToManaged() { throw null; } public string? ToManaged() { throw null; }
public void FreeNative() { } public void FreeNative() { }
} }
[System.AttributeUsageAttribute(System.AttributeTargets.Struct | System.AttributeTargets.Class, AllowMultiple = true)]
public sealed partial class CustomMarshallerAttribute : System.Attribute
{
public CustomMarshallerAttribute(System.Type managedType, System.Runtime.InteropServices.Marshalling.MarshalMode marshalMode, System.Type marshallerType) { }
public System.Type ManagedType { get { throw null; } }
public System.Runtime.InteropServices.Marshalling.MarshalMode MarshalMode { get { throw null; } }
public System.Type MarshallerType { get { throw null; } }
public struct GenericPlaceholder
{
}
}
[System.AttributeUsageAttribute(System.AttributeTargets.Struct)] [System.AttributeUsageAttribute(System.AttributeTargets.Struct)]
public sealed partial class CustomTypeMarshallerAttribute : System.Attribute public sealed partial class CustomTypeMarshallerAttribute : System.Attribute
{ {
@ -2204,6 +2217,19 @@ namespace System.Runtime.InteropServices.Marshalling
Value, Value,
LinearCollection LinearCollection
} }
public enum MarshalMode
{
Default = 0,
ManagedToUnmanagedIn = 1,
ManagedToUnmanagedRef = 2,
ManagedToUnmanagedOut = 3,
UnmanagedToManagedIn = 4,
UnmanagedToManagedRef = 5,
UnmanagedToManagedOut = 6,
ElementIn = 7,
ElementRef = 8,
ElementOut = 9
}
[System.AttributeUsageAttribute(System.AttributeTargets.Parameter | System.AttributeTargets.ReturnValue, AllowMultiple = true)] [System.AttributeUsageAttribute(System.AttributeTargets.Parameter | System.AttributeTargets.ReturnValue, AllowMultiple = true)]
public sealed partial class MarshalUsingAttribute : System.Attribute public sealed partial class MarshalUsingAttribute : System.Attribute
{ {

View file

@ -0,0 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace System.Runtime.InteropServices.Marshalling
{
/// <summary>
/// Specifies that this marshaller entry-point type is a contiguous collection marshaller.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public sealed class ContiguousCollectionMarshallerAttribute : Attribute
{
}
}

View file

@ -1,35 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable enable
using System;
namespace System.Runtime.InteropServices.Marshalling
{
/// <summary>
/// Attribute to indicate an entry point type for defining a marshaller.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
#if LIBRARYIMPORT_GENERATOR_TEST
public
#else
internal
#endif
sealed class CustomMarshallerAttribute : Attribute
{
/// <summary>
/// Create a <see cref="CustomMarshallerAttribute"/> instance.
/// </summary>
/// <param name="managedType">Managed type to marshal.</param>
/// <param name="scenario">Marshalling scenario.</param>
/// <param name="marshallerType">Type used for marshalling.</param>
public CustomMarshallerAttribute(Type managedType, Scenario scenario, Type marshallerType) { }
/// <summary>
/// Placeholder type for generic parameter
/// </summary>
public struct GenericPlaceholder
{
}
}
}

View file

@ -1,17 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace System.Runtime.InteropServices.Marshalling
{
/// <summary>
/// Specifies that a particular generic parameter is the collection element's unmanaged type.
/// </summary>
/// <remarks>
/// If this attribute is provided on a generic parameter of a marshaller, then the generator will assume
/// that it is a linear collection marshaller.
/// </remarks>
[AttributeUsage(AttributeTargets.GenericParameter)]
public sealed class ElementUnmanagedTypeAttribute : Attribute
{
}
}

View file

@ -47,19 +47,19 @@ namespace LibraryImportGenerator.IntegrationTests
[return: MarshalUsing(typeof(IntGuaranteedUnmarshal))] [return: MarshalUsing(typeof(IntGuaranteedUnmarshal))]
public static partial int GuaranteedUnmarshal([MarshalUsing(typeof(ExceptionOnUnmarshal))] out int ret); public static partial int GuaranteedUnmarshal([MarshalUsing(typeof(ExceptionOnUnmarshal))] out int ret);
[CustomMarshaller(typeof(int), Scenario.ManagedToUnmanagedOut, typeof(ExceptionOnUnmarshal))] [CustomMarshaller(typeof(int), MarshalMode.ManagedToUnmanagedOut, typeof(ExceptionOnUnmarshal))]
public static class ExceptionOnUnmarshal public static class ExceptionOnUnmarshal
{ {
public static int ConvertToManaged(int unmanaged) => throw new Exception(); public static int ConvertToManaged(int unmanaged) => throw new Exception();
} }
[CustomMarshaller(typeof(int), Scenario.ManagedToUnmanagedOut, typeof(IntGuaranteedUnmarshal))] [CustomMarshaller(typeof(int), MarshalMode.ManagedToUnmanagedOut, typeof(IntGuaranteedUnmarshal))]
public static unsafe class IntGuaranteedUnmarshal public static unsafe class IntGuaranteedUnmarshal
{ {
public static bool ConvertToManagedGuaranteedCalled = false; public static bool ConvertToManagedFinallyCalled = false;
public static int ConvertToManagedGuaranteed(int unmanaged) public static int ConvertToManagedFinally(int unmanaged)
{ {
ConvertToManagedGuaranteedCalled = true; ConvertToManagedFinallyCalled = true;
return unmanaged; return unmanaged;
} }
} }
@ -134,9 +134,9 @@ namespace LibraryImportGenerator.IntegrationTests
[Fact] [Fact]
public void GuaranteedUnmarshal() public void GuaranteedUnmarshal()
{ {
NativeExportsNE.Stateless.IntGuaranteedUnmarshal.ConvertToManagedGuaranteedCalled = false; NativeExportsNE.Stateless.IntGuaranteedUnmarshal.ConvertToManagedFinallyCalled = false;
Assert.Throws<Exception>(() => NativeExportsNE.Stateless.GuaranteedUnmarshal(out _)); Assert.Throws<Exception>(() => NativeExportsNE.Stateless.GuaranteedUnmarshal(out _));
Assert.True(NativeExportsNE.Stateless.IntGuaranteedUnmarshal.ConvertToManagedGuaranteedCalled); Assert.True(NativeExportsNE.Stateless.IntGuaranteedUnmarshal.ConvertToManagedFinallyCalled);
} }
[Fact] [Fact]
@ -240,7 +240,7 @@ namespace LibraryImportGenerator.IntegrationTests
} }
[Fact] [Fact]
public void NotifyInvokeSucceededInNoReturn() public void OnInvokedInNoReturn()
{ {
bool xNotified = false; bool xNotified = false;
bool yNotified = false; bool yNotified = false;
@ -260,7 +260,7 @@ namespace LibraryImportGenerator.IntegrationTests
} }
[Fact] [Fact]
public void NotifyInvokeSucceededInNoOut() public void OnInvokedInNoOut()
{ {
bool xNotified = false; bool xNotified = false;
bool yNotified = false; bool yNotified = false;

View file

@ -690,7 +690,7 @@ public struct S
}} }}
"; ";
private static string NonStatic = @" private static string NonStatic = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(Marshaller))] [CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller))]
public class Marshaller public class Marshaller
{ {
public struct Native { } public struct Native { }
@ -705,7 +705,7 @@ public class Marshaller
public static class Stateless public static class Stateless
{ {
private static string In = @" private static string In = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(Marshaller))] [CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller))]
public static class Marshaller public static class Marshaller
{ {
public struct Native { } public struct Native { }
@ -714,7 +714,7 @@ public static class Marshaller
} }
"; ";
private static string InBuffer = @" private static string InBuffer = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(Marshaller))] [CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller))]
public static class Marshaller public static class Marshaller
{ {
public struct Native { } public struct Native { }
@ -725,7 +725,7 @@ public static class Marshaller
"; ";
public static string InPinnable = @" public static string InPinnable = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(Marshaller))] [CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller))]
public static unsafe class Marshaller public static unsafe class Marshaller
{ {
public static byte* ConvertToUnmanaged(S s) => default; public static byte* ConvertToUnmanaged(S s) => default;
@ -733,7 +733,7 @@ public static unsafe class Marshaller
} }
"; ";
private static string Out = @" private static string Out = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedOut, typeof(Marshaller))] [CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedOut, typeof(Marshaller))]
public static class Marshaller public static class Marshaller
{ {
public struct Native { } public struct Native { }
@ -742,16 +742,16 @@ public static class Marshaller
} }
"; ";
private static string OutGuaranteed = @" private static string OutGuaranteed = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedOut, typeof(Marshaller))] [CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedOut, typeof(Marshaller))]
public static class Marshaller public static class Marshaller
{ {
public struct Native { } public struct Native { }
public static S ConvertToManagedGuaranteed(Native n) => default; public static S ConvertToManagedFinally(Native n) => default;
} }
"; ";
public static string Ref = @" public static string Ref = @"
[CustomMarshaller(typeof(S), Scenario.Default, typeof(Marshaller))] [CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))]
public static class Marshaller public static class Marshaller
{ {
public struct Native { } public struct Native { }
@ -761,8 +761,8 @@ public static class Marshaller
} }
"; ";
public static string RefBuffer = @" public static string RefBuffer = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(Marshaller))] [CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller))]
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedOut, typeof(Marshaller))] [CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedOut, typeof(Marshaller))]
public static class Marshaller public static class Marshaller
{ {
public struct Native { } public struct Native { }
@ -773,7 +773,7 @@ public static class Marshaller
} }
"; ";
public static string RefOptionalBuffer = @" public static string RefOptionalBuffer = @"
[CustomMarshaller(typeof(S), Scenario.Default, typeof(Marshaller))] [CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))]
public static class Marshaller public static class Marshaller
{ {
public struct Native { } public struct Native { }
@ -793,7 +793,7 @@ public static class Marshaller
+ NonBlittableUserDefinedType() + NonBlittableUserDefinedType()
+ Out; + Out;
public static string NativeToManagedGuaranteedOnlyOutParameter => BasicParameterWithByRefModifier("out", "S") public static string NativeToManagedFinallyOnlyOutParameter => BasicParameterWithByRefModifier("out", "S")
+ NonBlittableUserDefinedType() + NonBlittableUserDefinedType()
+ OutGuaranteed; + OutGuaranteed;
@ -805,7 +805,7 @@ public static class Marshaller
+ NonBlittableUserDefinedType() + NonBlittableUserDefinedType()
+ Out; + Out;
public static string NativeToManagedGuaranteedOnlyReturnValue => BasicReturnType("S") public static string NativeToManagedFinallyOnlyReturnValue => BasicReturnType("S")
+ NonBlittableUserDefinedType() + NonBlittableUserDefinedType()
+ Out; + Out;
@ -844,7 +844,7 @@ public static class Marshaller
public static class Stateful public static class Stateful
{ {
private static string In = @" private static string In = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(M))] [CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(M))]
public static class Marshaller public static class Marshaller
{ {
public struct Native { } public struct Native { }
@ -858,7 +858,7 @@ public static class Marshaller
"; ";
public static string InStatelessPinnable = @" public static string InStatelessPinnable = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(M))] [CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(M))]
public static class Marshaller public static class Marshaller
{ {
public unsafe struct M public unsafe struct M
@ -872,7 +872,7 @@ public static class Marshaller
"; ";
public static string InPinnable = @" public static string InPinnable = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(M))] [CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(M))]
public static class Marshaller public static class Marshaller
{ {
public unsafe struct M public unsafe struct M
@ -886,7 +886,7 @@ public static class Marshaller
"; ";
private static string InBuffer = @" private static string InBuffer = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(M))] [CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(M))]
public static class Marshaller public static class Marshaller
{ {
public struct Native { } public struct Native { }
@ -900,7 +900,7 @@ public static class Marshaller
} }
"; ";
private static string Out = @" private static string Out = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedOut, typeof(M))] [CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedOut, typeof(M))]
public static class Marshaller public static class Marshaller
{ {
public struct Native { } public struct Native { }
@ -913,7 +913,7 @@ public static class Marshaller
} }
"; ";
private static string OutGuaranteed = @" private static string OutGuaranteed = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedOut, typeof(M))] [CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedOut, typeof(M))]
public static class Marshaller public static class Marshaller
{ {
public struct Native { } public struct Native { }
@ -921,12 +921,12 @@ public static class Marshaller
public struct M public struct M
{ {
public void FromUnmanaged(Native n) {} public void FromUnmanaged(Native n) {}
public S ToManagedGuaranteed() => default; public S ToManagedFinally() => default;
} }
} }
"; ";
public static string Ref = @" public static string Ref = @"
[CustomMarshaller(typeof(S), Scenario.Default, typeof(M))] [CustomMarshaller(typeof(S), MarshalMode.Default, typeof(M))]
public static class Marshaller public static class Marshaller
{ {
public struct Native { } public struct Native { }
@ -941,7 +941,7 @@ public static class Marshaller
} }
"; ";
public static string RefWithFree = @" public static string RefWithFree = @"
[CustomMarshaller(typeof(S), Scenario.Default, typeof(M))] [CustomMarshaller(typeof(S), MarshalMode.Default, typeof(M))]
public static class Marshaller public static class Marshaller
{ {
public struct Native { } public struct Native { }
@ -956,8 +956,8 @@ public static class Marshaller
} }
} }
"; ";
public static string RefWithNotifyInvokeSucceeded = @" public static string RefWithOnInvoked = @"
[CustomMarshaller(typeof(S), Scenario.Default, typeof(M))] [CustomMarshaller(typeof(S), MarshalMode.Default, typeof(M))]
public static class Marshaller public static class Marshaller
{ {
public struct Native { } public struct Native { }
@ -968,13 +968,13 @@ public static class Marshaller
public Native ToUnmanaged() => default; public Native ToUnmanaged() => default;
public void FromUnmanaged(Native n) {} public void FromUnmanaged(Native n) {}
public S ToManaged() => default; public S ToManaged() => default;
public void NotifyInvokeSucceeded() {} public void OnInvoked() {}
} }
} }
"; ";
public static string RefBuffer = @" public static string RefBuffer = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(M))] [CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(M))]
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedOut, typeof(M))] [CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedOut, typeof(M))]
public static class Marshaller public static class Marshaller
{ {
public struct Native { } public struct Native { }
@ -990,7 +990,7 @@ public static class Marshaller
} }
"; ";
public static string RefOptionalBuffer = @" public static string RefOptionalBuffer = @"
[CustomMarshaller(typeof(S), Scenario.Default, typeof(M))] [CustomMarshaller(typeof(S), MarshalMode.Default, typeof(M))]
public static class Marshaller public static class Marshaller
{ {
public struct Native { } public struct Native { }
@ -1015,7 +1015,7 @@ public static class Marshaller
+ NonBlittableUserDefinedType() + NonBlittableUserDefinedType()
+ Out; + Out;
public static string NativeToManagedGuaranteedOnlyOutParameter => BasicParameterWithByRefModifier("out", "S") public static string NativeToManagedFinallyOnlyOutParameter => BasicParameterWithByRefModifier("out", "S")
+ NonBlittableUserDefinedType() + NonBlittableUserDefinedType()
+ OutGuaranteed; + OutGuaranteed;
@ -1027,7 +1027,7 @@ public static class Marshaller
+ NonBlittableUserDefinedType() + NonBlittableUserDefinedType()
+ Out; + Out;
public static string NativeToManagedGuaranteedOnlyReturnValue => BasicReturnType("S") public static string NativeToManagedFinallyOnlyReturnValue => BasicReturnType("S")
+ NonBlittableUserDefinedType() + NonBlittableUserDefinedType()
+ Out; + Out;
@ -1043,9 +1043,9 @@ public static class Marshaller
+ NonBlittableUserDefinedType(defineNativeMarshalling: true) + NonBlittableUserDefinedType(defineNativeMarshalling: true)
+ RefWithFree; + RefWithFree;
public static string ParametersAndModifiersWithNotifyInvokeSucceeded = BasicParametersAndModifiers("S", UsingSystemRuntimeInteropServicesMarshalling) public static string ParametersAndModifiersWithOnInvoked = BasicParametersAndModifiers("S", UsingSystemRuntimeInteropServicesMarshalling)
+ NonBlittableUserDefinedType(defineNativeMarshalling: true) + NonBlittableUserDefinedType(defineNativeMarshalling: true)
+ RefWithNotifyInvokeSucceeded; + RefWithOnInvoked;
public static string MarshalUsingParametersAndModifiers = MarshalUsingParametersAndModifiers("S", "Marshaller") public static string MarshalUsingParametersAndModifiers = MarshalUsingParametersAndModifiers("S", "Marshaller")
+ NonBlittableUserDefinedType(defineNativeMarshalling: false) + NonBlittableUserDefinedType(defineNativeMarshalling: false)
@ -1457,8 +1457,9 @@ partial class Test
public static class Stateless public static class Stateless
{ {
public const string In = @" public const string In = @"
[CustomMarshaller(typeof(TestCollection<>), Scenario.ManagedToUnmanagedIn, typeof(Marshaller<,>))] [CustomMarshaller(typeof(TestCollection<>), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller<,>))]
static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement> [ContiguousCollectionMarshaller]
static unsafe class Marshaller<T, TUnmanagedElement>
{ {
public static byte* AllocateContainerForUnmanagedElements(TestCollection<T> managed, out int numElements) => throw null; public static byte* AllocateContainerForUnmanagedElements(TestCollection<T> managed, out int numElements) => throw null;
public static System.ReadOnlySpan<T> GetManagedValuesSource(TestCollection<T> managed) => throw null; public static System.ReadOnlySpan<T> GetManagedValuesSource(TestCollection<T> managed) => throw null;
@ -1466,8 +1467,9 @@ static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement>
} }
"; ";
public const string InPinnable = @" public const string InPinnable = @"
[CustomMarshaller(typeof(TestCollection<>), Scenario.ManagedToUnmanagedIn, typeof(Marshaller<,>))] [CustomMarshaller(typeof(TestCollection<>), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller<,>))]
static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement> [ContiguousCollectionMarshaller]
static unsafe class Marshaller<T, TUnmanagedElement>
{ {
public static byte* AllocateContainerForUnmanagedElements(TestCollection<T> managed, out int numElements) => throw null; public static byte* AllocateContainerForUnmanagedElements(TestCollection<T> managed, out int numElements) => throw null;
public static System.ReadOnlySpan<T> GetManagedValuesSource(TestCollection<T> managed) => throw null; public static System.ReadOnlySpan<T> GetManagedValuesSource(TestCollection<T> managed) => throw null;
@ -1477,8 +1479,9 @@ static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement>
} }
"; ";
public const string InBuffer = @" public const string InBuffer = @"
[CustomMarshaller(typeof(TestCollection<>), Scenario.ManagedToUnmanagedIn, typeof(Marshaller<,>))] [CustomMarshaller(typeof(TestCollection<>), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller<,>))]
static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement> [ContiguousCollectionMarshaller]
static unsafe class Marshaller<T, TUnmanagedElement>
{ {
public const int BufferSize = 0x100; public const int BufferSize = 0x100;
public static byte* AllocateContainerForUnmanagedElements(TestCollection<T> managed, System.Span<byte> buffer, out int numElements) => throw null; public static byte* AllocateContainerForUnmanagedElements(TestCollection<T> managed, System.Span<byte> buffer, out int numElements) => throw null;
@ -1487,8 +1490,9 @@ static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement>
} }
"; ";
public const string Ref = @" public const string Ref = @"
[CustomMarshaller(typeof(TestCollection<>), Scenario.Default, typeof(Marshaller<,>))] [CustomMarshaller(typeof(TestCollection<>), MarshalMode.Default, typeof(Marshaller<,>))]
static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement> [ContiguousCollectionMarshaller]
static unsafe class Marshaller<T, TUnmanagedElement>
{ {
public static byte* AllocateContainerForUnmanagedElements(TestCollection<T> managed, out int numElements) => throw null; public static byte* AllocateContainerForUnmanagedElements(TestCollection<T> managed, out int numElements) => throw null;
public static System.ReadOnlySpan<T> GetManagedValuesSource(TestCollection<T> managed) => throw null; public static System.ReadOnlySpan<T> GetManagedValuesSource(TestCollection<T> managed) => throw null;
@ -1500,8 +1504,9 @@ static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement>
} }
"; ";
public const string RefNested = @" public const string RefNested = @"
[CustomMarshaller(typeof(TestCollection<>), Scenario.Default, typeof(Marshaller<,>.Ref.Nested))] [CustomMarshaller(typeof(TestCollection<>), MarshalMode.Default, typeof(Marshaller<,>.Ref.Nested))]
static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement> [ContiguousCollectionMarshaller]
static unsafe class Marshaller<T, TUnmanagedElement>
{ {
static class Nested static class Nested
{ {
@ -1519,8 +1524,9 @@ static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement>
} }
"; ";
public const string Out = @" public const string Out = @"
[CustomMarshaller(typeof(TestCollection<>), Scenario.ManagedToUnmanagedOut, typeof(Marshaller<,>))] [CustomMarshaller(typeof(TestCollection<>), MarshalMode.ManagedToUnmanagedOut, typeof(Marshaller<,>))]
static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement> [ContiguousCollectionMarshaller]
static unsafe class Marshaller<T, TUnmanagedElement>
{ {
public static TestCollection<T> AllocateContainerForManagedElements(byte* unmanaged, int length) => throw null; public static TestCollection<T> AllocateContainerForManagedElements(byte* unmanaged, int length) => throw null;
public static System.Span<T> GetManagedValuesDestination(TestCollection<T> managed) => throw null; public static System.Span<T> GetManagedValuesDestination(TestCollection<T> managed) => throw null;
@ -1577,8 +1583,9 @@ static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement>
[NativeMarshalling(typeof(Marshaller<,,>))] [NativeMarshalling(typeof(Marshaller<,,>))]
class TestCollection<T> {} class TestCollection<T> {}
[CustomMarshaller(typeof(TestCollection<>), Scenario.Default, typeof(Marshaller<,,>))] [CustomMarshaller(typeof(TestCollection<>), MarshalMode.Default, typeof(Marshaller<,,>))]
static unsafe class Marshaller<T, U, [ElementUnmanagedType] TUnmanagedElement> [ContiguousCollectionMarshaller]
static unsafe class Marshaller<T, U, TUnmanagedElement>
{ {
public static byte* AllocateContainerForUnmanagedElements(TestCollection<T> managed, out int numElements) => throw null; public static byte* AllocateContainerForUnmanagedElements(TestCollection<T> managed, out int numElements) => throw null;
public static System.ReadOnlySpan<T> GetManagedValuesSource(TestCollection<T> managed) => throw null; public static System.ReadOnlySpan<T> GetManagedValuesSource(TestCollection<T> managed) => throw null;

View file

@ -173,21 +173,21 @@ namespace LibraryImportGenerator.UnitTests
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.ParametersAndModifiers }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.ParametersAndModifiers };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.MarshalUsingParametersAndModifiers }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.MarshalUsingParametersAndModifiers };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.NativeToManagedOnlyOutParameter }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.NativeToManagedOnlyOutParameter };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.NativeToManagedGuaranteedOnlyOutParameter }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.NativeToManagedFinallyOnlyOutParameter };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.NativeToManagedOnlyReturnValue }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.NativeToManagedOnlyReturnValue };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.NativeToManagedGuaranteedOnlyReturnValue }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.NativeToManagedFinallyOnlyReturnValue };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.PinByValueInParameter }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.PinByValueInParameter };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.StackallocByValueInParameter }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.StackallocByValueInParameter };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.StackallocParametersAndModifiersNoRef }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.StackallocParametersAndModifiersNoRef };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.OptionalStackallocParametersAndModifiers }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.OptionalStackallocParametersAndModifiers };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.ParametersAndModifiers }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.ParametersAndModifiers };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.ParametersAndModifiersWithFree }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.ParametersAndModifiersWithFree };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.ParametersAndModifiersWithNotifyInvokeSucceeded }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.ParametersAndModifiersWithOnInvoked };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.MarshalUsingParametersAndModifiers }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.MarshalUsingParametersAndModifiers };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.NativeToManagedOnlyOutParameter }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.NativeToManagedOnlyOutParameter };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.NativeToManagedGuaranteedOnlyOutParameter }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.NativeToManagedFinallyOnlyOutParameter };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.NativeToManagedOnlyReturnValue }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.NativeToManagedOnlyReturnValue };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.NativeToManagedGuaranteedOnlyReturnValue }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.NativeToManagedFinallyOnlyReturnValue };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.StackallocByValueInParameter }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.StackallocByValueInParameter };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.PinByValueInParameter }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.PinByValueInParameter };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.MarshallerPinByValueInParameter }; yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.MarshallerPinByValueInParameter };

View file

@ -20,9 +20,9 @@ namespace SharedTypes
public string str2; public string str2;
} }
[CustomMarshaller(typeof(StringContainer), Scenario.ManagedToUnmanagedIn, typeof(In))] [CustomMarshaller(typeof(StringContainer), MarshalMode.ManagedToUnmanagedIn, typeof(In))]
[CustomMarshaller(typeof(StringContainer), Scenario.ManagedToUnmanagedRef, typeof(Ref))] [CustomMarshaller(typeof(StringContainer), MarshalMode.ManagedToUnmanagedRef, typeof(Ref))]
[CustomMarshaller(typeof(StringContainer), Scenario.ManagedToUnmanagedOut, typeof(Out))] [CustomMarshaller(typeof(StringContainer), MarshalMode.ManagedToUnmanagedOut, typeof(Out))]
public static class StringContainerMarshaller public static class StringContainerMarshaller
{ {
public struct StringContainerNative public struct StringContainerNative
@ -77,7 +77,7 @@ namespace SharedTypes
} }
} }
[CustomMarshaller(typeof(double), Scenario.ManagedToUnmanagedIn, typeof(DoubleToBytesBigEndianMarshaller))] [CustomMarshaller(typeof(double), MarshalMode.ManagedToUnmanagedIn, typeof(DoubleToBytesBigEndianMarshaller))]
public static unsafe class DoubleToBytesBigEndianMarshaller public static unsafe class DoubleToBytesBigEndianMarshaller
{ {
public const int BufferSize = 8; public const int BufferSize = 8;
@ -89,7 +89,7 @@ namespace SharedTypes
} }
} }
[CustomMarshaller(typeof(double), Scenario.ManagedToUnmanagedIn, typeof(DoubleToLongMarshaller))] [CustomMarshaller(typeof(double), MarshalMode.ManagedToUnmanagedIn, typeof(DoubleToLongMarshaller))]
public static class DoubleToLongMarshaller public static class DoubleToLongMarshaller
{ {
public static long ConvertToUnmanaged(double managed) public static long ConvertToUnmanaged(double managed)
@ -106,7 +106,7 @@ namespace SharedTypes
public bool b3; public bool b3;
} }
[CustomMarshaller(typeof(BoolStruct), Scenario.Default, typeof(BoolStructMarshaller))] [CustomMarshaller(typeof(BoolStruct), MarshalMode.Default, typeof(BoolStructMarshaller))]
public static class BoolStructMarshaller public static class BoolStructMarshaller
{ {
public struct BoolStructNative public struct BoolStructNative
@ -145,7 +145,7 @@ namespace SharedTypes
public ref int GetPinnableReference() => ref i; public ref int GetPinnableReference() => ref i;
} }
[CustomMarshaller(typeof(IntWrapper), Scenario.Default, typeof(IntWrapperMarshaller))] [CustomMarshaller(typeof(IntWrapper), MarshalMode.Default, typeof(IntWrapperMarshaller))]
public static unsafe class IntWrapperMarshaller public static unsafe class IntWrapperMarshaller
{ {
public static int* ConvertToUnmanaged(IntWrapper managed) public static int* ConvertToUnmanaged(IntWrapper managed)
@ -166,7 +166,7 @@ namespace SharedTypes
} }
} }
[CustomMarshaller(typeof(IntWrapper), Scenario.Default, typeof(Marshaller))] [CustomMarshaller(typeof(IntWrapper), MarshalMode.Default, typeof(Marshaller))]
public static unsafe class IntWrapperMarshallerStateful public static unsafe class IntWrapperMarshallerStateful
{ {
public struct Marshaller public struct Marshaller
@ -205,7 +205,7 @@ namespace SharedTypes
public int i; public int i;
} }
[CustomMarshaller(typeof(IntWrapperWithoutGetPinnableReference), Scenario.Default, typeof(IntWrapperWithoutGetPinnableReferenceMarshaller))] [CustomMarshaller(typeof(IntWrapperWithoutGetPinnableReference), MarshalMode.Default, typeof(IntWrapperWithoutGetPinnableReferenceMarshaller))]
public static unsafe class IntWrapperWithoutGetPinnableReferenceMarshaller public static unsafe class IntWrapperWithoutGetPinnableReferenceMarshaller
{ {
public static int* ConvertToUnmanaged(IntWrapperWithoutGetPinnableReference managed) public static int* ConvertToUnmanaged(IntWrapperWithoutGetPinnableReference managed)
@ -228,7 +228,7 @@ namespace SharedTypes
} }
} }
[CustomMarshaller(typeof(IntWrapperWithoutGetPinnableReference), Scenario.ManagedToUnmanagedIn, typeof(StatelessGetPinnableReference))] [CustomMarshaller(typeof(IntWrapperWithoutGetPinnableReference), MarshalMode.ManagedToUnmanagedIn, typeof(StatelessGetPinnableReference))]
public static unsafe class IntWrapperWithoutGetPinnableReferenceStatefulMarshaller public static unsafe class IntWrapperWithoutGetPinnableReferenceStatefulMarshaller
{ {
public struct StatelessGetPinnableReference public struct StatelessGetPinnableReference
@ -242,7 +242,7 @@ namespace SharedTypes
} }
} }
[CustomMarshaller(typeof(IntWrapperWithoutGetPinnableReference), Scenario.ManagedToUnmanagedIn, typeof(StatefulGetPinnableReference))] [CustomMarshaller(typeof(IntWrapperWithoutGetPinnableReference), MarshalMode.ManagedToUnmanagedIn, typeof(StatefulGetPinnableReference))]
public static unsafe class IntWrapperWithoutGetPinnableReferenceStatefulNoAllocMarshaller public static unsafe class IntWrapperWithoutGetPinnableReferenceStatefulNoAllocMarshaller
{ {
public struct StatefulGetPinnableReference public struct StatefulGetPinnableReference
@ -281,7 +281,7 @@ namespace SharedTypes
} }
} }
[CustomMarshaller(typeof(IntWrapperWithNotification), Scenario.Default, typeof(Marshaller))] [CustomMarshaller(typeof(IntWrapperWithNotification), MarshalMode.Default, typeof(Marshaller))]
public static class IntWrapperWithNotificationMarshaller public static class IntWrapperWithNotificationMarshaller
{ {
public struct Marshaller public struct Marshaller
@ -296,11 +296,11 @@ namespace SharedTypes
public IntWrapperWithNotification ToManaged() => _managed; public IntWrapperWithNotification ToManaged() => _managed;
public void NotifyInvokeSucceeded() => _managed.RaiseInvokeSucceeded(); public void OnInvoked() => _managed.RaiseInvokeSucceeded();
} }
} }
[CustomMarshaller(typeof(BoolStruct), Scenario.Default, typeof(Marshaller))] [CustomMarshaller(typeof(BoolStruct), MarshalMode.Default, typeof(Marshaller))]
public static class BoolStructMarshallerStateful public static class BoolStructMarshallerStateful
{ {
public struct BoolStructNative public struct BoolStructNative
@ -339,8 +339,9 @@ namespace SharedTypes
} }
} }
[CustomMarshaller(typeof(List<>), Scenario.Default, typeof(ListMarshaller<,>))] [CustomMarshaller(typeof(List<>), MarshalMode.Default, typeof(ListMarshaller<,>))]
public unsafe static class ListMarshaller<T, [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged [ContiguousCollectionMarshaller]
public unsafe static class ListMarshaller<T, TUnmanagedElement> where TUnmanagedElement : unmanaged
{ {
public static byte* AllocateContainerForUnmanagedElements(List<T> managed, out int numElements) public static byte* AllocateContainerForUnmanagedElements(List<T> managed, out int numElements)
=> AllocateContainerForUnmanagedElements(managed, Span<byte>.Empty, out numElements); => AllocateContainerForUnmanagedElements(managed, Span<byte>.Empty, out numElements);
@ -397,8 +398,9 @@ namespace SharedTypes
=> Marshal.FreeCoTaskMem((IntPtr)unmanaged); => Marshal.FreeCoTaskMem((IntPtr)unmanaged);
} }
[CustomMarshaller(typeof(List<>), Scenario.Default, typeof(ListMarshallerWithPinning<,>))] [CustomMarshaller(typeof(List<>), MarshalMode.Default, typeof(ListMarshallerWithPinning<,>))]
public unsafe static class ListMarshallerWithPinning<T, [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged [ContiguousCollectionMarshaller]
public unsafe static class ListMarshallerWithPinning<T, TUnmanagedElement> where TUnmanagedElement : unmanaged
{ {
public static byte* AllocateContainerForUnmanagedElements(List<T> managed, out int numElements) public static byte* AllocateContainerForUnmanagedElements(List<T> managed, out int numElements)
=> AllocateContainerForUnmanagedElements(managed, Span<byte>.Empty, out numElements); => AllocateContainerForUnmanagedElements(managed, Span<byte>.Empty, out numElements);
@ -464,8 +466,9 @@ namespace SharedTypes
} }
} }
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), Scenario.Default, typeof(CustomArrayMarshaller<,>))] [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.Default, typeof(CustomArrayMarshaller<,>))]
public unsafe static class CustomArrayMarshaller<T, [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged [ContiguousCollectionMarshaller]
public unsafe static class CustomArrayMarshaller<T, TUnmanagedElement> where TUnmanagedElement : unmanaged
{ {
public static byte* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements) public static byte* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements)
{ {