From c99b5b067cf438a9b718f432876fe3e7b095b889 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 6 Jul 2022 09:35:51 -0700 Subject: [PATCH] Update design and expose new attributes for the CustomTypeMarshaller support (#71682) --- .editorconfig | 3 - .../UserTypeMarshallingV2.md | 268 +++++++++--------- eng/generators.targets | 2 - .../Common/src/Interop/Interop.Ldap.cs | 2 +- .../CryptUI/Interop.CryptUIDlgCertificate.cs | 4 +- .../Windows/WinHttp/Interop.winhttp.cs | 2 +- .../Windows/WinHttp/Interop.winhttp_types.cs | 2 +- .../WinMm/Interop.waveOutGetDevCaps.cs | 2 +- .../Windows/WinSock/Interop.WinsockBSD.cs | 2 +- .../Diagnostics/Reader/UnsafeNativeMethods.cs | 2 +- .../src/Interop/Windows/Interop.Gdi32.cs | 2 +- .../System.Private.CoreLib.Shared.projitems | 2 + .../Marshalling/CustomMarshallerAttribute.cs | 48 ++++ .../Marshalling/MarshalMode.cs} | 15 +- .../Analyzers/CustomTypeMarshallerAnalyzer.cs | 7 + .../LibraryImportGenerator.cs | 4 +- .../ManualTypeMarshallingHelper.cs | 66 ++--- .../MarshallerShape.cs | 62 ++-- ...ributedMarshallingModelGeneratorFactory.cs | 18 +- .../ICustomTypeMarshallingStrategy.cs | 14 +- .../MarshallingAttributeInfo.cs | 2 +- .../Microsoft.Interop.SourceGeneration.csproj | 4 +- .../TypeNames.cs | 2 +- .../ref/System.Runtime.InteropServices.cs | 26 ++ ...ContiguousCollectionMarshallerAttribute.cs | 13 + .../CustomMarshallerAttribute.cs | 35 --- .../ElementUnmanagedTypeAttribute.cs | 17 -- .../CustomMarshallingTests.cs | 18 +- .../CodeSnippets.cs | 99 ++++--- .../Compiles.cs | 10 +- .../TestAssets/SharedTypes/NonBlittable.cs | 43 +-- 31 files changed, 415 insertions(+), 381 deletions(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/CustomMarshallerAttribute.cs rename src/libraries/{System.Runtime.InteropServices/tests/Ancillary.Interop/Scenario.cs => System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/MarshalMode.cs} (81%) create mode 100644 src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ContiguousCollectionMarshallerAttribute.cs delete mode 100644 src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/CustomMarshallerAttribute.cs delete mode 100644 src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ElementUnmanagedTypeAttribute.cs diff --git a/.editorconfig b/.editorconfig index 598d07adf41..15658bab8d0 100644 --- a/.editorconfig +++ b/.editorconfig @@ -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 diff --git a/docs/design/libraries/LibraryImportGenerator/UserTypeMarshallingV2.md b/docs/design/libraries/LibraryImportGenerator/UserTypeMarshallingV2.md index ee1da9ff467..c1306a55da5 100644 --- a/docs/design/libraries/LibraryImportGenerator/UserTypeMarshallingV2.md +++ b/docs/design/libraries/LibraryImportGenerator/UserTypeMarshallingV2.md @@ -97,114 +97,94 @@ namespace System.Runtime.InteropServices.Marshalling; - Ref = In | Out, - } ++ ++ + /// -+ /// Define features for a custom type marshaller. ++ /// An enumeration representing the different marshalling scenarios in our marshalling model. + /// -+ [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class)] -+ public sealed class CustomTypeMarshallerFeaturesAttribute : Attribute ++ public enum MarshalMode + { + /// -+ /// 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. + /// -+ public int BufferSize { get; set; } ++ Default, ++ /// ++ /// By-value and in parameters in managed-to-unmanaged scenarios, like P/Invoke. ++ /// ++ ManagedToUnmanagedIn, ++ /// ++ /// ref parameters in managed-to-unmanaged scenarios, like P/Invoke. ++ /// ++ ManagedToUnmanagedRef, ++ /// ++ /// out parameters in managed-to-unmanaged scenarios, like P/Invoke. ++ /// ++ ManagedToUnmanagedOut, ++ /// ++ /// By-value and in parameters in unmanaged-to-managed scenarios, like Reverse P/Invoke. ++ /// ++ UnmanagedToManagedIn, ++ /// ++ /// ref parameters in unmanaged-to-managed scenarios, like Reverse P/Invoke. ++ /// ++ UnmanagedToManagedRef, ++ /// ++ /// out parameters in unmanaged-to-managed scenarios, like Reverse P/Invoke. ++ /// ++ UnmanagedToManagedOut, ++ /// ++ /// Elements of arrays passed with in or by-value in interop scenarios. ++ /// ++ ElementIn, ++ /// ++ /// Elements of arrays passed with ref or passed by-value with both and in interop scenarios. ++ /// ++ ElementRef, ++ /// ++ /// Elements of arrays passed with out or passed by-value with only in interop scenarios. ++ /// ++ ElementOut + } + -+ + /// -+ /// Base class attribute for custom marshaller attributes. ++ /// Attribute to indicate an entry point type for defining a marshaller. + /// -+ /// -+ /// 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. -+ /// -+ public abstract class CustomUnmanagedTypeMarshallersAttributeBase : Attribute ++ [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true)] ++ public sealed class CustomMarshallerAttribute : Attribute + { + /// ++ /// Create a instance. ++ /// ++ /// Managed type to marshal. ++ /// Marshalling mode. ++ /// Type used for marshalling. ++ 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; } ++ ++ /// + /// Placeholder type for generic parameter + /// -+ public sealed class GenericPlaceholder { } ++ public struct GenericPlaceholder ++ { ++ } + } + + /// -+ /// 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. + /// -+ [AttributeUsage(AttributeTargets.Class)] -+ public sealed class ManagedToUnmanagedMarshallersAttribute : CustomUnmanagedTypeMarshallersAttributeBase -+ { -+ /// -+ /// Create instance of . -+ /// -+ /// Managed type to marshal -+ public ManagedToUnmanagedMarshallersAttribute(Type managedType) { } -+ -+ /// -+ /// Marshaller to use when a parameter of the managed type is passed by-value or with the in keyword. -+ /// -+ public Type? InMarshaller { get; set; } -+ -+ /// -+ /// Marshaller to use when a parameter of the managed type is passed by-value or with the ref keyword. -+ /// -+ public Type? RefMarshaller { get; set; } -+ -+ /// -+ /// Marshaller to use when a parameter of the managed type is passed by-value or with the out keyword. -+ /// -+ public Type? OutMarshaller { get; set; } -+ } -+ -+ /// -+ /// Specify marshallers used in the unmanaged to managed direction (that is, Reverse P/Invoke) -+ /// -+ [AttributeUsage(AttributeTargets.Class)] -+ public sealed class UnmanagedToManagedMarshallersAttribute : CustomUnmanagedTypeMarshallersAttributeBase -+ { -+ /// -+ /// Create instance of . -+ /// -+ /// Managed type to marshal -+ public UnmanagedToManagedMarshallersAttribute(Type managedType) { } -+ -+ /// -+ /// Marshaller to use when a parameter of the managed type is passed by-value or with the in keyword. -+ /// -+ public Type? InMarshaller { get; set; } -+ -+ /// -+ /// Marshaller to use when a parameter of the managed type is passed by-value or with the ref keyword. -+ /// -+ public Type? RefMarshaller { get; set; } -+ -+ /// -+ /// Marshaller to use when a parameter of the managed type is passed by-value or with the out keyword. -+ /// -+ public Type? OutMarshaller { get; set; } -+ } -+ -+ /// -+ /// Specify marshaller for array-element marshalling and default struct field marshalling. -+ /// -+ [AttributeUsage(AttributeTargets.Class)] -+ public sealed class ElementMarshallerAttribute : CustomUnmanagedTypeMarshallersAttributeBase -+ { -+ /// -+ /// Create instance of . -+ /// -+ /// Managed type to marshal -+ /// Marshaller type to use for marshalling . -+ public ElementMarshallerAttribute(Type managedType, Type elementMarshaller) { } -+ } -+ -+ /// -+ /// Specifies that a particular generic parameter is the collection element's unmanaged type. -+ /// -+ /// -+ /// If this attribute is provided on a generic parameter of a marshaller, then the generator will assume -+ /// that it is a linear collection marshaller. -+ /// -+ [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 { - [CustomTypeMarshallerFeatures(BufferSize = 0x200)] public static class ManagedToNative { + public static int BufferSize { get; } public static TNative ConvertToUnmanaged(TManaged managed, Span callerAllocatedBuffer); // Can throw exceptions public static void Free(TNative unmanaged); // Optional. Should not throw exceptions @@ -294,7 +274,7 @@ static class TMarshaller ### 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 { 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 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 { - [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 buffer); // Can throw exceptions. @@ -376,7 +356,7 @@ static class TMarshaller 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 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 } ``` -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 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 where TUnmanagedElement : unmanaged { public static class ManagedToNative { @@ -487,13 +469,14 @@ static class TMarshaller 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 where TUnmanagedElement : unmanaged +[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))] +[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ElementIn, typeof(ManagedToNative))] +[ContiguousCollectionMarshaller] +static class TMarshaller where TUnmanagedElement : unmanaged { - [CustomTypeMarshallerFeatures(BufferSize = 0x200)] public static class ManagedToNative { + public static int BufferSize { get; } public static TNative AllocateContainerForUnmanagedElements(TCollection managed, Span buffer, out int numElements); // Can throw exceptions public static ReadOnlySpan GetManagedValuesSource(TCollection managed); // Can throw exceptions @@ -511,9 +494,11 @@ static class TMarshaller w ### Stateless Unmanaged->Managed ```csharp -[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(NativeToManaged))] -[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(NativeToManaged))] -static class TMarshaller 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 where TUnmanagedElement : unmanaged { public static class NativeToManaged { @@ -531,16 +516,16 @@ static class TMarshaller 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 where TUnmanagedElement : unmanaged +[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))] +[ContiguousCollectionMarshaller] +static class TMarshaller 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 GetManagedValuesDestination(T[] managed) => managed; // Can throw exceptions @@ -554,10 +539,11 @@ static class TMarshaller w ### Stateless Bidirectional ```csharp -[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), RefMarshaller = typeof(Bidirectional))] -[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), RefMarshaller = typeof(Bidirectional))] -[ElementMarshaller(typeof(TManaged<,,,...>), typeof(Bidirectional))] -static class TMarshaller 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 where TUnmanagedElement : unmanaged { public static class Bidirectional { @@ -572,9 +558,10 @@ static class TMarshaller w ### Stateful Managed->Unmanaged ```csharp -[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(ManagedToNative))] -[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(ManagedToNative))] -static class TMarshaller where TUnmanagedElement : unmanaged +[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))] +[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.UnmanagedToManagedOut, typeof(ManagedToNative))] +[ContiguousCollectionMarshaller] +static class TMarshaller where TUnmanagedElement : unmanaged { public struct ManagedToNative // Can be ref struct { @@ -592,7 +579,7 @@ static class TMarshaller 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 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 where TUnmanagedElement : unmanaged +[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedToNative))] +[ContiguousCollectionMarshaller] +static class TMarshaller 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 buffer); // Can throw exceptions. @@ -623,7 +611,7 @@ static class TMarshaller 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 w ### Stateful Unmanaged->Managed ```csharp -[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(NativeToManaged))] -[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(NativeToManaged))] -static class TMarshaller where TUnmanagedElement : unmanaged +[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))] +[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.UnmanagedToManagedIn, typeof(NativeToManaged))] +[ContiguousCollectionMarshaller] +static class TMarshaller where TUnmanagedElement : unmanaged { public struct NativeToManaged // Can be ref struct { @@ -657,9 +646,9 @@ static class TMarshaller w ### Stateful Unmanaged->Managed with Guaranteed Unmarshalling ```csharp -[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), OutMarshaller = typeof(NativeToManaged))] -[UnmanagedToManagedMarshallers(typeof(TCollection<,,,...>), InMarshaller = typeof(NativeToManaged))] -static class TMarshaller where TUnmanagedElement : unmanaged +[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedOut, typeof(NativeToManaged))] +[ContiguousCollectionMarshaller] +static class TMarshaller where TUnmanagedElement : unmanaged { public struct NativeToManaged // Can be ref struct { @@ -671,7 +660,7 @@ static class TMarshaller w public Span 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 w ### Stateful Bidirectional ```csharp -[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), RefMarshaller = typeof(Bidirectional))] -[ManagedToUnmanagedMarshallers(typeof(TCollection<,,,...>), RefMarshaller = typeof(Bidirectional))] -static class TMarshaller where TUnmanagedElement : unmanaged +[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.ManagedToUnmanagedRef, typeof(Bidirectional))] +[CustomMarshaller(typeof(TCollection<,,,...>), MarshalMode.UnmanagedToManagedRef, typeof(Bidirectional))] +[ContiguousCollectionMarshaller] +static class TMarshaller 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. diff --git a/eng/generators.targets b/eng/generators.targets index cc04480a7ff..ac01adc5cc4 100644 --- a/eng/generators.targets +++ b/eng/generators.targets @@ -69,8 +69,6 @@ - - diff --git a/src/libraries/Common/src/Interop/Interop.Ldap.cs b/src/libraries/Common/src/Interop/Interop.Ldap.cs index cc830f8da21..b313fb36b05 100644 --- a/src/libraries/Common/src/Interop/Interop.Ldap.cs +++ b/src/libraries/Common/src/Interop/Interop.Ldap.cs @@ -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) diff --git a/src/libraries/Common/src/Interop/Windows/CryptUI/Interop.CryptUIDlgCertificate.cs b/src/libraries/Common/src/Interop/Windows/CryptUI/Interop.CryptUIDlgCertificate.cs index 8342b5c405a..e58a0b497dc 100644 --- a/src/libraries/Common/src/Interop/Windows/CryptUI/Interop.CryptUIDlgCertificate.cs +++ b/src/libraries/Common/src/Interop/Windows/CryptUI/Interop.CryptUIDlgCertificate.cs @@ -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); diff --git a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs index 14306c82e36..ad97442aced 100644 --- a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs +++ b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs @@ -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) diff --git a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs index fe86bda7758..1cbdfa79d59 100644 --- a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs +++ b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs @@ -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); diff --git a/src/libraries/Common/src/Interop/Windows/WinMm/Interop.waveOutGetDevCaps.cs b/src/libraries/Common/src/Interop/Windows/WinMm/Interop.waveOutGetDevCaps.cs index 34c29cf3173..3c3e831fac9 100644 --- a/src/libraries/Common/src/Interop/Windows/WinMm/Interop.waveOutGetDevCaps.cs +++ b/src/libraries/Common/src/Interop/Windows/WinMm/Interop.waveOutGetDevCaps.cs @@ -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); diff --git a/src/libraries/Common/src/Interop/Windows/WinSock/Interop.WinsockBSD.cs b/src/libraries/Common/src/Interop/Windows/WinSock/Interop.WinsockBSD.cs index 54bb6149a02..0633d7ab896 100644 --- a/src/libraries/Common/src/Interop/Windows/WinSock/Interop.WinsockBSD.cs +++ b/src/libraries/Common/src/Interop/Windows/WinSock/Interop.WinsockBSD.cs @@ -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); diff --git a/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/UnsafeNativeMethods.cs b/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/UnsafeNativeMethods.cs index 49015a133a3..f3aca7e7595 100644 --- a/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/UnsafeNativeMethods.cs +++ b/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/UnsafeNativeMethods.cs @@ -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); diff --git a/src/libraries/System.Drawing.Common/src/Interop/Windows/Interop.Gdi32.cs b/src/libraries/System.Drawing.Common/src/Interop/Windows/Interop.Gdi32.cs index 140356c7967..8b754d321fa 100644 --- a/src/libraries/System.Drawing.Common/src/Interop/Windows/Interop.Gdi32.cs +++ b/src/libraries/System.Drawing.Common/src/Interop/Windows/Interop.Gdi32.cs @@ -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); diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index a079ceb5f11..d978ef0b8c4 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -872,10 +872,12 @@ + + diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/CustomMarshallerAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/CustomMarshallerAttribute.cs new file mode 100644 index 00000000000..a19740e2983 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/CustomMarshallerAttribute.cs @@ -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 +{ + /// + /// Attribute to indicate an entry point type for defining a marshaller. + /// + [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true)] + public sealed class CustomMarshallerAttribute : Attribute + { + /// + /// Create a instance. + /// + /// Managed type to marshal. + /// The marshalling mode this attribute applies to. + /// Type used for marshalling. + public CustomMarshallerAttribute(Type managedType, MarshalMode marshalMode, Type marshallerType) + { + ManagedType = managedType; + MarshalMode = marshalMode; + MarshallerType = marshallerType; + } + + /// + /// The managed type to marshal. + /// + public Type ManagedType { get; } + + /// + /// The marshalling mode this attribute applies to. + /// + public MarshalMode MarshalMode { get; } + + /// + /// Type used for marshalling. + /// + public Type MarshallerType { get; } + + /// + /// Placeholder type for generic parameter + /// + public struct GenericPlaceholder + { + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/Scenario.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/MarshalMode.cs similarity index 81% rename from src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/Scenario.cs rename to src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/MarshalMode.cs index 485d2418706..5d7a79756e2 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/Scenario.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/MarshalMode.cs @@ -4,22 +4,17 @@ #if MICROSOFT_INTEROP_SOURCEGENERATION namespace Microsoft.Interop #else -namespace System.Runtime.InteropServices +namespace System.Runtime.InteropServices.Marshalling #endif { /// - /// An enumeration representing the different marshalling scenarios in our marshalling model. + /// An enumeration representing the different marshalling modes in our marshalling model. /// -#if LIBRARYIMPORT_GENERATOR_TEST || MICROSOFT_INTEROP_SOURCEGENERATION - public -#else - internal -#endif - enum Scenario + public enum MarshalMode { /// - /// 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. /// Default, /// diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerAnalyzer.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerAnalyzer.cs index 6b6e1e1589a..8e380eeba24 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerAnalyzer.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerAnalyzer.cs @@ -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, diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs index c262c2e0017..e32ccc145f6 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.cs @@ -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); } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs index 2f45d23393e..568fc4ff111 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs @@ -24,32 +24,32 @@ namespace Microsoft.Interop MarshallingInfo? CollectionElementMarshallingInfo); public readonly record struct CustomTypeMarshallers( - ImmutableDictionary Scenarios) + ImmutableDictionary 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 scenarios = new(); + Dictionary 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) { diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallerShape.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallerShape.cs index ec37715128b..aa22bcff19f 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallerShape.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallerShape.cs @@ -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() .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() .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() .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() .FirstOrDefault(m => m is { IsStatic: false, Parameters.Length: 0, ReturnsVoid: true }); } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs index 57dc764ba0b..c7117f002f9 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs @@ -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) { diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomTypeMarshallingStrategy.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomTypeMarshallingStrategy.cs index 048c89867d0..210fc4bf25e 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomTypeMarshallingStrategy.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ICustomTypeMarshallingStrategy.cs @@ -74,7 +74,7 @@ namespace Microsoft.Interop (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info); - // = .ConvertToManagedGuaranteed(); + // = .ConvertToManagedFinally(); 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); - // = .ToManagedGuaranteed(); + // = .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 GenerateNotifyForSuccessfulInvokeStatements(TypePositionInfo info, StubCodeContext context) { - if (!_shape.HasFlag(MarshallerShape.NotifyInvokeSucceeded)) + if (!_shape.HasFlag(MarshallerShape.OnInvoked)) yield break; - // .NotifyInvokeSucceeded(); + // .OnInvoked(); yield return ExpressionStatement( InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(context.GetAdditionalIdentifier(info, MarshallerIdentifier)), - IdentifierName(ShapeMemberNames.Value.Stateful.NotifyInvokeSucceeded)), + IdentifierName(ShapeMemberNames.Value.Stateful.OnInvoked)), ArgumentList())); } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs index 7269e4f444c..d3987fba7ec 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs @@ -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()); diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj index e3325f0935a..02621feb273 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj @@ -17,8 +17,8 @@ Link="Production\CustomTypeMarshallerFeatures.cs" /> - + diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs index 5428b971559..f0a96eb7c49 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs @@ -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"; diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index 0a3c15e1955..bbc7222170a 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -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 { diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ContiguousCollectionMarshallerAttribute.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ContiguousCollectionMarshallerAttribute.cs new file mode 100644 index 00000000000..2261b4279d3 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ContiguousCollectionMarshallerAttribute.cs @@ -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 +{ + /// + /// Specifies that this marshaller entry-point type is a contiguous collection marshaller. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] + public sealed class ContiguousCollectionMarshallerAttribute : Attribute + { + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/CustomMarshallerAttribute.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/CustomMarshallerAttribute.cs deleted file mode 100644 index 55abce124ab..00000000000 --- a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/CustomMarshallerAttribute.cs +++ /dev/null @@ -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 -{ - /// - /// Attribute to indicate an entry point type for defining a marshaller. - /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -#if LIBRARYIMPORT_GENERATOR_TEST - public -#else - internal -#endif - sealed class CustomMarshallerAttribute : Attribute - { - /// - /// Create a instance. - /// - /// Managed type to marshal. - /// Marshalling scenario. - /// Type used for marshalling. - public CustomMarshallerAttribute(Type managedType, Scenario scenario, Type marshallerType) { } - - /// - /// Placeholder type for generic parameter - /// - public struct GenericPlaceholder - { - } - } -} diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ElementUnmanagedTypeAttribute.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ElementUnmanagedTypeAttribute.cs deleted file mode 100644 index d0f508904a1..00000000000 --- a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ElementUnmanagedTypeAttribute.cs +++ /dev/null @@ -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 -{ - /// - /// Specifies that a particular generic parameter is the collection element's unmanaged type. - /// - /// - /// If this attribute is provided on a generic parameter of a marshaller, then the generator will assume - /// that it is a linear collection marshaller. - /// - [AttributeUsage(AttributeTargets.GenericParameter)] - public sealed class ElementUnmanagedTypeAttribute : Attribute - { - } -} diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.cs index c21a7d918f7..5e9a86c4a27 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.cs @@ -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(() => 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; diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs index 06e64cb4332..690b14742d8 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs @@ -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 +[CustomMarshaller(typeof(TestCollection<>), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller<,>))] +[ContiguousCollectionMarshaller] +static unsafe class Marshaller { public static byte* AllocateContainerForUnmanagedElements(TestCollection managed, out int numElements) => throw null; public static System.ReadOnlySpan GetManagedValuesSource(TestCollection managed) => throw null; @@ -1466,8 +1467,9 @@ static unsafe class Marshaller } "; public const string InPinnable = @" -[CustomMarshaller(typeof(TestCollection<>), Scenario.ManagedToUnmanagedIn, typeof(Marshaller<,>))] -static unsafe class Marshaller +[CustomMarshaller(typeof(TestCollection<>), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller<,>))] +[ContiguousCollectionMarshaller] +static unsafe class Marshaller { public static byte* AllocateContainerForUnmanagedElements(TestCollection managed, out int numElements) => throw null; public static System.ReadOnlySpan GetManagedValuesSource(TestCollection managed) => throw null; @@ -1477,8 +1479,9 @@ static unsafe class Marshaller } "; public const string InBuffer = @" -[CustomMarshaller(typeof(TestCollection<>), Scenario.ManagedToUnmanagedIn, typeof(Marshaller<,>))] -static unsafe class Marshaller +[CustomMarshaller(typeof(TestCollection<>), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller<,>))] +[ContiguousCollectionMarshaller] +static unsafe class Marshaller { public const int BufferSize = 0x100; public static byte* AllocateContainerForUnmanagedElements(TestCollection managed, System.Span buffer, out int numElements) => throw null; @@ -1487,8 +1490,9 @@ static unsafe class Marshaller } "; public const string Ref = @" -[CustomMarshaller(typeof(TestCollection<>), Scenario.Default, typeof(Marshaller<,>))] -static unsafe class Marshaller +[CustomMarshaller(typeof(TestCollection<>), MarshalMode.Default, typeof(Marshaller<,>))] +[ContiguousCollectionMarshaller] +static unsafe class Marshaller { public static byte* AllocateContainerForUnmanagedElements(TestCollection managed, out int numElements) => throw null; public static System.ReadOnlySpan GetManagedValuesSource(TestCollection managed) => throw null; @@ -1500,8 +1504,9 @@ static unsafe class Marshaller } "; public const string RefNested = @" -[CustomMarshaller(typeof(TestCollection<>), Scenario.Default, typeof(Marshaller<,>.Ref.Nested))] -static unsafe class Marshaller +[CustomMarshaller(typeof(TestCollection<>), MarshalMode.Default, typeof(Marshaller<,>.Ref.Nested))] +[ContiguousCollectionMarshaller] +static unsafe class Marshaller { static class Nested { @@ -1519,8 +1524,9 @@ static unsafe class Marshaller } "; public const string Out = @" -[CustomMarshaller(typeof(TestCollection<>), Scenario.ManagedToUnmanagedOut, typeof(Marshaller<,>))] -static unsafe class Marshaller +[CustomMarshaller(typeof(TestCollection<>), MarshalMode.ManagedToUnmanagedOut, typeof(Marshaller<,>))] +[ContiguousCollectionMarshaller] +static unsafe class Marshaller { public static TestCollection AllocateContainerForManagedElements(byte* unmanaged, int length) => throw null; public static System.Span GetManagedValuesDestination(TestCollection managed) => throw null; @@ -1577,8 +1583,9 @@ static unsafe class Marshaller [NativeMarshalling(typeof(Marshaller<,,>))] class TestCollection {} -[CustomMarshaller(typeof(TestCollection<>), Scenario.Default, typeof(Marshaller<,,>))] -static unsafe class Marshaller +[CustomMarshaller(typeof(TestCollection<>), MarshalMode.Default, typeof(Marshaller<,,>))] +[ContiguousCollectionMarshaller] +static unsafe class Marshaller { public static byte* AllocateContainerForUnmanagedElements(TestCollection managed, out int numElements) => throw null; public static System.ReadOnlySpan GetManagedValuesSource(TestCollection managed) => throw null; diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs index 21ebc41f7ea..2c78a8d2d57 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs @@ -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 }; diff --git a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs index 62065e639a7..85795088934 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs @@ -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 where TUnmanagedElement : unmanaged + [CustomMarshaller(typeof(List<>), MarshalMode.Default, typeof(ListMarshaller<,>))] + [ContiguousCollectionMarshaller] + public unsafe static class ListMarshaller where TUnmanagedElement : unmanaged { public static byte* AllocateContainerForUnmanagedElements(List managed, out int numElements) => AllocateContainerForUnmanagedElements(managed, Span.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 where TUnmanagedElement : unmanaged + [CustomMarshaller(typeof(List<>), MarshalMode.Default, typeof(ListMarshallerWithPinning<,>))] + [ContiguousCollectionMarshaller] + public unsafe static class ListMarshallerWithPinning where TUnmanagedElement : unmanaged { public static byte* AllocateContainerForUnmanagedElements(List managed, out int numElements) => AllocateContainerForUnmanagedElements(managed, Span.Empty, out numElements); @@ -464,8 +466,9 @@ namespace SharedTypes } } - [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), Scenario.Default, typeof(CustomArrayMarshaller<,>))] - public unsafe static class CustomArrayMarshaller where TUnmanagedElement : unmanaged + [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.Default, typeof(CustomArrayMarshaller<,>))] + [ContiguousCollectionMarshaller] + public unsafe static class CustomArrayMarshaller where TUnmanagedElement : unmanaged { public static byte* AllocateContainerForUnmanagedElements(T[]? managed, out int numElements) {