diff --git a/docs/design/libraries/DllImportGenerator/Compatibility.md b/docs/design/libraries/DllImportGenerator/Compatibility.md
index 2790eff6e8943..5f5997a36edaa 100644
--- a/docs/design/libraries/DllImportGenerator/Compatibility.md
+++ b/docs/design/libraries/DllImportGenerator/Compatibility.md
@@ -4,7 +4,11 @@ Documentation on compatibility guidance and the current state. The version headi
## Version 1
-The focus of version 1 is to support `NetCoreApp`. This implies that anything not needed by `NetCoreApp` is subject to change. Only .NET 6+ is supported.
+The focus of version 1 is to support `NetCoreApp`. This implies that anything not needed by `NetCoreApp` is subject to change.
+
+### Fallback mechanism
+
+In the event a marshaller would generate code that has a specific target framework or version requirement that is not satisfied, the generator will instead produce a normal `DllImportAttribute` declaration. This fallback mechanism enables the use of `GeneratedDllImportAttribute` in most circumstances and permits the conversion from `DllImportAttribute` to `GeneratedDllImportAttribute` to be across most code bases. There are instances where the generator will not be able to handle signatures or configuration. For example, uses of `StringBuilder` are not supported in any form and consumers should retain uses of `DllImportAttribute`. Additionally, `GeneratedDllImportAttribute` cannot represent all settings available on `DllImportAttribute`—see below for details.
### Semantic changes compared to `DllImportAttribute`
@@ -92,4 +96,4 @@ Unlike the built-in system, the source generator does not support marshalling fo
## Version 0
-This version is the built-in IL Stub generation system that is triggered whenever a method marked with `DllImport` is invoked.
+This version is the built-in IL Stub generation system that is triggered whenever a method marked with `DllImportAttribute` is invoked.
diff --git a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Comparers.cs b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Comparers.cs
index 71ecae6a88860..39166e8c76748 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Comparers.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Comparers.cs
@@ -25,12 +25,12 @@ internal static class Comparers
///
/// Comparer for an individual generated stub source as a syntax tree and the generated diagnostics for the stub.
///
- public static readonly IEqualityComparer<(MemberDeclarationSyntax Syntax, ImmutableArray Diagnostics)> GeneratedSyntax = new CustomValueTupleElementComparer>(new SyntaxEquivalentComparer(), new ImmutableArraySequenceEqualComparer(EqualityComparer.Default));
+ public static readonly IEqualityComparer<(MemberDeclarationSyntax Syntax, ImmutableArray Diagnostics)> GeneratedSyntax = new CustomValueTupleElementComparer>(SyntaxEquivalentComparer.Instance, new ImmutableArraySequenceEqualComparer(EqualityComparer.Default));
///
/// Comparer for the context used to generate a stub and the original user-provided syntax that triggered stub creation.
///
- public static readonly IEqualityComparer<(MethodDeclarationSyntax Syntax, DllImportGenerator.IncrementalStubGenerationContext StubContext)> CalculatedContextWithSyntax = new CustomValueTupleElementComparer(new SyntaxEquivalentComparer(), EqualityComparer.Default);
+ public static readonly IEqualityComparer<(MethodDeclarationSyntax Syntax, DllImportGenerator.IncrementalStubGenerationContext StubContext)> CalculatedContextWithSyntax = new CustomValueTupleElementComparer(SyntaxEquivalentComparer.Instance, EqualityComparer.Default);
}
///
@@ -63,6 +63,10 @@ public int GetHashCode(ImmutableArray obj)
internal class SyntaxEquivalentComparer : IEqualityComparer
{
+ public static readonly SyntaxEquivalentComparer Instance = new();
+
+ private SyntaxEquivalentComparer() { }
+
public bool Equals(SyntaxNode x, SyntaxNode y)
{
return x.IsEquivalentTo(y);
diff --git a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/DllImportGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/DllImportGenerator.cs
index 69ee5175042ba..f69393e6e1589 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/DllImportGenerator.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/DllImportGenerator.cs
@@ -24,16 +24,20 @@ public sealed class DllImportGenerator : IIncrementalGenerator
private const string GeneratedDllImport = nameof(GeneratedDllImport);
private const string GeneratedDllImportAttribute = nameof(GeneratedDllImportAttribute);
- private static readonly Version s_minimumSupportedFrameworkVersion = new Version(5, 0);
-
- internal sealed record IncrementalStubGenerationContext(DllImportStubContext StubContext, ImmutableArray ForwardedAttributes, GeneratedDllImportData DllImportData, ImmutableArray Diagnostics)
+ internal sealed record IncrementalStubGenerationContext(
+ StubEnvironment Environment,
+ DllImportStubContext StubContext,
+ ImmutableArray ForwardedAttributes,
+ GeneratedDllImportData DllImportData,
+ ImmutableArray Diagnostics)
{
public bool Equals(IncrementalStubGenerationContext? other)
{
return other is not null
+ && StubEnvironment.AreCompilationSettingsEqual(Environment, other.Environment)
&& StubContext.Equals(other.StubContext)
&& DllImportData.Equals(other.DllImportData)
- && ForwardedAttributes.SequenceEqual(other.ForwardedAttributes, (IEqualityComparer)new SyntaxEquivalentComparer())
+ && ForwardedAttributes.SequenceEqual(other.ForwardedAttributes, (IEqualityComparer)SyntaxEquivalentComparer.Instance)
&& Diagnostics.SequenceEqual(other.Diagnostics);
}
@@ -93,11 +97,11 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
context.ReportDiagnostic(Diagnostic.Create(GeneratorDiagnostics.ReturnConfigurationNotSupported, refReturnMethod.Syntax.GetLocation(), "ref return", refReturnMethod.Symbol.ToDisplayString()));
});
- IncrementalValueProvider<(Compilation compilation, bool isSupported, Version targetFrameworkVersion)> compilationAndTargetFramework = context.CompilationProvider
+ IncrementalValueProvider<(Compilation compilation, TargetFramework targetFramework, Version targetFrameworkVersion)> compilationAndTargetFramework = context.CompilationProvider
.Select(static (compilation, ct) =>
{
- bool isSupported = IsSupportedTargetFramework(compilation, out Version targetFrameworkVersion);
- return (compilation, isSupported, targetFrameworkVersion);
+ TargetFramework fmk = DetermineTargetFramework(compilation, out Version targetFrameworkVersion);
+ return (compilation, fmk, targetFrameworkVersion);
});
context.RegisterSourceOutput(
@@ -105,16 +109,16 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
.Combine(methodsToGenerate.Collect()),
static (context, data) =>
{
- if (!data.Left.isSupported && data.Right.Any())
+ if (data.Left.targetFramework is TargetFramework.Unknown && data.Right.Any())
{
- // We don't block source generation when the TFM is unsupported.
+ // We don't block source generation when the TFM is unknown.
// This allows a user to copy generated source and use it as a starting point
// for manual marshalling if desired.
context.ReportDiagnostic(
Diagnostic.Create(
GeneratorDiagnostics.TargetFrameworkNotSupported,
Location.None,
- s_minimumSupportedFrameworkVersion.ToString(2)));
+ data.Left.targetFrameworkVersion));
}
});
@@ -127,7 +131,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
static (data, ct) =>
new StubEnvironment(
data.Left.compilation,
- data.Left.isSupported,
+ data.Left.targetFramework,
data.Left.targetFrameworkVersion,
data.Left.compilation.SourceModule.GetAttributes().Any(attr => attr.AttributeClass?.ToDisplayString() == TypeNames.System_Runtime_CompilerServices_SkipLocalsInitAttribute),
data.Right)
@@ -312,7 +316,7 @@ private static MemberDeclarationSyntax WrapMethodInContainingScopes(DllImportStu
return toPrint;
}
- private static bool IsSupportedTargetFramework(Compilation compilation, out Version version)
+ private static TargetFramework DetermineTargetFramework(Compilation compilation, out Version version)
{
IAssemblySymbol systemAssembly = compilation.GetSpecialType(SpecialType.System_Object).ContainingAssembly;
version = systemAssembly.Identity.Version;
@@ -320,12 +324,13 @@ private static bool IsSupportedTargetFramework(Compilation compilation, out Vers
return systemAssembly.Identity.Name switch
{
// .NET Framework
- "mscorlib" => false,
+ "mscorlib" => TargetFramework.Framework,
// .NET Standard
- "netstandard" => false,
+ "netstandard" => TargetFramework.Standard,
// .NET Core (when version < 5.0) or .NET
- "System.Runtime" or "System.Private.CoreLib" => version >= s_minimumSupportedFrameworkVersion,
- _ => false,
+ "System.Runtime" or "System.Private.CoreLib" =>
+ (version.Major < 5) ? TargetFramework.Core : TargetFramework.Net,
+ _ => TargetFramework.Unknown,
};
}
@@ -339,7 +344,6 @@ private static GeneratedDllImportData ProcessGeneratedDllImportAttribute(Attribu
throw new InvalidProgramException();
}
-
// Default values for these properties are based on the
// documented semanatics of DllImportAttribute:
// - https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.dllimportattribute
@@ -473,7 +477,7 @@ private static IncrementalStubGenerationContext CalculateStubInformation(IMethod
// Create the stub.
var dllImportStub = DllImportStubContext.Create(symbol, stubDllImportData, environment, generatorDiagnostics, ct);
- return new IncrementalStubGenerationContext(dllImportStub, additionalAttributes.ToImmutableArray(), stubDllImportData, generatorDiagnostics.Diagnostics.ToImmutableArray());
+ return new IncrementalStubGenerationContext(environment, dllImportStub, additionalAttributes.ToImmutableArray(), stubDllImportData, generatorDiagnostics.Diagnostics.ToImmutableArray());
}
private (MemberDeclarationSyntax, ImmutableArray) GenerateSource(
@@ -490,12 +494,16 @@ private static IncrementalStubGenerationContext CalculateStubInformation(IMethod
// Generate stub code
var stubGenerator = new PInvokeStubCodeGenerator(
+ dllImportStub.Environment,
dllImportStub.StubContext.ElementTypeInformation,
dllImportStub.DllImportData.SetLastError && !options.GenerateForwarders,
(elementInfo, ex) => diagnostics.ReportMarshallingNotSupported(originalSyntax, elementInfo, ex.NotSupportedDetails),
dllImportStub.StubContext.GeneratorFactory);
- if (stubGenerator.StubIsBasicForwarder)
+ // Check if the generator should produce a forwarder stub - regular DllImport.
+ // This is done if the signature is blittable or the target framework is not supported.
+ if (stubGenerator.StubIsBasicForwarder
+ || !stubGenerator.SupportsTargetFramework)
{
return (PrintForwarderStub(originalSyntax, dllImportStub), dllImportStub.Diagnostics.AddRange(diagnostics.Diagnostics));
}
diff --git a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/DllImportStubContext.cs b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/DllImportStubContext.cs
index 853422ab5a1ff..420e2b6f88743 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/DllImportStubContext.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/DllImportStubContext.cs
@@ -18,10 +18,27 @@ namespace Microsoft.Interop
{
internal record StubEnvironment(
Compilation Compilation,
- bool SupportedTargetFramework,
+ TargetFramework TargetFramework,
Version TargetFrameworkVersion,
bool ModuleSkipLocalsInit,
- DllImportGeneratorOptions Options);
+ DllImportGeneratorOptions Options)
+ {
+ ///
+ /// Override for determining if two StubEnvironment instances are
+ /// equal. This intentionally excludes the Compilation instance
+ /// since that represents the actual compilation and not just the settings.
+ ///
+ /// The first StubEnvironment
+ /// The second StubEnvironment
+ /// True if the settings are equal, otherwise false.
+ public static bool AreCompilationSettingsEqual(StubEnvironment env1, StubEnvironment env2)
+ {
+ return env1.TargetFramework == env2.TargetFramework
+ && env1.TargetFrameworkVersion == env2.TargetFrameworkVersion
+ && env1.ModuleSkipLocalsInit == env2.ModuleSkipLocalsInit
+ && env1.Options.Equals(env2.Options);
+ }
+ }
internal sealed class DllImportStubContext : IEquatable
{
@@ -164,7 +181,6 @@ private static (ImmutableArray, IMarshallingGeneratorFactory)
NativeIndex = typeInfos.Count
};
typeInfos.Add(typeInfo);
-
}
TypePositionInfo retTypeInfo = new(ManagedTypeInfo.CreateTypeInfoForTypeSymbol(method.ReturnType), marshallingAttributeParser.ParseMarshallingInfo(method.ReturnType, method.GetReturnTypeAttributes()));
@@ -234,9 +250,9 @@ public bool Equals(DllImportStubContext other)
return other is not null
&& StubTypeNamespace == other.StubTypeNamespace
&& ElementTypeInformation.SequenceEqual(other.ElementTypeInformation)
- && StubContainingTypes.SequenceEqual(other.StubContainingTypes, (IEqualityComparer)new SyntaxEquivalentComparer())
+ && StubContainingTypes.SequenceEqual(other.StubContainingTypes, (IEqualityComparer)SyntaxEquivalentComparer.Instance)
&& StubReturnType.IsEquivalentTo(other.StubReturnType)
- && AdditionalAttributes.SequenceEqual(other.AdditionalAttributes, (IEqualityComparer)new SyntaxEquivalentComparer())
+ && AdditionalAttributes.SequenceEqual(other.AdditionalAttributes, (IEqualityComparer)SyntaxEquivalentComparer.Instance)
&& Options.Equals(other.Options);
}
diff --git a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/PInvokeStubCodeGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/PInvokeStubCodeGenerator.cs
index 6915a3c996601..4c9bbd0b1e392 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/PInvokeStubCodeGenerator.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/PInvokeStubCodeGenerator.cs
@@ -34,6 +34,10 @@ private record struct BoundGenerator(TypePositionInfo TypeInfo, IMarshallingGene
public override bool AdditionalTemporaryStateLivesAcrossStages => true;
+ public bool SupportsTargetFramework { get; init; }
+
+ public bool StubIsBasicForwarder { get; init; }
+
///
/// Identifier for managed return value
///
@@ -58,9 +62,8 @@ private record struct BoundGenerator(TypePositionInfo TypeInfo, IMarshallingGene
private readonly List _sortedMarshallers;
private readonly bool _stubReturnsVoid;
- public bool StubIsBasicForwarder { get; }
-
public PInvokeStubCodeGenerator(
+ StubEnvironment environment,
IEnumerable argTypes,
bool setLastError,
Action marshallingNotSupportedCallback,
@@ -68,6 +71,19 @@ public PInvokeStubCodeGenerator(
{
_setLastError = setLastError;
+ // Support for SetLastError logic requires .NET 6+. Initialize the
+ // supports target framework value with this value.
+ if (_setLastError)
+ {
+ SupportsTargetFramework = environment.TargetFramework == TargetFramework.Net
+ && environment.TargetFrameworkVersion.Major >= 6;
+ }
+ else
+ {
+ SupportsTargetFramework = true;
+ }
+
+ bool noMarshallingNeeded = true;
List allMarshallers = new();
List paramMarshallers = new();
bool foundNativeRetMarshaller = false;
@@ -78,6 +94,14 @@ public PInvokeStubCodeGenerator(
foreach (TypePositionInfo argType in argTypes)
{
BoundGenerator generator = CreateGenerator(argType);
+
+ // Check each marshaler if the current target framework is supported or not.
+ SupportsTargetFramework &= generator.Generator.IsSupported(environment.TargetFramework, environment.TargetFrameworkVersion);
+
+ // Check if generator is either blittable or just a forwarder.
+ noMarshallingNeeded &= generator is { Generator: BlittableMarshaller, TypeInfo: { IsByRef: false } }
+ or { Generator: Forwarder };
+
allMarshallers.Add(generator);
if (argType.IsManagedReturnPosition)
{
@@ -139,9 +163,7 @@ public PInvokeStubCodeGenerator(
StubIsBasicForwarder = !setLastError
&& managedRetMarshaller.TypeInfo.IsNativeReturnPosition // If the managed return has native return position, then it's the return for both.
- && _sortedMarshallers.All(
- m => m is { Generator: BlittableMarshaller, TypeInfo: { IsByRef: false } }
- or { Generator: Forwarder });
+ && noMarshallingNeeded;
if (managedRetMarshaller.Generator.UsesNativeIdentifier(managedRetMarshaller.TypeInfo, this))
{
diff --git a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Resources.Designer.cs b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Resources.Designer.cs
index eb6bfa6e52e08..30ad6508d4f17 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Resources.Designer.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Resources.Designer.cs
@@ -511,7 +511,7 @@ internal static string StackallocMarshallingShouldSupportAllocatingMarshallingFa
}
///
- /// Looks up a localized string similar to P/Invoke source generation is only supported on .NET {0} or above. The generated source will not be compatible with other frameworks..
+ /// Looks up a localized string similar to P/Invoke source generation is not supported on unknown target framework v{0}. The generated source will not be compatible with other frameworks..
///
internal static string TargetFrameworkNotSupportedDescription {
get {
@@ -520,7 +520,7 @@ internal static string TargetFrameworkNotSupportedDescription {
}
///
- /// Looks up a localized string similar to 'GeneratedDllImportAttribute' cannot be used for source-generated P/Invokes on the current target framework. Source-generated P/Invokes require .NET {0} or above..
+ /// Looks up a localized string similar to 'GeneratedDllImportAttribute' cannot be used for source-generated P/Invokes on an unknown target framework v{0}..
///
internal static string TargetFrameworkNotSupportedMessage {
get {
diff --git a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Resources.resx b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Resources.resx
index 3124872bc3175..e66ea89a005c8 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Resources.resx
+++ b/src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Resources.resx
@@ -269,11 +269,11 @@
Native type '{0}' has a stack-allocating constructor does not support marshalling in scenarios where stack allocation is impossible
- P/Invoke source generation is only supported on .NET {0} or above. The generated source will not be compatible with other frameworks.
+ P/Invoke source generation is not supported on unknown target framework v{0}. The generated source will not be compatible with other frameworks.{0} is a version number
- 'GeneratedDllImportAttribute' cannot be used for source-generated P/Invokes on the current target framework. Source-generated P/Invokes require .NET {0} or above.
+ 'GeneratedDllImportAttribute' cannot be used for source-generated P/Invokes on an unknown target framework v{0}.{0} is a version number
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ArrayMarshaller.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ArrayMarshaller.cs
index 82ee55861816f..4e6980a80250f 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ArrayMarshaller.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ArrayMarshaller.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System;
using System.Collections.Generic;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -23,6 +24,11 @@ public ArrayMarshaller(IMarshallingGenerator manualMarshallingGenerator, TypeSyn
_options = options;
}
+ public bool IsSupported(TargetFramework target, Version version)
+ {
+ return target is TargetFramework.Net && version.Major >= 6;
+ }
+
public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context)
{
if (IsPinningPathSupported(info, context))
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/BlittableMarshaller.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/BlittableMarshaller.cs
index c68037306af57..b137316d21aed 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/BlittableMarshaller.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/BlittableMarshaller.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System;
using System.Collections.Generic;
using Microsoft.CodeAnalysis;
@@ -12,6 +13,8 @@ namespace Microsoft.Interop
{
public sealed class BlittableMarshaller : IMarshallingGenerator
{
+ public bool IsSupported(TargetFramework target, Version version) => true;
+
public TypeSyntax AsNativeType(TypePositionInfo info)
{
return info.ManagedType.Syntax;
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/BoolMarshaller.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/BoolMarshaller.cs
index a11a5243575fa..247d19ff1cf2c 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/BoolMarshaller.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/BoolMarshaller.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -26,6 +27,8 @@ protected BoolMarshallerBase(PredefinedTypeSyntax nativeType, int trueValue, int
_compareToTrue = compareToTrue;
}
+ public bool IsSupported(TargetFramework target, Version version) => true;
+
public TypeSyntax AsNativeType(TypePositionInfo info)
{
Debug.Assert(info.ManagedType is SpecialTypeInfo(_, _, SpecialType.System_Boolean));
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CharMarshaller.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CharMarshaller.cs
index fb18cb531f513..4852974aa8053 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CharMarshaller.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CharMarshaller.cs
@@ -20,6 +20,8 @@ public Utf16CharMarshaller()
{
}
+ public bool IsSupported(TargetFramework target, Version version) => true;
+
public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context)
{
(string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info);
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ConditionalStackallocMarshallingGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ConditionalStackallocMarshallingGenerator.cs
index 2b638538904e0..fb097a53a12f5 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ConditionalStackallocMarshallingGenerator.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ConditionalStackallocMarshallingGenerator.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System;
using System.Collections.Generic;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
@@ -227,6 +228,12 @@ protected virtual ExpressionSyntax GenerateNullCheckExpression(
LiteralExpression(SyntaxKind.NullLiteralExpression));
}
+ ///
+ public virtual bool IsSupported(TargetFramework target, Version version)
+ {
+ return target is TargetFramework.Net && version.Major >= 6;
+ }
+
///
public abstract TypeSyntax AsNativeType(TypePositionInfo info);
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CustomNativeTypeMarshallingGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CustomNativeTypeMarshallingGenerator.cs
index f01c2741ea7e0..4a27fa3cb4eb5 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CustomNativeTypeMarshallingGenerator.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/CustomNativeTypeMarshallingGenerator.cs
@@ -23,6 +23,11 @@ public CustomNativeTypeMarshallingGenerator(ICustomNativeTypeMarshallingStrategy
_enableByValueContentsMarshalling = enableByValueContentsMarshalling;
}
+ public bool IsSupported(TargetFramework target, Version version)
+ {
+ return target is TargetFramework.Net && version.Major >= 6;
+ }
+
public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context)
{
return _nativeTypeMarshaller.AsArgument(info, context);
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/DelegateMarshaller.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/DelegateMarshaller.cs
index 32fe10c6ec9c7..4db41933d591a 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/DelegateMarshaller.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/DelegateMarshaller.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System;
using System.Collections.Generic;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
@@ -11,6 +12,8 @@ namespace Microsoft.Interop
{
public sealed class DelegateMarshaller : IMarshallingGenerator
{
+ public bool IsSupported(TargetFramework target, Version version) => true;
+
public TypeSyntax AsNativeType(TypePositionInfo info)
{
return MarshallerHelpers.SystemIntPtrType;
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/Forwarder.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/Forwarder.cs
index fd4ca6a37ae62..931fccaf1616e 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/Forwarder.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/Forwarder.cs
@@ -13,6 +13,8 @@ namespace Microsoft.Interop
{
public sealed class Forwarder : IMarshallingGenerator, IAttributedReturnTypeMarshallingGenerator
{
+ public bool IsSupported(TargetFramework target, Version version) => true;
+
public TypeSyntax AsNativeType(TypePositionInfo info)
{
return info.ManagedType.Syntax;
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/HResultExceptionMarshaller.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/HResultExceptionMarshaller.cs
index 446750e2bc5ca..cb32ee3b33cc7 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/HResultExceptionMarshaller.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/HResultExceptionMarshaller.cs
@@ -16,6 +16,8 @@ public sealed class HResultExceptionMarshaller : IMarshallingGenerator
{
private static readonly TypeSyntax s_nativeType = PredefinedType(Token(SyntaxKind.IntKeyword));
+ public bool IsSupported(TargetFramework target, Version version) => true;
+
public TypeSyntax AsNativeType(TypePositionInfo info)
{
Debug.Assert(info.ManagedType is SpecialTypeInfo(_, _, SpecialType.System_Int32));
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs
index 74e7a517a4707..bad094d4ed357 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs
@@ -8,11 +8,31 @@
namespace Microsoft.Interop
{
+ ///
+ /// Target framework identifier
+ ///
+ public enum TargetFramework
+ {
+ Unknown,
+ Framework,
+ Core,
+ Standard,
+ Net
+ }
+
///
/// Interface for generation of marshalling code for P/Invoke stubs
///
public interface IMarshallingGenerator
{
+ ///
+ /// Determine if the generator is supported for the supplied version of the framework.
+ ///
+ /// The framework to target.
+ /// The version of the framework.
+ /// True if the marshaller is supported, otherwise false.
+ bool IsSupported(TargetFramework target, Version version);
+
///
/// Get the native type syntax for
///
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/PinnableManagedValueMarshaller.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/PinnableManagedValueMarshaller.cs
index aa47a55409cd2..e5890d04e9567 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/PinnableManagedValueMarshaller.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/PinnableManagedValueMarshaller.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System;
using System.Collections.Generic;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -17,6 +18,9 @@ public PinnableManagedValueMarshaller(IMarshallingGenerator manualMarshallingGen
_manualMarshallingGenerator = manualMarshallingGenerator;
}
+ public bool IsSupported(TargetFramework target, Version version)
+ => _manualMarshallingGenerator.IsSupported(target, version);
+
public ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context)
{
if (IsPinningPathSupported(info, context))
diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/SafeHandleMarshaller.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/SafeHandleMarshaller.cs
index 4a663542f52c1..59dc0b6001bd2 100644
--- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/SafeHandleMarshaller.cs
+++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/SafeHandleMarshaller.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis;
@@ -12,6 +13,11 @@ namespace Microsoft.Interop
{
public sealed class SafeHandleMarshaller : IMarshallingGenerator
{
+ public bool IsSupported(TargetFramework target, Version version)
+ {
+ return target is TargetFramework.Net && version.Major >= 6;
+ }
+
public TypeSyntax AsNativeType(TypePositionInfo info)
{
return MarshallerHelpers.SystemIntPtrType;
diff --git a/src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/AdditionalAttributesOnStub.cs b/src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/AdditionalAttributesOnStub.cs
index df7a1c536a8a9..803904a9f9881 100644
--- a/src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/AdditionalAttributesOnStub.cs
+++ b/src/libraries/System.Runtime.InteropServices/tests/DllImportGenerator.UnitTests/AdditionalAttributesOnStub.cs
@@ -64,47 +64,45 @@ partial class C
public static IEnumerable