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
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
[*.{cpp,h,in}]
curly_bracket_next_line = true

View file

@ -97,114 +97,94 @@ namespace System.Runtime.InteropServices.Marshalling;
- Ref = In | Out,
- }
+
+
+ /// <summary>
+ /// Define features for a custom type marshaller.
+ /// An enumeration representing the different marshalling scenarios in our marshalling model.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class)]
+ public sealed class CustomTypeMarshallerFeaturesAttribute : Attribute
+ public enum MarshalMode
+ {
+ /// <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>
+ 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>
+ /// Base class attribute for custom marshaller attributes.
+ /// Attribute to indicate an entry point type for defining a marshaller.
+ /// </summary>
+ /// <remarks>
+ /// Use a base class here to allow doing ManagedToUnmanagedMarshallersAttribute.GenericPlaceholder, etc. without having 3 + separate placeholder types.
+ /// 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
+ [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">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
+ /// </summary>
+ public sealed class GenericPlaceholder { }
+ public struct GenericPlaceholder
+ {
+ }
+ }
+
+ /// <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>
+ [AttributeUsage(AttributeTargets.Class)]
+ public sealed class ManagedToUnmanagedMarshallersAttribute : CustomUnmanagedTypeMarshallersAttributeBase
+ {
+ /// <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
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
+ public sealed class ContiguousCollectionMarshallerAttribute : 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))]
static class TMarshaller<T, U, V...>
{
[CustomTypeMarshallerFeatures(BufferSize = 0x200)]
public static class ManagedToNative
{
public static int BufferSize { get; }
public static TNative ConvertToUnmanaged(TManaged managed, Span<byte> callerAllocatedBuffer); // Can 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
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
[ManagedToUnmanagedMarshallers(typeof(TManaged<,,,...>), OutMarshaller = typeof(NativeToManaged))]
@ -303,7 +283,7 @@ static class TMarshaller<T, U, V...>
{
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
}
@ -347,7 +327,7 @@ static class TMarshaller<T, U, V...>
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.
}
@ -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))]
static class TMarshaller<T, U, V...>
{
[CustomTypeMarshallerFeatures(BufferSize = 0x200)]
public struct ManagedToNative // Can be ref struct
{
public static int BufferSize { get; }
public ManagedToNative(); // Optional, 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 void NotifyInvokeSucceeded(); // Optional. Should not throw exceptions.
public void OnInvoked(); // Optional. 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 TManaged ToManagedGuaranteed(); // Should not throw exceptions.
public TManaged ToManagedFinally(); // 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.
@ -463,9 +443,11 @@ The type `TNative` can be any `unmanaged` type. It represents whatever unmanaged
### Stateless Managed->Unmanaged
```csharp
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(ManagedToNative))]
[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(ManagedToNative))]
static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged
[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))]
[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.UnmanagedToManagedOut, typeof(ManagedToNative))]
[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ElementIn, typeof(ManagedToNative))]
[ContiguousCollectionMarshaller]
static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement : unmanaged
{
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`.
```csharp
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(ManagedToNative))]
[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(ManagedToNative))]
static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged
[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))]
[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ElementIn, typeof(ManagedToNative))]
[ContiguousCollectionMarshaller]
static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement : unmanaged
{
[CustomTypeMarshallerFeatures(BufferSize = 0x200)]
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 ReadOnlySpan<TManagedElement> GetManagedValuesSource(TCollection managed); // Can throw exceptions
@ -511,9 +494,11 @@ static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> w
### Stateless Unmanaged->Managed
```csharp
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(NativeToManaged))]
[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(NativeToManaged))]
static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged
[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))]
[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.UnmanagedToManagedIn, typeof(NativeToManaged))]
[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ElementOut, typeof(NativeToManaged))]
[ContiguousCollectionMarshaller]
static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement : unmanaged
{
public static class NativeToManaged
{
@ -531,16 +516,16 @@ static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> w
### 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
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(NativeToManaged))]
[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(NativeToManaged))]
static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged
[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))]
[ContiguousCollectionMarshaller]
static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement : unmanaged
{
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
@ -554,10 +539,11 @@ static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> w
### Stateless Bidirectional
```csharp
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), RefMarshaller = typeof(Bidirectional))]
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), RefMarshaller = typeof(Bidirectional))]
[ElementMarshaller(typeof(TManaged<,,,...>), typeof(Bidirectional))]
static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged
[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedRef, typeof(Bidirectional))]
[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.UnmanagedToManagedRef, typeof(Bidirectional))]
[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ElementRef, typeof(Bidirectional))]
[ContiguousCollectionMarshaller]
static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement : unmanaged
{
public static class Bidirectional
{
@ -572,9 +558,10 @@ static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> w
### Stateful Managed->Unmanaged
```csharp
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(ManagedToNative))]
[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(ManagedToNative))]
static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged
[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))]
[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.UnmanagedToManagedOut, typeof(ManagedToNative))]
[ContiguousCollectionMarshaller]
static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement : unmanaged
{
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 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.
```csharp
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(ManagedToNative))]
[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(ManagedToNative))]
static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged
[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))]
[ContiguousCollectionMarshaller]
static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement : unmanaged
{
[CustomTypeMarshallerFeatures(BufferSize = 0x200)]
public struct ManagedToNative // Can be ref struct
{
public static int BufferSize { get; }
public ManagedToNative(); // Optional, 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 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
```csharp
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(NativeToManaged))]
[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(NativeToManaged))]
static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged
[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))]
[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.UnmanagedToManagedIn, typeof(NativeToManaged))]
[ContiguousCollectionMarshaller]
static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement : unmanaged
{
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
```csharp
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(NativeToManaged))]
[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(NativeToManaged))]
static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged
[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))]
[ContiguousCollectionMarshaller]
static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement : unmanaged
{
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 TCollection ToManagedGuaranteed(); // Can throw exceptions
public TCollection ToManagedFinally(); // Can 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
```csharp
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), RefMarshaller = typeof(Bidirectional))]
[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), RefMarshaller = typeof(Bidirectional))]
static class TMarshaller<T, U, V..., [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged
[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedRef, typeof(Bidirectional))]
[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.UnmanagedToManagedRef, typeof(Bidirectional))]
[ContiguousCollectionMarshaller]
static class TMarshaller<T, U, V..., TUnmanagedElement> where TUnmanagedElement : unmanaged
{
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.
### 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.
@ -731,7 +721,7 @@ The marshaller type must be an entry-point marshaller type as defined above and
- The type must either be:
- Non-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.
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>
<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>
</Target>

View file

@ -49,7 +49,7 @@ namespace System.DirectoryServices.Protocols
public int packageListLength;
#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
{
public static Native ConvertToUnmanaged(SEC_WINNT_AUTH_IDENTITY_EX managed)

View file

@ -40,7 +40,7 @@ internal static partial class Interop
internal uint nStartPage;
#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 Native ConvertToUnmanaged(CRYPTUI_VIEWCERTIFICATE_STRUCTW managed) => new(managed);
@ -152,7 +152,7 @@ internal static partial class Interop
internal IntPtr hSelectedCertStore;
#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 Native ConvertToUnmanaged(CRYPTUI_SELECTCERTIFICATE_STRUCTW managed) => new(managed);

View file

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

View file

@ -262,7 +262,7 @@ internal static partial class Interop
[MarshalAs(UnmanagedType.Bool)]
public bool AutoLoginIfChallenged;
#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 Native ConvertToUnmanaged(WINHTTP_AUTOPROXY_OPTIONS managed) => new(managed);

View file

@ -28,7 +28,7 @@ internal static partial class Interop
private ushort wReserved1;
private ushort dwSupport;
#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 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 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 Native ConvertToUnmanaged(IPv6MulticastRequest managed) => new(managed);

View file

@ -703,7 +703,7 @@ namespace Microsoft.Win32
public uint Type;
#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 Native ConvertToUnmanaged(EvtStringVariant managed) => new(managed);

View file

@ -188,7 +188,7 @@ internal static partial class Interop
internal int fwType;
#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 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\ArrayMarshaller.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\CustomTypeMarshallerDirection.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\MarshalMode.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\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
namespace Microsoft.Interop
#else
namespace System.Runtime.InteropServices
namespace System.Runtime.InteropServices.Marshalling
#endif
{
/// <summary>
/// An enumeration representing the different marshalling scenarios in our marshalling model.
/// An enumeration representing the different marshalling modes in our marshalling model.
/// </summary>
#if LIBRARYIMPORT_GENERATOR_TEST || MICROSOFT_INTEROP_SOURCEGENERATION
public
#else
internal
#endif
enum Scenario
public enum MarshalMode
{
/// <summary>
/// All scenarios. A marshaller specified with this scenario will be used if there is not a specific
/// marshaller specified for a given usage scenario.
/// All modes. A marshaller specified with this mode will be used if there is not a specific
/// marshaller specified for a given usage mode.
/// </summary>
Default,
/// <summary>

View file

@ -500,6 +500,13 @@ namespace Microsoft.Interop.Analyzers
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(
attributeData.CreateDiagnostic(
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
// use the regular blittable marshaller in all cases.
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
// as the later generator factories only apply to parameters.
generatorFactory = new AttributedMarshallingModelGeneratorFactory(
generatorFactory,
elementFactory,
new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, Scenario.ManagedToUnmanagedIn, Scenario.ManagedToUnmanagedRef, Scenario.ManagedToUnmanagedOut));
new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, MarshalMode.ManagedToUnmanagedIn, MarshalMode.ManagedToUnmanagedRef, MarshalMode.ManagedToUnmanagedOut));
generatorFactory = new ByValueContentsMarshalKindValidator(generatorFactory);
}

View file

@ -24,32 +24,32 @@ namespace Microsoft.Interop
MarshallingInfo? CollectionElementMarshallingInfo);
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;
if (Scenarios.TryGetValue(scenario, out data))
if (Modes.TryGetValue(mode, out data))
return data;
if (Scenarios.TryGetValue(Scenario.Default, out data))
if (Modes.TryGetValue(MarshalMode.Default, out data))
return data;
// TODO: Hard failure based on previous implementation
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 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)
{
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)
@ -116,7 +116,7 @@ namespace Microsoft.Interop
// We expect a callback for getting the element marshalling info when handling linear collection marshalling
Debug.Assert(!isLinearCollectionMarshalling || getMarshallingInfoForElement is not null);
Dictionary<Scenario, CustomTypeMarshallerData> scenarios = new();
Dictionary<MarshalMode, CustomTypeMarshallerData> modes = new();
foreach (AttributeData attr in attrs)
{
Debug.Assert(attr.ConstructorArguments.Length == 3);
@ -136,7 +136,7 @@ namespace Microsoft.Interop
&& !compilation.HasImplicitConversion(managedType, managedTypeInst))
return false;
var marshallerScenario = (Scenario)attr.ConstructorArguments[1].Value!;
var marshalMode = (MarshalMode)attr.ConstructorArguments[1].Value!;
ITypeSymbol? marshallerTypeOnAttr = attr.ConstructorArguments[2].Value as ITypeSymbol;
if (marshallerTypeOnAttr is null)
@ -168,51 +168,51 @@ namespace Microsoft.Interop
}
// 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,
Scenario.ManagedToUnmanagedIn
or Scenario.UnmanagedToManagedOut
MarshalMode.ManagedToUnmanagedIn
or MarshalMode.UnmanagedToManagedOut
=> MarshallingDirection.ManagedToUnmanaged,
Scenario.ManagedToUnmanagedOut
or Scenario.UnmanagedToManagedIn
MarshalMode.ManagedToUnmanagedOut
or MarshalMode.UnmanagedToManagedIn
=> MarshallingDirection.UnmanagedToManaged,
Scenario.ManagedToUnmanagedRef
or Scenario.UnmanagedToManagedRef
MarshalMode.ManagedToUnmanagedRef
or MarshalMode.UnmanagedToManagedRef
=> MarshallingDirection.Bidirectional,
Scenario.ElementIn
or Scenario.ElementRef
or Scenario.ElementOut
MarshalMode.ElementIn
or MarshalMode.ElementRef
or MarshalMode.ElementOut
=> MarshallingDirection.Bidirectional,
_ => throw new UnreachableException()
};
// TODO: Report invalid shape for scenario
// Skip checking for bidirectional support for Default scenario - always take / store marshaller data
// TODO: Report invalid shape for mode
// Skip checking for bidirectional support for Default mode - always take / store marshaller data
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
|| scenarios.ContainsKey(marshallerScenario))
|| modes.ContainsKey(marshalMode))
{
continue;
}
scenarios.Add(marshallerScenario, data.Value);
modes.Add(marshalMode, data.Value);
}
if (scenarios.Count == 0)
if (modes.Count == 0)
return false;
marshallers = new CustomTypeMarshallers()
{
Scenarios = scenarios.ToImmutableDictionary()
Modes = modes.ToImmutableDictionary()
};
return true;
@ -392,10 +392,10 @@ namespace Microsoft.Interop
}
else
{
// Native type is the first parameter of ConvertToManaged or ConvertToManagedGuaranteed
if (methods.ToManagedGuaranteed is not null)
// Native type is the first parameter of ConvertToManaged or ConvertToManagedFinally
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)
{

View file

@ -22,7 +22,7 @@ namespace Microsoft.Interop
ToManaged = 0x10,
GuaranteedUnmarshal = 0x20,
Free = 0x40,
NotifyInvokeSucceeded = 0x80,
OnInvoked = 0x80,
}
public static class ShapeMemberNames
@ -36,7 +36,7 @@ namespace Microsoft.Interop
public static class Stateless
{
public const string ConvertToManaged = nameof(ConvertToManaged);
public const string ConvertToManagedGuaranteed = nameof(ConvertToManagedGuaranteed);
public const string ConvertToManagedFinally = nameof(ConvertToManagedFinally);
public const string ConvertToUnmanaged = nameof(ConvertToUnmanaged);
}
@ -47,11 +47,11 @@ namespace Microsoft.Interop
public const string ToUnmanaged = nameof(ToUnmanaged);
// Unmanaged to managed
public const string ToManaged = nameof(ToManaged);
public const string ToManagedGuaranteed = nameof(ToManagedGuaranteed);
public const string ToManagedFinally = nameof(ToManagedFinally);
public const string FromUnmanaged = nameof(FromUnmanaged);
// Optional features
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
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 GetUnmanagedValuesSource = nameof(GetUnmanagedValuesSource);
}
@ -82,11 +82,11 @@ namespace Microsoft.Interop
public const string GetManagedValuesDestination = nameof(GetManagedValuesDestination);
public const string GetUnmanagedValuesSource = nameof(GetUnmanagedValuesSource);
public const string ToManaged = nameof(ToManaged);
public const string ToManagedGuaranteed = nameof(ToManagedGuaranteed);
public const string ToManagedFinally = nameof(ToManagedFinally);
public const string FromUnmanaged = nameof(FromUnmanaged);
// Optional features
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? ToUnmanagedWithBuffer;
public IMethodSymbol? ToManaged;
public IMethodSymbol? ToManagedGuaranteed;
public IMethodSymbol? ToManagedFinally;
// Linear collection
public IMethodSymbol? ManagedValuesSource;
@ -142,7 +142,7 @@ namespace Microsoft.Interop
// Unmanaged -> Managed
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? unmanagedSource = LinearCollection.GetUnmanagedValuesSource(marshallerType, readOnlySpanOfT);
if ((allocateManaged is not null || allocateManagedGuaranteed is not null)
@ -158,7 +158,7 @@ namespace Microsoft.Interop
methods = methods with
{
ToManaged = allocateManaged,
ToManagedGuaranteed = allocateManagedGuaranteed,
ToManagedFinally = allocateManagedGuaranteed,
ManagedValuesDestination = managedDestination,
UnmanagedValuesSource = unmanagedSource
};
@ -178,8 +178,8 @@ namespace Microsoft.Interop
if (toManaged is not null)
shape |= MarshallerShape.ToManaged;
IMethodSymbol? toManagedGuaranteed = Value.ConvertToManagedGuaranteed(marshallerType, managedType);
if (toManagedGuaranteed is not null)
IMethodSymbol? toManagedFinally = Value.ConvertToManagedFinally(marshallerType, managedType);
if (toManagedFinally is not null)
shape |= MarshallerShape.GuaranteedUnmarshal;
methods = methods with
@ -187,7 +187,7 @@ namespace Microsoft.Interop
ToUnmanaged = toUnmanaged,
ToUnmanagedWithBuffer = toUnmanagedWithBuffer,
ToManaged = toManaged,
ToManagedGuaranteed = toManagedGuaranteed
ToManagedFinally = toManagedFinally
};
}
@ -275,10 +275,10 @@ namespace Microsoft.Interop
&& 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)
return type.GetMembers(ShapeMemberNames.Value.Stateless.ConvertToManagedGuaranteed)
// static TManaged ConvertToManagedFinally(TNative unmanaged)
return type.GetMembers(ShapeMemberNames.Value.Stateless.ConvertToManagedFinally)
.OfType<IMethodSymbol>()
.FirstOrDefault(m => m is { IsStatic: true, Parameters.Length: 1, ReturnsVoid: false }
&& SymbolEqualityComparer.Default.Equals(managedType, m.ReturnType));
@ -349,9 +349,9 @@ namespace Microsoft.Interop
&& 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)
.OfType<IMethodSymbol>()
.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? ToUnmanaged { 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)
@ -431,11 +431,11 @@ namespace Microsoft.Interop
}
IMethodSymbol toManaged = GetToManagedMethod(marshallerType, managedType);
IMethodSymbol toManagedGuaranteed = GetToManagedGuaranteedMethod(marshallerType, managedType);
IMethodSymbol toManagedFinally = GetToManagedFinallyMethod(marshallerType, managedType);
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;
}
@ -447,7 +447,7 @@ namespace Microsoft.Interop
{
FromUnmanaged = fromUnmanaged,
ToManaged = toManaged,
ToManagedGuranteed = toManagedGuaranteed
ToManagedGuranteed = toManagedFinally
};
}
@ -458,11 +458,11 @@ namespace Microsoft.Interop
methods = methods with { Free = free };
}
IMethodSymbol notifyInvokeSucceeded = GetNotifyInvokeSucceededMethod(marshallerType);
if (notifyInvokeSucceeded is not null)
IMethodSymbol OnInvoked = GetOnInvokedMethod(marshallerType);
if (OnInvoked is not null)
{
shape |= MarshallerShape.NotifyInvokeSucceeded;
methods = methods with { NotifyInvokeSucceeded = notifyInvokeSucceeded };
shape |= MarshallerShape.OnInvoked;
methods = methods with { OnInvoked = OnInvoked };
}
if (GetStatelessGetPinnableReference(marshallerType, managedType) is not null)
@ -531,9 +531,9 @@ namespace Microsoft.Interop
&& 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>()
.FirstOrDefault(m => m is { IsStatic: false, Parameters.Length: 0, ReturnsVoid: false, ReturnsByRef: false, ReturnsByRefReadonly: false }
&& SymbolEqualityComparer.Default.Equals(managedType, m.ReturnType));
@ -587,9 +587,9 @@ namespace Microsoft.Interop
.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>()
.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
{
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
{
@ -214,15 +214,15 @@ namespace Microsoft.Interop
CustomTypeMarshallerData marshallerData;
if (info.IsManagedReturnPosition)
{
marshallerData = marshalInfo.Marshallers.GetScenarioOrDefault(Options.OutScenario);
marshallerData = marshalInfo.Marshallers.GetModeOrDefault(Options.OutMode);
}
else
{
marshallerData = info.RefKind switch
{
RefKind.None or RefKind.In => marshalInfo.Marshallers.GetScenarioOrDefault(Options.InScenario),
RefKind.Ref => marshalInfo.Marshallers.GetScenarioOrDefault(Options.RefScenario),
RefKind.Out => marshalInfo.Marshallers.GetScenarioOrDefault(Options.OutScenario),
RefKind.None or RefKind.In => marshalInfo.Marshallers.GetModeOrDefault(Options.InMode),
RefKind.Ref => marshalInfo.Marshallers.GetModeOrDefault(Options.RefMode),
RefKind.Out => marshalInfo.Marshallers.GetModeOrDefault(Options.OutMode),
_ => throw new MarshallingNotSupportedException(info, context)
};
}
@ -334,7 +334,7 @@ namespace Microsoft.Interop
{
// Marshalling out or return parameter, but no out marshaller is specified
if ((info.RefKind == RefKind.Out || info.IsManagedReturnPosition)
&& !marshalInfo.Marshallers.IsDefinedOrDefault(Options.OutScenario))
&& !marshalInfo.Marshallers.IsDefinedOrDefault(Options.OutMode))
{
throw new MarshallingNotSupportedException(info, context)
{
@ -343,7 +343,7 @@ namespace Microsoft.Interop
}
// 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)
{
@ -353,7 +353,7 @@ namespace Microsoft.Interop
// Marshalling in parameter, but no in marshaller is specified
if (info.RefKind == RefKind.In
&& !marshalInfo.Marshallers.IsDefinedOrDefault(Options.InScenario))
&& !marshalInfo.Marshallers.IsDefinedOrDefault(Options.InMode))
{
throw new MarshallingNotSupportedException(info, context)
{
@ -365,7 +365,7 @@ namespace Microsoft.Interop
if (!info.IsByRef
&& !info.IsManagedReturnPosition
&& context.SingleFrameSpansNativeContext
&& !(marshalInfo.IsPinnableManagedType || marshalInfo.Marshallers.IsDefinedOrDefault(Options.InScenario)))
&& !(marshalInfo.IsPinnableManagedType || marshalInfo.Marshallers.IsDefinedOrDefault(Options.InMode)))
{
throw new MarshallingNotSupportedException(info, context)
{

View file

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

View file

@ -627,7 +627,7 @@ namespace Microsoft.Interop
else if (type is INamedTypeSymbol namedManagedType)
{
// 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)
{
_diagnostics.ReportInvalidMarshallingAttributeInfo(attrData, nameof(SR.MarshallerEntryPointTypeMustMatchArity), entryPointType.ToDisplayString(), type.ToDisplayString());

View file

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

View file

@ -18,7 +18,7 @@ namespace Microsoft.Interop
public const string CustomMarshallerAttribute = "System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute";
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 BStrStringMarshaller = "System.Runtime.InteropServices.Marshalling.BStrStringMarshaller";

View file

@ -2169,6 +2169,19 @@ namespace System.Runtime.InteropServices.Marshalling
public string? ToManaged() { throw null; }
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)]
public sealed partial class CustomTypeMarshallerAttribute : System.Attribute
{
@ -2204,6 +2217,19 @@ namespace System.Runtime.InteropServices.Marshalling
Value,
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)]
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))]
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 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 bool ConvertToManagedGuaranteedCalled = false;
public static int ConvertToManagedGuaranteed(int unmanaged)
public static bool ConvertToManagedFinallyCalled = false;
public static int ConvertToManagedFinally(int unmanaged)
{
ConvertToManagedGuaranteedCalled = true;
ConvertToManagedFinallyCalled = true;
return unmanaged;
}
}
@ -134,9 +134,9 @@ namespace LibraryImportGenerator.IntegrationTests
[Fact]
public void GuaranteedUnmarshal()
{
NativeExportsNE.Stateless.IntGuaranteedUnmarshal.ConvertToManagedGuaranteedCalled = false;
NativeExportsNE.Stateless.IntGuaranteedUnmarshal.ConvertToManagedFinallyCalled = false;
Assert.Throws<Exception>(() => NativeExportsNE.Stateless.GuaranteedUnmarshal(out _));
Assert.True(NativeExportsNE.Stateless.IntGuaranteedUnmarshal.ConvertToManagedGuaranteedCalled);
Assert.True(NativeExportsNE.Stateless.IntGuaranteedUnmarshal.ConvertToManagedFinallyCalled);
}
[Fact]
@ -240,7 +240,7 @@ namespace LibraryImportGenerator.IntegrationTests
}
[Fact]
public void NotifyInvokeSucceededInNoReturn()
public void OnInvokedInNoReturn()
{
bool xNotified = false;
bool yNotified = false;
@ -260,7 +260,7 @@ namespace LibraryImportGenerator.IntegrationTests
}
[Fact]
public void NotifyInvokeSucceededInNoOut()
public void OnInvokedInNoOut()
{
bool xNotified = false;
bool yNotified = false;

View file

@ -690,7 +690,7 @@ public struct S
}}
";
private static string NonStatic = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(Marshaller))]
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller))]
public class Marshaller
{
public struct Native { }
@ -705,7 +705,7 @@ public class Marshaller
public static class Stateless
{
private static string In = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(Marshaller))]
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller))]
public static class Marshaller
{
public struct Native { }
@ -714,7 +714,7 @@ public static class Marshaller
}
";
private static string InBuffer = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(Marshaller))]
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller))]
public static class Marshaller
{
public struct Native { }
@ -725,7 +725,7 @@ public static class Marshaller
";
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 byte* ConvertToUnmanaged(S s) => default;
@ -733,7 +733,7 @@ public static unsafe class Marshaller
}
";
private static string Out = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedOut, typeof(Marshaller))]
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedOut, typeof(Marshaller))]
public static class Marshaller
{
public struct Native { }
@ -742,16 +742,16 @@ public static class Marshaller
}
";
private static string OutGuaranteed = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedOut, typeof(Marshaller))]
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedOut, typeof(Marshaller))]
public static class Marshaller
{
public struct Native { }
public static S ConvertToManagedGuaranteed(Native n) => default;
public static S ConvertToManagedFinally(Native n) => default;
}
";
public static string Ref = @"
[CustomMarshaller(typeof(S), Scenario.Default, typeof(Marshaller))]
[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))]
public static class Marshaller
{
public struct Native { }
@ -761,8 +761,8 @@ public static class Marshaller
}
";
public static string RefBuffer = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(Marshaller))]
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedOut, typeof(Marshaller))]
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller))]
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedOut, typeof(Marshaller))]
public static class Marshaller
{
public struct Native { }
@ -773,7 +773,7 @@ public static class Marshaller
}
";
public static string RefOptionalBuffer = @"
[CustomMarshaller(typeof(S), Scenario.Default, typeof(Marshaller))]
[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(Marshaller))]
public static class Marshaller
{
public struct Native { }
@ -793,7 +793,7 @@ public static class Marshaller
+ NonBlittableUserDefinedType()
+ Out;
public static string NativeToManagedGuaranteedOnlyOutParameter => BasicParameterWithByRefModifier("out", "S")
public static string NativeToManagedFinallyOnlyOutParameter => BasicParameterWithByRefModifier("out", "S")
+ NonBlittableUserDefinedType()
+ OutGuaranteed;
@ -805,7 +805,7 @@ public static class Marshaller
+ NonBlittableUserDefinedType()
+ Out;
public static string NativeToManagedGuaranteedOnlyReturnValue => BasicReturnType("S")
public static string NativeToManagedFinallyOnlyReturnValue => BasicReturnType("S")
+ NonBlittableUserDefinedType()
+ Out;
@ -844,7 +844,7 @@ public static class Marshaller
public static class Stateful
{
private static string In = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(M))]
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(M))]
public static class Marshaller
{
public struct Native { }
@ -858,7 +858,7 @@ public static class Marshaller
";
public static string InStatelessPinnable = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(M))]
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(M))]
public static class Marshaller
{
public unsafe struct M
@ -872,7 +872,7 @@ public static class Marshaller
";
public static string InPinnable = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(M))]
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(M))]
public static class Marshaller
{
public unsafe struct M
@ -886,7 +886,7 @@ public static class Marshaller
";
private static string InBuffer = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(M))]
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(M))]
public static class Marshaller
{
public struct Native { }
@ -900,7 +900,7 @@ public static class Marshaller
}
";
private static string Out = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedOut, typeof(M))]
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedOut, typeof(M))]
public static class Marshaller
{
public struct Native { }
@ -913,7 +913,7 @@ public static class Marshaller
}
";
private static string OutGuaranteed = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedOut, typeof(M))]
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedOut, typeof(M))]
public static class Marshaller
{
public struct Native { }
@ -921,12 +921,12 @@ public static class Marshaller
public struct M
{
public void FromUnmanaged(Native n) {}
public S ToManagedGuaranteed() => default;
public S ToManagedFinally() => default;
}
}
";
public static string Ref = @"
[CustomMarshaller(typeof(S), Scenario.Default, typeof(M))]
[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(M))]
public static class Marshaller
{
public struct Native { }
@ -941,7 +941,7 @@ public static class Marshaller
}
";
public static string RefWithFree = @"
[CustomMarshaller(typeof(S), Scenario.Default, typeof(M))]
[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(M))]
public static class Marshaller
{
public struct Native { }
@ -956,8 +956,8 @@ public static class Marshaller
}
}
";
public static string RefWithNotifyInvokeSucceeded = @"
[CustomMarshaller(typeof(S), Scenario.Default, typeof(M))]
public static string RefWithOnInvoked = @"
[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(M))]
public static class Marshaller
{
public struct Native { }
@ -968,13 +968,13 @@ public static class Marshaller
public Native ToUnmanaged() => default;
public void FromUnmanaged(Native n) {}
public S ToManaged() => default;
public void NotifyInvokeSucceeded() {}
public void OnInvoked() {}
}
}
";
public static string RefBuffer = @"
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(M))]
[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedOut, typeof(M))]
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedIn, typeof(M))]
[CustomMarshaller(typeof(S), MarshalMode.ManagedToUnmanagedOut, typeof(M))]
public static class Marshaller
{
public struct Native { }
@ -990,7 +990,7 @@ public static class Marshaller
}
";
public static string RefOptionalBuffer = @"
[CustomMarshaller(typeof(S), Scenario.Default, typeof(M))]
[CustomMarshaller(typeof(S), MarshalMode.Default, typeof(M))]
public static class Marshaller
{
public struct Native { }
@ -1015,7 +1015,7 @@ public static class Marshaller
+ NonBlittableUserDefinedType()
+ Out;
public static string NativeToManagedGuaranteedOnlyOutParameter => BasicParameterWithByRefModifier("out", "S")
public static string NativeToManagedFinallyOnlyOutParameter => BasicParameterWithByRefModifier("out", "S")
+ NonBlittableUserDefinedType()
+ OutGuaranteed;
@ -1027,7 +1027,7 @@ public static class Marshaller
+ NonBlittableUserDefinedType()
+ Out;
public static string NativeToManagedGuaranteedOnlyReturnValue => BasicReturnType("S")
public static string NativeToManagedFinallyOnlyReturnValue => BasicReturnType("S")
+ NonBlittableUserDefinedType()
+ Out;
@ -1043,9 +1043,9 @@ public static class Marshaller
+ NonBlittableUserDefinedType(defineNativeMarshalling: true)
+ RefWithFree;
public static string ParametersAndModifiersWithNotifyInvokeSucceeded = BasicParametersAndModifiers("S", UsingSystemRuntimeInteropServicesMarshalling)
public static string ParametersAndModifiersWithOnInvoked = BasicParametersAndModifiers("S", UsingSystemRuntimeInteropServicesMarshalling)
+ NonBlittableUserDefinedType(defineNativeMarshalling: true)
+ RefWithNotifyInvokeSucceeded;
+ RefWithOnInvoked;
public static string MarshalUsingParametersAndModifiers = MarshalUsingParametersAndModifiers("S", "Marshaller")
+ NonBlittableUserDefinedType(defineNativeMarshalling: false)
@ -1457,8 +1457,9 @@ partial class Test
public static class Stateless
{
public const string In = @"
[CustomMarshaller(typeof(TestCollection<>), Scenario.ManagedToUnmanagedIn, typeof(Marshaller<,>))]
static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement>
[CustomMarshaller(typeof(TestCollection<>), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller<,>))]
[ContiguousCollectionMarshaller]
static unsafe class Marshaller<T, TUnmanagedElement>
{
public static byte* AllocateContainerForUnmanagedElements(TestCollection<T> managed, out int numElements) => 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 = @"
[CustomMarshaller(typeof(TestCollection<>), Scenario.ManagedToUnmanagedIn, typeof(Marshaller<,>))]
static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement>
[CustomMarshaller(typeof(TestCollection<>), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller<,>))]
[ContiguousCollectionMarshaller]
static unsafe class Marshaller<T, TUnmanagedElement>
{
public static byte* AllocateContainerForUnmanagedElements(TestCollection<T> managed, out int numElements) => 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 = @"
[CustomMarshaller(typeof(TestCollection<>), Scenario.ManagedToUnmanagedIn, typeof(Marshaller<,>))]
static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement>
[CustomMarshaller(typeof(TestCollection<>), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller<,>))]
[ContiguousCollectionMarshaller]
static unsafe class Marshaller<T, TUnmanagedElement>
{
public const int BufferSize = 0x100;
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 = @"
[CustomMarshaller(typeof(TestCollection<>), Scenario.Default, typeof(Marshaller<,>))]
static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement>
[CustomMarshaller(typeof(TestCollection<>), MarshalMode.Default, typeof(Marshaller<,>))]
[ContiguousCollectionMarshaller]
static unsafe class Marshaller<T, TUnmanagedElement>
{
public static byte* AllocateContainerForUnmanagedElements(TestCollection<T> managed, out int numElements) => 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 = @"
[CustomMarshaller(typeof(TestCollection<>), Scenario.Default, typeof(Marshaller<,>.Ref.Nested))]
static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement>
[CustomMarshaller(typeof(TestCollection<>), MarshalMode.Default, typeof(Marshaller<,>.Ref.Nested))]
[ContiguousCollectionMarshaller]
static unsafe class Marshaller<T, TUnmanagedElement>
{
static class Nested
{
@ -1519,8 +1524,9 @@ static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement>
}
";
public const string Out = @"
[CustomMarshaller(typeof(TestCollection<>), Scenario.ManagedToUnmanagedOut, typeof(Marshaller<,>))]
static unsafe class Marshaller<T, [ElementUnmanagedType] TUnmanagedElement>
[CustomMarshaller(typeof(TestCollection<>), MarshalMode.ManagedToUnmanagedOut, typeof(Marshaller<,>))]
[ContiguousCollectionMarshaller]
static unsafe class Marshaller<T, TUnmanagedElement>
{
public static TestCollection<T> AllocateContainerForManagedElements(byte* unmanaged, int length) => 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<,,>))]
class TestCollection<T> {}
[CustomMarshaller(typeof(TestCollection<>), Scenario.Default, typeof(Marshaller<,,>))]
static unsafe class Marshaller<T, U, [ElementUnmanagedType] TUnmanagedElement>
[CustomMarshaller(typeof(TestCollection<>), MarshalMode.Default, typeof(Marshaller<,,>))]
[ContiguousCollectionMarshaller]
static unsafe class Marshaller<T, U, TUnmanagedElement>
{
public static byte* AllocateContainerForUnmanagedElements(TestCollection<T> managed, out int numElements) => 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.MarshalUsingParametersAndModifiers };
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.NativeToManagedGuaranteedOnlyReturnValue };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.NativeToManagedFinallyOnlyReturnValue };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.PinByValueInParameter };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.StackallocByValueInParameter };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.StackallocParametersAndModifiersNoRef };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateless.OptionalStackallocParametersAndModifiers };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.ParametersAndModifiers };
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.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.NativeToManagedGuaranteedOnlyReturnValue };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.NativeToManagedFinallyOnlyReturnValue };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.StackallocByValueInParameter };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.PinByValueInParameter };
yield return new[] { CodeSnippets.CustomStructMarshalling.Stateful.MarshallerPinByValueInParameter };

View file

@ -20,9 +20,9 @@ namespace SharedTypes
public string str2;
}
[CustomMarshaller(typeof(StringContainer), Scenario.ManagedToUnmanagedIn, typeof(In))]
[CustomMarshaller(typeof(StringContainer), Scenario.ManagedToUnmanagedRef, typeof(Ref))]
[CustomMarshaller(typeof(StringContainer), Scenario.ManagedToUnmanagedOut, typeof(Out))]
[CustomMarshaller(typeof(StringContainer), MarshalMode.ManagedToUnmanagedIn, typeof(In))]
[CustomMarshaller(typeof(StringContainer), MarshalMode.ManagedToUnmanagedRef, typeof(Ref))]
[CustomMarshaller(typeof(StringContainer), MarshalMode.ManagedToUnmanagedOut, typeof(Out))]
public static class StringContainerMarshaller
{
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 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 long ConvertToUnmanaged(double managed)
@ -106,7 +106,7 @@ namespace SharedTypes
public bool b3;
}
[CustomMarshaller(typeof(BoolStruct), Scenario.Default, typeof(BoolStructMarshaller))]
[CustomMarshaller(typeof(BoolStruct), MarshalMode.Default, typeof(BoolStructMarshaller))]
public static class BoolStructMarshaller
{
public struct BoolStructNative
@ -145,7 +145,7 @@ namespace SharedTypes
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 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 struct Marshaller
@ -205,7 +205,7 @@ namespace SharedTypes
public int i;
}
[CustomMarshaller(typeof(IntWrapperWithoutGetPinnableReference), Scenario.Default, typeof(IntWrapperWithoutGetPinnableReferenceMarshaller))]
[CustomMarshaller(typeof(IntWrapperWithoutGetPinnableReference), MarshalMode.Default, typeof(IntWrapperWithoutGetPinnableReferenceMarshaller))]
public static unsafe class IntWrapperWithoutGetPinnableReferenceMarshaller
{
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 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 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 struct Marshaller
@ -296,11 +296,11 @@ namespace SharedTypes
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 struct BoolStructNative
@ -339,8 +339,9 @@ namespace SharedTypes
}
}
[CustomMarshaller(typeof(List<>), Scenario.Default, typeof(ListMarshaller<,>))]
public unsafe static class ListMarshaller<T, [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged
[CustomMarshaller(typeof(List<>), MarshalMode.Default, typeof(ListMarshaller<,>))]
[ContiguousCollectionMarshaller]
public unsafe static class ListMarshaller<T, TUnmanagedElement> where TUnmanagedElement : unmanaged
{
public static byte* AllocateContainerForUnmanagedElements(List<T> managed, out int numElements)
=> AllocateContainerForUnmanagedElements(managed, Span<byte>.Empty, out numElements);
@ -397,8 +398,9 @@ namespace SharedTypes
=> Marshal.FreeCoTaskMem((IntPtr)unmanaged);
}
[CustomMarshaller(typeof(List<>), Scenario.Default, typeof(ListMarshallerWithPinning<,>))]
public unsafe static class ListMarshallerWithPinning<T, [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged
[CustomMarshaller(typeof(List<>), MarshalMode.Default, typeof(ListMarshallerWithPinning<,>))]
[ContiguousCollectionMarshaller]
public unsafe static class ListMarshallerWithPinning<T, TUnmanagedElement> where TUnmanagedElement : unmanaged
{
public static byte* AllocateContainerForUnmanagedElements(List<T> managed, out int numElements)
=> AllocateContainerForUnmanagedElements(managed, Span<byte>.Empty, out numElements);
@ -464,8 +466,9 @@ namespace SharedTypes
}
}
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), Scenario.Default, typeof(CustomArrayMarshaller<,>))]
public unsafe static class CustomArrayMarshaller<T, [ElementUnmanagedType] TUnmanagedElement> where TUnmanagedElement : unmanaged
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.Default, typeof(CustomArrayMarshaller<,>))]
[ContiguousCollectionMarshaller]
public unsafe static class CustomArrayMarshaller<T, TUnmanagedElement> where TUnmanagedElement : unmanaged
{
public static byte* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements)
{