Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--eng/generators.targets4
-rw-r--r--src/libraries/Common/src/Interop/Interop.Ldap.cs2
-rw-r--r--src/libraries/Common/src/Interop/Windows/CryptUI/Interop.CryptUIDlgCertificate.cs4
-rw-r--r--src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp.cs2
-rw-r--r--src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs2
-rw-r--r--src/libraries/Common/src/Interop/Windows/WinMm/Interop.waveOutGetDevCaps.cs2
-rw-r--r--src/libraries/Common/src/Interop/Windows/WinSock/Interop.WinsockBSD.cs3
-rw-r--r--src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/UnsafeNativeMethods.cs2
-rw-r--r--src/libraries/System.Drawing.Common/src/Interop/Windows/Interop.Gdi32.cs2
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerAnalyzer.cs42
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs203
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs24
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs4
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj4
-rw-r--r--src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs2
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/CustomMarshallerAttribute.cs35
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/CustomTypeMarshallersAttributeBase.cs26
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ManagedToUnmanagedMarshallersAttribute.cs38
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/Scenario.cs62
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.cs4
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs17
-rw-r--r--src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs15
22 files changed, 313 insertions, 186 deletions
diff --git a/eng/generators.targets b/eng/generators.targets
index 92c76103b17..cc04480a7ff 100644
--- a/eng/generators.targets
+++ b/eng/generators.targets
@@ -69,8 +69,8 @@
</PropertyGroup>
<ItemGroup Condition="'$(NetCoreAppCurrentTargetFrameworkMoniker)' == '$(TargetFrameworkMoniker)' and '$(IncludeLibraryImportGeneratorSources)' != 'false'">
- <Compile Include="$(LibrariesProjectRoot)System.Runtime.InteropServices/tests/Ancillary.Interop/CustomTypeMarshallersAttributeBase.cs" />
- <Compile Include="$(LibrariesProjectRoot)System.Runtime.InteropServices/tests/Ancillary.Interop/ManagedToUnmanagedMarshallersAttribute.cs" />
+ <Compile Include="$(LibrariesProjectRoot)System.Runtime.InteropServices/tests/Ancillary.Interop/CustomMarshallerAttribute.cs" />
+ <Compile Include="$(LibrariesProjectRoot)System.Runtime.InteropServices/tests/Ancillary.Interop/Scenario.cs" />
</ItemGroup>
</Target>
diff --git a/src/libraries/Common/src/Interop/Interop.Ldap.cs b/src/libraries/Common/src/Interop/Interop.Ldap.cs
index cce83e2111c..cc830f8da21 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
- [ManagedToUnmanagedMarshallers(typeof(SEC_WINNT_AUTH_IDENTITY_EX), InMarshaller = typeof(Marshaller))]
+ [CustomMarshaller(typeof(SEC_WINNT_AUTH_IDENTITY_EX), Scenario.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 23819aef230..8342b5c405a 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
- [ManagedToUnmanagedMarshallers(typeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW), InMarshaller = typeof(Marshaller), RefMarshaller = typeof(Marshaller), OutMarshaller = typeof(Marshaller))]
+ [CustomMarshaller(typeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW), Scenario.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
- [ManagedToUnmanagedMarshallers(typeof(CRYPTUI_SELECTCERTIFICATE_STRUCTW), InMarshaller = typeof(Marshaller), RefMarshaller = typeof(Marshaller), OutMarshaller = typeof(Marshaller))]
+ [CustomMarshaller(typeof(CRYPTUI_SELECTCERTIFICATE_STRUCTW), Scenario.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 a40773a564d..14306c82e36 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
- [ManagedToUnmanagedMarshallers(typeof(StringBuilder), InMarshaller = typeof(SimpleStringBufferMarshaller))]
+ [CustomMarshaller(typeof(StringBuilder), Scenario.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 f83448e81b1..fe86bda7758 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
- [ManagedToUnmanagedMarshallers(typeof(WINHTTP_AUTOPROXY_OPTIONS), InMarshaller = typeof(Marshaller), RefMarshaller = typeof(Marshaller), OutMarshaller = typeof(Marshaller))]
+ [CustomMarshaller(typeof(WINHTTP_AUTOPROXY_OPTIONS), Scenario.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 329a997c5e9..34c29cf3173 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
- [ManagedToUnmanagedMarshallers(typeof(WAVEOUTCAPS), InMarshaller = typeof(Marshaller), RefMarshaller = typeof(Marshaller), OutMarshaller = typeof(Marshaller))]
+ [CustomMarshaller(typeof(WAVEOUTCAPS), Scenario.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 2a8421a376e..54bb6149a02 100644
--- a/src/libraries/Common/src/Interop/Windows/WinSock/Interop.WinsockBSD.cs
+++ b/src/libraries/Common/src/Interop/Windows/WinSock/Interop.WinsockBSD.cs
@@ -74,7 +74,8 @@ internal static partial class Interop
{
internal byte[] MulticastAddress; // IP address of group.
internal int InterfaceIndex; // Local interface index.
- [ManagedToUnmanagedMarshallers(typeof(IPv6MulticastRequest), InMarshaller = typeof(Marshaller), RefMarshaller = typeof(Marshaller), OutMarshaller = typeof(Marshaller))]
+
+ [CustomMarshaller(typeof(IPv6MulticastRequest), Scenario.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 3c6a4f5e61b..49015a133a3 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
- [ManagedToUnmanagedMarshallers(typeof(EvtStringVariant), InMarshaller = typeof(Marshaller), RefMarshaller = typeof(Marshaller), OutMarshaller = typeof(Marshaller))]
+ [CustomMarshaller(typeof(EvtStringVariant), Scenario.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 08bd1c39710..140356c7967 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
- [ManagedToUnmanagedMarshallers(typeof(DOCINFO), InMarshaller = typeof(Marshaller))]
+ [CustomMarshaller(typeof(DOCINFO), Scenario.ManagedToUnmanagedIn, typeof(Marshaller))]
public static class Marshaller
{
public static Native ConvertToUnmanaged(DOCINFO managed) => new(managed);
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 dfc4139263d..6b6e1e1589a 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerAnalyzer.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/Analyzers/CustomTypeMarshallerAnalyzer.cs
@@ -405,7 +405,7 @@ namespace Microsoft.Interop.Analyzers
// Analyze NativeMarshalling/MarshalUsing for correctness
context.RegisterSymbolAction(PerCompilationAnalyzer.AnalyzeTypeDefinition, SymbolKind.NamedType);
- context.RegisterSymbolAction(PerCompilationAnalyzer.AnalyzeElement, SymbolKind.Parameter, SymbolKind.Field);
+ context.RegisterSymbolAction(PerCompilationAnalyzer.AnalyzeParameterOrField, SymbolKind.Parameter, SymbolKind.Field);
context.RegisterSymbolAction(PerCompilationAnalyzer.AnalyzeReturnType, SymbolKind.Method);
// Analyze marshaller type to validate shape.
@@ -431,18 +431,16 @@ namespace Microsoft.Interop.Analyzers
public static void AnalyzeTypeDefinition(SymbolAnalysisContext context)
{
INamedTypeSymbol type = (INamedTypeSymbol)context.Symbol;
-
- (AttributeData? attributeData, INamedTypeSymbol? marshallerType) = ManualTypeMarshallingHelper.GetDefaultMarshallerInfo(type);
-
+ (AttributeData? attributeData, INamedTypeSymbol? entryType) = ManualTypeMarshallingHelper.GetDefaultMarshallerEntryType(type);
if (attributeData is null)
{
return;
}
- AnalyzeManagedTypeMarshallingInfo(context, type, attributeData, marshallerType);
+ AnalyzeManagedTypeMarshallingInfo(context, type, attributeData, entryType);
}
- public static void AnalyzeElement(SymbolAnalysisContext context)
+ public static void AnalyzeParameterOrField(SymbolAnalysisContext context)
{
ITypeSymbol managedType = context.Symbol switch
{
@@ -455,6 +453,7 @@ namespace Microsoft.Interop.Analyzers
{
return;
}
+
AnalyzeManagedTypeMarshallingInfo(context, managedType, attributeData, attributeData.ConstructorArguments[0].Value as INamedTypeSymbol);
}
@@ -467,39 +466,44 @@ namespace Microsoft.Interop.Analyzers
{
return;
}
+
AnalyzeManagedTypeMarshallingInfo(context, managedType, attributeData, attributeData.ConstructorArguments[0].Value as INamedTypeSymbol);
}
- private static void AnalyzeManagedTypeMarshallingInfo(SymbolAnalysisContext context, ITypeSymbol type, AttributeData attributeData, INamedTypeSymbol? marshallerType)
+ private static void AnalyzeManagedTypeMarshallingInfo(
+ SymbolAnalysisContext context,
+ ITypeSymbol managedType,
+ AttributeData attributeData,
+ INamedTypeSymbol? entryType)
{
- if (marshallerType is null)
+ if (entryType is null)
{
context.ReportDiagnostic(
attributeData.CreateDiagnostic(
NativeTypeMustHaveCustomTypeMarshallerAttributeRule,
- type.ToDisplayString()));
+ managedType.ToDisplayString()));
return;
}
- if (marshallerType.IsUnboundGenericType)
+ if (entryType.IsUnboundGenericType)
{
context.ReportDiagnostic(
attributeData.CreateDiagnostic(
NativeGenericTypeMustBeClosedOrMatchArityRule,
- marshallerType.ToDisplayString(),
- type.ToDisplayString()));
+ entryType.ToDisplayString(),
+ managedType.ToDisplayString()));
}
- (bool hasCustomTypeMarshallerAttribute, ITypeSymbol? marshallerManagedType, _) = ManualTypeMarshallingHelper_V1.GetMarshallerShapeInfo(marshallerType);
+ (bool hasCustomTypeMarshallerAttribute, ITypeSymbol? marshallerManagedType, _) = ManualTypeMarshallingHelper_V1.GetMarshallerShapeInfo(entryType);
- marshallerManagedType = ManualTypeMarshallingHelper.ResolveManagedType(marshallerManagedType, marshallerType, context.Compilation);
+ marshallerManagedType = ManualTypeMarshallingHelper.ResolveManagedType(marshallerManagedType, entryType, context.Compilation);
if (!hasCustomTypeMarshallerAttribute)
{
context.ReportDiagnostic(
attributeData.CreateDiagnostic(
NativeTypeMustHaveCustomTypeMarshallerAttributeRule,
- type.ToDisplayString()));
+ managedType.ToDisplayString()));
return;
}
@@ -508,16 +512,16 @@ namespace Microsoft.Interop.Analyzers
context.ReportDiagnostic(
attributeData.CreateDiagnostic(
NativeTypeMustHaveCustomTypeMarshallerAttributeRule,
- type.ToDisplayString()));
+ managedType.ToDisplayString()));
return;
}
- if (!TypeSymbolsConstructedFromEqualTypes(type, marshallerManagedType))
+ if (!TypeSymbolsConstructedFromEqualTypes(managedType, marshallerManagedType))
{
context.ReportDiagnostic(
attributeData.CreateDiagnostic(
NativeTypeMustHaveCustomTypeMarshallerAttributeRule,
- type.ToDisplayString()));
+ managedType.ToDisplayString()));
return;
}
}
@@ -846,7 +850,7 @@ namespace Microsoft.Interop.Analyzers
type.ToDisplayString()));
}
- if (SymbolEqualityComparer.Default.Equals(ManualTypeMarshallingHelper.GetDefaultMarshallerInfo(type).marshallerType, marshallerType)
+ if (SymbolEqualityComparer.Default.Equals(ManualTypeMarshallingHelper.GetDefaultMarshallerEntryType(type).entryType, marshallerType)
&& ManualTypeMarshallingHelper.FindGetPinnableReference(type) is IMethodSymbol managedGetPinnableReferenceMethod)
{
if (!managedGetPinnableReferenceMethod.ReturnType.IsConsideredBlittable())
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 ca64749c523..6ec395354d2 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
@@ -4,7 +4,10 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Diagnostics;
using System.Linq;
+using System.Linq.Expressions;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis;
@@ -17,7 +20,35 @@ namespace Microsoft.Interop
bool IsStrictlyBlittable,
ManagedTypeInfo? BufferElementType);
- public readonly record struct CustomTypeMarshallers(CustomTypeMarshallerData? In, CustomTypeMarshallerData? Ref, CustomTypeMarshallerData? Out);
+ public readonly record struct CustomTypeMarshallers(
+ ImmutableDictionary<Scenario, CustomTypeMarshallerData> Scenarios)
+ {
+ public CustomTypeMarshallerData GetScenarioOrDefault(Scenario scenario)
+ {
+ CustomTypeMarshallerData data;
+ if (Scenarios.TryGetValue(scenario, out data))
+ return data;
+
+ if (Scenarios.TryGetValue(Scenario.Default, out data))
+ return data;
+
+ // TODO: Hard failure based on previous implementation
+ throw new InvalidOperationException();
+ }
+
+ public bool TryGetScenarioOrDefault(Scenario scenario, out CustomTypeMarshallerData data)
+ {
+ if (Scenarios.TryGetValue(scenario, out data))
+ return true;
+
+ return Scenarios.TryGetValue(Scenario.Default, out data);
+ }
+
+ public bool IsDefinedOrDefault(Scenario scenario)
+ {
+ return Scenarios.ContainsKey(scenario) || Scenarios.ContainsKey(Scenario.Default);
+ }
+ }
public static class ManualTypeMarshallingHelper
{
@@ -28,13 +59,6 @@ namespace Microsoft.Interop
public const string ConstantElementCount = nameof(ConstantElementCount);
}
- internal static class MarshallersProperties
- {
- public const string InMarshaller = nameof(InMarshaller);
- public const string RefMarshaller = nameof(RefMarshaller);
- public const string OutMarshaller = nameof(OutMarshaller);
- }
-
[Flags]
private enum MarshallingDirection
{
@@ -49,54 +73,120 @@ namespace Microsoft.Interop
return false;
}
- public static bool TryGetMarshallers(ITypeSymbol entryPointType, ITypeSymbol managedType, bool isLinearCollectionMarshalling, Compilation compilation, out CustomTypeMarshallers? marshallers)
+ public static bool TryGetMarshallersFromEntryType(
+ INamedTypeSymbol entryPointType,
+ ITypeSymbol managedType,
+ bool isLinearCollectionMarshalling,
+ Compilation compilation,
+ out CustomTypeMarshallers? marshallers)
{
marshallers = null;
- var attr = entryPointType.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.ToDisplayString() == TypeNames.ManagedToUnmanagedMarshallersAttribute);
- if (attr is null || attr.ConstructorArguments.Length == 0)
+ var attrs = entryPointType.GetAttributes().Where(attr => attr.AttributeClass.ToDisplayString() == TypeNames.CustomMarshallerAttribute).ToArray();
+ if (attrs is null || attrs.Length == 0)
return false;
- ITypeSymbol? managedTypeOnAttr = attr.ConstructorArguments[0].Value as ITypeSymbol;
- if (!SymbolEqualityComparer.Default.Equals(managedType, managedTypeOnAttr)
- && !compilation.HasImplicitConversion(managedType, managedTypeOnAttr))
- return false;
+ Dictionary<Scenario, CustomTypeMarshallerData> scenarios = new();
+ foreach (AttributeData attr in attrs)
+ {
+ Debug.Assert(attr.ConstructorArguments.Length == 3);
+
+ // Verify the defined marshaller is for the managed type.
+ ITypeSymbol? managedTypeOnAttr = attr.ConstructorArguments[0].Value as ITypeSymbol;
+ if (!SymbolEqualityComparer.Default.Equals(managedType, managedTypeOnAttr)
+ && !compilation.HasImplicitConversion(managedType, managedTypeOnAttr))
+ {
+ continue;
+ }
+
+ // Verify any instantiation of Generic parameters is provided by entry point.
+ // TODO: Hard failure based on previous implementation
+ ITypeSymbol? managedTypeInst = ResolveManagedType(managedTypeOnAttr, entryPointType, compilation);
+ if (managedTypeInst is null)
+ return false;
+
+ // Verify any instantiated managed types are derived properly.
+ // TODO: Hard failure based on previous implementation
+ if (!TypeSymbolsConstructedFromEqualTypes(managedType, managedTypeInst))
+ return false;
+
+ var marshallerScenario = (Scenario)attr.ConstructorArguments[1].Value!;
+
+ ITypeSymbol? marshallerTypeOnAttr = attr.ConstructorArguments[2].Value as ITypeSymbol;
+ if (marshallerTypeOnAttr is null)
+ continue;
+
+ // TODO: We can probably get rid of MarshallingDirection and just use Scenario instead
+ MarshallingDirection direction = marshallerScenario switch
+ {
+ Scenario.Default
+ => MarshallingDirection.Bidirectional,
+
+ Scenario.ManagedToUnmanagedIn
+ or Scenario.UnmanagedToManagedOut
+ => MarshallingDirection.ManagedToUnmanaged,
+
+ Scenario.ManagedToUnmanagedOut
+ or Scenario.UnmanagedToManagedIn
+ => MarshallingDirection.UnmanagedToManaged,
+
+ Scenario.ManagedToUnmanagedRef
+ or Scenario.UnmanagedToManagedRef
+ => MarshallingDirection.Bidirectional,
- var namedArguments = attr.NamedArguments.ToImmutableDictionary();
- CustomTypeMarshallerData? inMarshaller =
- GetNamedArgumentAsMarshallerData(namedArguments, MarshallersProperties.InMarshaller, MarshallingDirection.ManagedToUnmanaged, managedTypeOnAttr, compilation) ??
- GetMarshallerDataForType(entryPointType, MarshallingDirection.ManagedToUnmanaged, managedTypeOnAttr, compilation);
+ Scenario.ElementIn
+ or Scenario.ElementRef
+ or Scenario.ElementOut
+ => MarshallingDirection.Bidirectional,
- CustomTypeMarshallerData? refMarshaller =
- GetNamedArgumentAsMarshallerData(namedArguments, MarshallersProperties.RefMarshaller, MarshallingDirection.Bidirectional, managedTypeOnAttr, compilation) ??
- GetMarshallerDataForType(entryPointType, MarshallingDirection.Bidirectional, managedTypeOnAttr, compilation);
+ _ => throw new UnreachableException()
+ };
+
+ // TODO: Report invalid shape for scenario
+ // Skip checking for bidirectional support for Default scenario - always take / store marshaller data
+ CustomTypeMarshallerData? data = GetMarshallerDataForType(marshallerTypeOnAttr, direction, managedTypeOnAttr, compilation);
+
+ // TODO: Should we fire a diagnostic for duplicated scenarios or just take the last one?
+ if (data is null
+ || scenarios.ContainsKey(marshallerScenario))
+ {
+ continue;
+ }
- CustomTypeMarshallerData? outMarshaller =
- GetNamedArgumentAsMarshallerData(namedArguments, MarshallersProperties.OutMarshaller, MarshallingDirection.UnmanagedToManaged, managedTypeOnAttr, compilation) ??
- GetMarshallerDataForType(entryPointType, MarshallingDirection.UnmanagedToManaged, managedTypeOnAttr, compilation);
+ scenarios.Add(marshallerScenario, data.Value);
+ }
- if (inMarshaller is null && refMarshaller is null && outMarshaller is null)
+ if (scenarios.Count == 0)
return false;
marshallers = new CustomTypeMarshallers()
{
- In = inMarshaller,
- Ref = refMarshaller,
- Out = outMarshaller,
+ Scenarios = scenarios.ToImmutableDictionary()
};
return true;
+
+ static bool TypeSymbolsConstructedFromEqualTypes(ITypeSymbol left, ITypeSymbol right)
+ {
+ return (left, right) switch
+ {
+ (INamedTypeSymbol namedLeft, INamedTypeSymbol namedRight) => SymbolEqualityComparer.Default.Equals(namedLeft.ConstructedFrom, namedRight.ConstructedFrom),
+ _ => SymbolEqualityComparer.Default.Equals(left, right)
+ };
+ }
}
/// <summary>
- /// Resolve a non-<see cref="INamedTypeSymbol"/> <paramref name="managedType"/> to the correct managed type if <paramref name="marshallerType"/> is generic and <paramref name="managedType"/> is using any placeholder types.
+ /// Resolve a non-<see cref="INamedTypeSymbol"/> <paramref name="managedType"/> to the correct
+ /// managed type if <paramref name="entryType"/> is generic and <paramref name="managedType"/>
+ /// is using any placeholder types.
/// </summary>
/// <param name="managedType">The non-named managed type.</param>
- /// <param name="marshallerType">The marshaller type.</param>
+ /// <param name="entryType">The marshaller type.</param>
/// <param name="compilation">The compilation to use to make new type symbols.</param>
/// <returns>The resolved managed type, or <paramref name="managedType"/> if the provided type did not have any placeholders.</returns>
- public static ITypeSymbol? ResolveManagedType(ITypeSymbol? managedType, INamedTypeSymbol marshallerType, Compilation compilation)
+ public static ITypeSymbol? ResolveManagedType(ITypeSymbol? managedType, INamedTypeSymbol entryType, Compilation compilation)
{
- if (managedType is null || !marshallerType.IsGenericType)
+ if (managedType is null || !entryType.IsGenericType)
{
return managedType;
}
@@ -121,7 +211,7 @@ namespace Microsoft.Interop
return managedType;
}
- ITypeSymbol resultType = marshallerType.TypeArguments[0];
+ ITypeSymbol resultType = entryType.TypeArguments[0];
while (typeStack.Count > 0)
{
@@ -142,39 +232,46 @@ namespace Microsoft.Interop
return resultType;
}
- public static (AttributeData? attribute, INamedTypeSymbol? marshallerType) GetDefaultMarshallerInfo(ITypeSymbol managedType)
+ /// <summary>
+ /// Get the managed type's defined marshaller entry type.
+ /// </summary>
+ /// <param name="managedType">The managed type.</param>
+ /// <returns>The attribute data and entry type for marshalling.</returns>
+ public static (AttributeData? attribute, INamedTypeSymbol? entryType) GetDefaultMarshallerEntryType(ITypeSymbol managedType)
{
AttributeData? attr = managedType.GetAttributes().FirstOrDefault(attr => attr.AttributeClass.ToDisplayString() == TypeNames.NativeMarshallingAttribute);
- if (attr is null)
- {
- return (attr, null);
- }
- INamedTypeSymbol? marshallerType = null;
- if (attr.ConstructorArguments.Length == 0)
+ if (attr is null || attr.ConstructorArguments.Length == 0)
{
return (attr, null);
}
- marshallerType = attr.ConstructorArguments[0].Value as INamedTypeSymbol;
- if (managedType is not INamedTypeSymbol namedType || marshallerType is null)
+ INamedTypeSymbol? entryType = attr.ConstructorArguments[0].Value as INamedTypeSymbol;
+ if (managedType is not INamedTypeSymbol namedType || entryType is null)
{
return (attr, null);
}
+
+ // Non-generic types involved, return the entry defined in the attribute.
if (namedType.TypeArguments.Length == 0)
{
- return (attr, marshallerType);
+ return (attr, entryType);
}
- else if (marshallerType.TypeArguments.Length != namedType.TypeArguments.Length)
+
+ // Mismatch of generic type arguments between the type and entry.
+ if (namedType.TypeArguments.Length != entryType.TypeArguments.Length)
{
return (attr, null);
}
- else if (marshallerType.IsGenericType)
+
+ // If the marshaller is generic, instantiate it based on the type.
+ if (entryType.IsGenericType)
{
// Construct the marshaler type around the same type arguments as the managed type.
- return (attr, marshallerType.ConstructedFrom.Construct(namedType.TypeArguments, namedType.TypeArgumentNullableAnnotations));
+ return (attr, entryType.ConstructedFrom.Construct(namedType.TypeArguments, namedType.TypeArgumentNullableAnnotations));
}
- return (attr, marshallerType);
+ // Entry isn't generic, just return it.
+ return (attr, entryType);
}
public static IMethodSymbol? FindGetPinnableReference(ITypeSymbol type)
@@ -189,16 +286,6 @@ namespace Microsoft.Interop
({ ReturnsByRef: true } or { ReturnsByRefReadonly: true }));
}
- private static CustomTypeMarshallerData? GetNamedArgumentAsMarshallerData(ImmutableDictionary<string, TypedConstant> namedArguments, string name, MarshallingDirection direction, ITypeSymbol managedType, Compilation compilation)
- {
- ITypeSymbol? marshallerType = namedArguments.TryGetValue(name, out TypedConstant typeMaybe) ? typeMaybe.Value as ITypeSymbol : null;
- if (marshallerType is null)
- return null;
-
- // TODO: Report invalid shape
- return GetMarshallerDataForType(marshallerType, direction, managedType, compilation);
- }
-
private static CustomTypeMarshallerData? GetMarshallerDataForType(ITypeSymbol marshallerType, MarshallingDirection direction, ITypeSymbol managedType, Compilation compilation)
{
(MarshallerShape shape, Dictionary<MarshallerShape, IMethodSymbol> methodsByShape) = MarshallerShapeHelper.GetShapeForType(marshallerType, managedType, compilation);
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 41a20f14606..b96d5cca47d 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
@@ -213,15 +213,15 @@ namespace Microsoft.Interop
CustomTypeMarshallerData marshallerData;
if (info.IsManagedReturnPosition)
{
- marshallerData = marshalInfo.ManagedToUnmanagedMarshallers.Out.Value;
+ marshallerData = marshalInfo.Marshallers.GetScenarioOrDefault(Scenario.ManagedToUnmanagedOut);
}
else
{
marshallerData = info.RefKind switch
{
- RefKind.None or RefKind.In => marshalInfo.ManagedToUnmanagedMarshallers.In.Value,
- RefKind.Ref => marshalInfo.ManagedToUnmanagedMarshallers.Ref.Value,
- RefKind.Out => marshalInfo.ManagedToUnmanagedMarshallers.Out.Value,
+ RefKind.None or RefKind.In => marshalInfo.Marshallers.GetScenarioOrDefault(Scenario.ManagedToUnmanagedIn),
+ RefKind.Ref => marshalInfo.Marshallers.GetScenarioOrDefault(Scenario.ManagedToUnmanagedRef),
+ RefKind.Out => marshalInfo.Marshallers.GetScenarioOrDefault(Scenario.ManagedToUnmanagedOut),
_ => throw new MarshallingNotSupportedException(info, context)
};
}
@@ -250,30 +250,30 @@ namespace Microsoft.Interop
{
// Marshalling out or return parameter, but no out marshaller is specified
if ((info.RefKind == RefKind.Out || info.IsManagedReturnPosition)
- && !marshalInfo.ManagedToUnmanagedMarshallers.Out.HasValue)
+ && !marshalInfo.Marshallers.IsDefinedOrDefault(Scenario.ManagedToUnmanagedOut))
{
throw new MarshallingNotSupportedException(info, context)
{
- NotSupportedDetails = string.Format(SR.UnmanagedToManagedMissingRequiredMarshaller, ManualTypeMarshallingHelper.MarshallersProperties.OutMarshaller, marshalInfo.EntryPointType.FullTypeName)
+ NotSupportedDetails = string.Format(SR.UnmanagedToManagedMissingRequiredMarshaller, marshalInfo.EntryPointType.FullTypeName)
};
}
// Marshalling ref parameter, but no ref marshaller is specified
- if (info.RefKind == RefKind.Ref && !marshalInfo.ManagedToUnmanagedMarshallers.Ref.HasValue)
+ if (info.RefKind == RefKind.Ref && !marshalInfo.Marshallers.IsDefinedOrDefault(Scenario.ManagedToUnmanagedRef))
{
throw new MarshallingNotSupportedException(info, context)
{
- NotSupportedDetails = string.Format(SR.BidirectionalMissingRequiredMarshaller, ManualTypeMarshallingHelper.MarshallersProperties.RefMarshaller, marshalInfo.EntryPointType.FullTypeName)
+ NotSupportedDetails = string.Format(SR.BidirectionalMissingRequiredMarshaller, marshalInfo.EntryPointType.FullTypeName)
};
}
// Marshalling in parameter, but no in marshaller is specified
if (info.RefKind == RefKind.In
- && !marshalInfo.ManagedToUnmanagedMarshallers.In.HasValue)
+ && !marshalInfo.Marshallers.IsDefinedOrDefault(Scenario.ManagedToUnmanagedIn))
{
throw new MarshallingNotSupportedException(info, context)
{
- NotSupportedDetails = string.Format(SR.ManagedToUnmanagedMissingRequiredMarshaller, ManualTypeMarshallingHelper.MarshallersProperties.InMarshaller, marshalInfo.EntryPointType.FullTypeName)
+ NotSupportedDetails = string.Format(SR.ManagedToUnmanagedMissingRequiredMarshaller, marshalInfo.EntryPointType.FullTypeName)
};
}
@@ -281,11 +281,11 @@ namespace Microsoft.Interop
if (!info.IsByRef
&& !info.IsManagedReturnPosition
&& context.SingleFrameSpansNativeContext
- && !(marshalInfo.IsPinnableManagedType || marshalInfo.ManagedToUnmanagedMarshallers.In.HasValue))
+ && !(marshalInfo.IsPinnableManagedType || marshalInfo.Marshallers.IsDefinedOrDefault(Scenario.ManagedToUnmanagedIn)))
{
throw new MarshallingNotSupportedException(info, context)
{
- NotSupportedDetails = string.Format(SR.ManagedToUnmanagedMissingRequiredMarshaller, ManualTypeMarshallingHelper.MarshallersProperties.InMarshaller, marshalInfo.EntryPointType.FullTypeName)
+ NotSupportedDetails = string.Format(SR.ManagedToUnmanagedMissingRequiredMarshaller, marshalInfo.EntryPointType.FullTypeName)
};
}
}
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 94cb51c028f..81021677c4f 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
@@ -142,7 +142,7 @@ namespace Microsoft.Interop
/// </summary>
public record NativeMarshallingAttributeInfo(
ManagedTypeInfo EntryPointType,
- CustomTypeMarshallers ManagedToUnmanagedMarshallers,
+ CustomTypeMarshallers Marshallers,
bool IsPinnableManagedType) : MarshallingInfo;
/// <summary>
@@ -584,7 +584,7 @@ namespace Microsoft.Interop
ref int maxIndirectionDepthUsed)
{
bool isLinearCollectionMarshalling = ManualTypeMarshallingHelper.IsLinearCollectionEntryPoint(entryPointType);
- if (ManualTypeMarshallingHelper.TryGetMarshallers(entryPointType, type, isLinearCollectionMarshalling, _compilation, out CustomTypeMarshallers? marshallers))
+ if (ManualTypeMarshallingHelper.TryGetMarshallersFromEntryType(entryPointType, type, isLinearCollectionMarshalling, _compilation, out CustomTypeMarshallers? marshallers))
{
if (!entryPointType.IsStatic)
{
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 1033928da4f..e3325f0935a 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
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
@@ -17,6 +17,8 @@
Link="Production\CustomTypeMarshallerFeatures.cs" />
<Compile Include="$(CoreLibSharedDir)System\Runtime\InteropServices\StringMarshalling.cs"
Link="Production\StringMarshalling.cs" />
+ <Compile Include="..\..\tests\Ancillary.Interop\Scenario.cs"
+ Link="Production\Scenario.cs" />
</ItemGroup>
<ItemGroup>
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 b73f03ca140..f9c3128f772 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
@@ -16,7 +16,7 @@ namespace Microsoft.Interop
public const string CustomTypeMarshallerAttribute = "System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerAttribute";
public const string CustomTypeMarshallerAttributeGenericPlaceholder = "System.Runtime.InteropServices.Marshalling.CustomTypeMarshallerAttribute.GenericPlaceholder";
- public const string ManagedToUnmanagedMarshallersAttribute = "System.Runtime.InteropServices.Marshalling.ManagedToUnmanagedMarshallersAttribute";
+ public const string CustomMarshallerAttribute = "System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute";
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/tests/Ancillary.Interop/CustomMarshallerAttribute.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/CustomMarshallerAttribute.cs
new file mode 100644
index 00000000000..55abce124ab
--- /dev/null
+++ b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/CustomMarshallerAttribute.cs
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+#nullable enable
+
+using System;
+
+namespace System.Runtime.InteropServices.Marshalling
+{
+ /// <summary>
+ /// Attribute to indicate an entry point type for defining a marshaller.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+#if LIBRARYIMPORT_GENERATOR_TEST
+ public
+#else
+ internal
+#endif
+ sealed class CustomMarshallerAttribute : Attribute
+ {
+ /// <summary>
+ /// Create a <see cref="CustomMarshallerAttribute"/> instance.
+ /// </summary>
+ /// <param name="managedType">Managed type to marshal.</param>
+ /// <param name="scenario">Marshalling scenario.</param>
+ /// <param name="marshallerType">Type used for marshalling.</param>
+ public CustomMarshallerAttribute(Type managedType, Scenario scenario, Type marshallerType) { }
+
+ /// <summary>
+ /// Placeholder type for generic parameter
+ /// </summary>
+ public struct GenericPlaceholder
+ {
+ }
+ }
+}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/CustomTypeMarshallersAttributeBase.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/CustomTypeMarshallersAttributeBase.cs
deleted file mode 100644
index be020d0f716..00000000000
--- a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/CustomTypeMarshallersAttributeBase.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace System.Runtime.InteropServices.Marshalling
-{
- /// <summary>
- /// Base class attribute for custom marshaller attributes.
- /// </summary>
- /// <remarks>
- /// Use a base class here to allow doing ManagedToUnmanagedMarshallersAttribute.GenericPlaceholder, etc. without having 3 separate placeholder types.
- /// For the following attribute types, any marshaller types that are provided will be validated by an analyzer to have the correct members to prevent
- /// developers from accidentally typoing a member like Free() and causing memory leaks.
- /// </remarks>
-#if LIBRARYIMPORT_GENERATOR_TEST
- public
-#else
- internal
-#endif
- abstract class CustomUnmanagedTypeMarshallersAttributeBase : Attribute
- {
- /// <summary>
- /// Placeholder type for generic parameter
- /// </summary>
- public struct GenericPlaceholder { }
- }
-}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ManagedToUnmanagedMarshallersAttribute.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ManagedToUnmanagedMarshallersAttribute.cs
deleted file mode 100644
index d950e222992..00000000000
--- a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ManagedToUnmanagedMarshallersAttribute.cs
+++ /dev/null
@@ -1,38 +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
-
-namespace System.Runtime.InteropServices.Marshalling
-{
- /// <summary>
- /// Specify marshallers used in the managed to unmanaged direction (that is, P/Invoke)
- /// </summary>
-#if LIBRARYIMPORT_GENERATOR_TEST
- public
-#else
- internal
-#endif
- sealed class ManagedToUnmanagedMarshallersAttribute : CustomUnmanagedTypeMarshallersAttributeBase
- {
- /// <summary>
- /// Create instance of <see cref="ManagedToUnmanagedMarshallersAttribute"/>.
- /// </summary>
- /// <param name="managedType">Managed type to marshal</param>
- public ManagedToUnmanagedMarshallersAttribute(Type managedType) { }
-
- /// <summary>
- /// Marshaller to use when a parameter of the managed type is passed by-value or with the <c>in</c> keyword.
- /// </summary>
- public Type? InMarshaller { get; set; }
-
- /// <summary>
- /// Marshaller to use when a parameter of the managed type is passed by-value or with the <c>ref</c> keyword.
- /// </summary>
- public Type? RefMarshaller { get; set; }
-
- /// <summary>
- /// Marshaller to use when a parameter of the managed type is passed by-value or with the <c>out</c> keyword.
- /// </summary>
- public Type? OutMarshaller { get; set; }
- }
-}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/Scenario.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/Scenario.cs
new file mode 100644
index 00000000000..485d2418706
--- /dev/null
+++ b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/Scenario.cs
@@ -0,0 +1,62 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#if MICROSOFT_INTEROP_SOURCEGENERATION
+namespace Microsoft.Interop
+#else
+namespace System.Runtime.InteropServices
+#endif
+{
+ /// <summary>
+ /// An enumeration representing the different marshalling scenarios in our marshalling model.
+ /// </summary>
+#if LIBRARYIMPORT_GENERATOR_TEST || MICROSOFT_INTEROP_SOURCEGENERATION
+ public
+#else
+ internal
+#endif
+ enum Scenario
+ {
+ /// <summary>
+ /// All scenarios. A marshaller specified with this scenario will be used if there is not a specific
+ /// marshaller specified for a given usage scenario.
+ /// </summary>
+ Default,
+ /// <summary>
+ /// By-value and <c>in</c> parameters in managed-to-unmanaged scenarios, like P/Invoke.
+ /// </summary>
+ ManagedToUnmanagedIn,
+ /// <summary>
+ /// <c>ref</c> parameters in managed-to-unmanaged scenarios, like P/Invoke.
+ /// </summary>
+ ManagedToUnmanagedRef,
+ /// <summary>
+ /// <c>out</c> parameters in managed-to-unmanaged scenarios, like P/Invoke.
+ /// </summary>
+ ManagedToUnmanagedOut,
+ /// <summary>
+ /// By-value and <c>in</c> parameters in unmanaged-to-managed scenarios, like Reverse P/Invoke.
+ /// </summary>
+ UnmanagedToManagedIn,
+ /// <summary>
+ /// <c>ref</c> parameters in unmanaged-to-managed scenarios, like Reverse P/Invoke.
+ /// </summary>
+ UnmanagedToManagedRef,
+ /// <summary>
+ /// <c>out</c> parameters in unmanaged-to-managed scenarios, like Reverse P/Invoke.
+ /// </summary>
+ UnmanagedToManagedOut,
+ /// <summary>
+ /// Elements of arrays passed with <c>in</c> or by-value in interop scenarios.
+ /// </summary>
+ ElementIn,
+ /// <summary>
+ /// Elements of arrays passed with <c>ref</c> or passed by-value with both <see cref="InAttribute"/> and <see cref="OutAttribute" /> in interop scenarios.
+ /// </summary>
+ ElementRef,
+ /// <summary>
+ /// Elements of arrays passed with <c>out</c> or passed by-value with only <see cref="OutAttribute" /> in interop scenarios.
+ /// </summary>
+ ElementOut
+ }
+}
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 7288cd3615c..f35fdcd05ba 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CustomMarshallingTests.cs
@@ -43,13 +43,13 @@ namespace LibraryImportGenerator.IntegrationTests
[return: MarshalUsing(typeof(IntGuaranteedUnmarshal))]
public static partial int GuaranteedUnmarshal([MarshalUsing(typeof(ExceptionOnUnmarshal))] out int ret);
- [ManagedToUnmanagedMarshallers(typeof(int))]
+ [CustomMarshaller(typeof(int), Scenario.ManagedToUnmanagedOut, typeof(ExceptionOnUnmarshal))]
public static class ExceptionOnUnmarshal
{
public static int ConvertToManaged(int unmanaged) => throw new Exception();
}
- [ManagedToUnmanagedMarshallers(typeof(int))]
+ [CustomMarshaller(typeof(int), Scenario.ManagedToUnmanagedOut, typeof(IntGuaranteedUnmarshal))]
public static unsafe class IntGuaranteedUnmarshal
{
public static bool ConvertToManagedGuaranteedCalled = 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 70261fd077f..940cd5ab2b0 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 = @"
-[ManagedToUnmanagedMarshallers(typeof(S))]
+[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(Marshaller))]
public class Marshaller
{
public struct Native { }
@@ -699,7 +699,7 @@ public class Marshaller
}
";
private static string StatelessIn = @"
-[ManagedToUnmanagedMarshallers(typeof(S))]
+[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(Marshaller))]
public static class Marshaller
{
public struct Native { }
@@ -708,7 +708,7 @@ public static class Marshaller
}
";
private static string StatelessInBuffer = @"
-[ManagedToUnmanagedMarshallers(typeof(S))]
+[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(Marshaller))]
public static class Marshaller
{
public struct Native { }
@@ -718,7 +718,7 @@ public static class Marshaller
}
";
private static string StatelessOut = @"
-[ManagedToUnmanagedMarshallers(typeof(S))]
+[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedOut, typeof(Marshaller))]
public static class Marshaller
{
public struct Native { }
@@ -727,7 +727,7 @@ public static class Marshaller
}
";
private static string StatelessOutGuaranteed = @"
-[ManagedToUnmanagedMarshallers(typeof(S))]
+[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedOut, typeof(Marshaller))]
public static class Marshaller
{
public struct Native { }
@@ -736,7 +736,7 @@ public static class Marshaller
}
";
public static string StatelessRef = @"
-[ManagedToUnmanagedMarshallers(typeof(S))]
+[CustomMarshaller(typeof(S), Scenario.Default, typeof(Marshaller))]
public static class Marshaller
{
public struct Native { }
@@ -746,7 +746,8 @@ public static class Marshaller
}
";
public static string StatelessRefBuffer = @"
-[ManagedToUnmanagedMarshallers(typeof(S))]
+[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedIn, typeof(Marshaller))]
+[CustomMarshaller(typeof(S), Scenario.ManagedToUnmanagedOut, typeof(Marshaller))]
public static class Marshaller
{
public struct Native { }
@@ -757,7 +758,7 @@ public static class Marshaller
}
";
public static string StatelessRefOptionalBuffer = @"
-[ManagedToUnmanagedMarshallers(typeof(S))]
+[CustomMarshaller(typeof(S), Scenario.Default, typeof(Marshaller))]
public static class Marshaller
{
public struct Native { }
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 6451bc7e86b..609ef8c8ab5 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/NonBlittable.cs
@@ -19,10 +19,9 @@ namespace SharedTypes
public string str2;
}
- [ManagedToUnmanagedMarshallers(typeof(StringContainer),
- InMarshaller = typeof(In),
- RefMarshaller = typeof(Ref),
- OutMarshaller = typeof(Out))]
+ [CustomMarshaller(typeof(StringContainer), Scenario.ManagedToUnmanagedIn, typeof(In))]
+ [CustomMarshaller(typeof(StringContainer), Scenario.ManagedToUnmanagedRef, typeof(Ref))]
+ [CustomMarshaller(typeof(StringContainer), Scenario.ManagedToUnmanagedOut, typeof(Out))]
public static class StringContainerMarshaller
{
public struct StringContainerNative
@@ -77,7 +76,7 @@ namespace SharedTypes
}
}
- [ManagedToUnmanagedMarshallers(typeof(double))]
+ [CustomMarshaller(typeof(double), Scenario.ManagedToUnmanagedIn, typeof(DoubleToBytesBigEndianMarshaller))]
public static unsafe class DoubleToBytesBigEndianMarshaller
{
public const int BufferSize = 8;
@@ -89,7 +88,7 @@ namespace SharedTypes
}
}
- [ManagedToUnmanagedMarshallers(typeof(double))]
+ [CustomMarshaller(typeof(double), Scenario.ManagedToUnmanagedIn, typeof(DoubleToLongMarshaller))]
public static class DoubleToLongMarshaller
{
public static long ConvertToUnmanaged(double managed)
@@ -106,7 +105,7 @@ namespace SharedTypes
public bool b3;
}
- [ManagedToUnmanagedMarshallers(typeof(BoolStruct))]
+ [CustomMarshaller(typeof(BoolStruct), Scenario.Default, typeof(BoolStructMarshaller))]
public static class BoolStructMarshaller
{
public struct BoolStructNative
@@ -145,7 +144,7 @@ namespace SharedTypes
public ref int GetPinnableReference() => ref i;
}
- [ManagedToUnmanagedMarshallers(typeof(IntWrapper))]
+ [CustomMarshaller(typeof(IntWrapper), Scenario.Default, typeof(IntWrapperMarshaller))]
public static unsafe class IntWrapperMarshaller
{
public static int* ConvertToUnmanaged(IntWrapper managed)