diff --git a/DllImportGenerator/Ancillary.Interop/Ancillary.Interop.csproj b/DllImportGenerator/Ancillary.Interop/Ancillary.Interop.csproj
index e19d9b4e5d9b..b04f4ba3c089 100644
--- a/DllImportGenerator/Ancillary.Interop/Ancillary.Interop.csproj
+++ b/DllImportGenerator/Ancillary.Interop/Ancillary.Interop.csproj
@@ -6,6 +6,7 @@
System.Runtime.InteropServices
enable
true
+ APIs required for usage of the DllImportGenerator and related tools.
diff --git a/DllImportGenerator/Benchmarks/Benchmarks.csproj b/DllImportGenerator/Benchmarks/Benchmarks.csproj
index 02ec9f973bfd..fb1e9ea05338 100644
--- a/DllImportGenerator/Benchmarks/Benchmarks.csproj
+++ b/DllImportGenerator/Benchmarks/Benchmarks.csproj
@@ -18,6 +18,7 @@
+
diff --git a/DllImportGenerator/Demo/Demo.csproj b/DllImportGenerator/Demo/Demo.csproj
index 11805179e79d..1ffe230ada81 100644
--- a/DllImportGenerator/Demo/Demo.csproj
+++ b/DllImportGenerator/Demo/Demo.csproj
@@ -16,6 +16,7 @@
+
diff --git a/DllImportGenerator/DllImportGenerator.IntegrationTests/DllImportGenerator.IntegrationTests.csproj b/DllImportGenerator/DllImportGenerator.IntegrationTests/DllImportGenerator.IntegrationTests.csproj
index 4588c962fc81..ecd9ee7adf63 100644
--- a/DllImportGenerator/DllImportGenerator.IntegrationTests/DllImportGenerator.IntegrationTests.csproj
+++ b/DllImportGenerator/DllImportGenerator.IntegrationTests/DllImportGenerator.IntegrationTests.csproj
@@ -18,6 +18,7 @@
+
diff --git a/DllImportGenerator/DllImportGenerator.sln b/DllImportGenerator/DllImportGenerator.sln
index 20d7d1b61884..79455991304f 100644
--- a/DllImportGenerator/DllImportGenerator.sln
+++ b/DllImportGenerator/DllImportGenerator.sln
@@ -29,6 +29,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmarks", "Benchmarks\Be
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DllImportGenerator.Vsix", "DllImportGenerator.Vsix\DllImportGenerator.Vsix.csproj", "{F9215CDD-7B47-4C17-9166-0BE5066CA6BB}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Interop.SourceGeneration", "Microsoft.Interop.SourceGeneration\Microsoft.Interop.SourceGeneration.csproj", "{03FAE24C-728D-419C-B6EC-5C7AE8C45705}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -79,6 +81,10 @@ Global
{F9215CDD-7B47-4C17-9166-0BE5066CA6BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F9215CDD-7B47-4C17-9166-0BE5066CA6BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F9215CDD-7B47-4C17-9166-0BE5066CA6BB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {03FAE24C-728D-419C-B6EC-5C7AE8C45705}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {03FAE24C-728D-419C-B6EC-5C7AE8C45705}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {03FAE24C-728D-419C-B6EC-5C7AE8C45705}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {03FAE24C-728D-419C-B6EC-5C7AE8C45705}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/DllImportGenerator/DllImportGenerator/DllImportGenerator.cs b/DllImportGenerator/DllImportGenerator/DllImportGenerator.cs
index 92668a646d46..70dfbaef0120 100644
--- a/DllImportGenerator/DllImportGenerator/DllImportGenerator.cs
+++ b/DllImportGenerator/DllImportGenerator/DllImportGenerator.cs
@@ -105,16 +105,18 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
}
});
+ var stubOptions = context.AnalyzerConfigOptionsProvider.Select((options, ct) => new DllImportGeneratorOptions(options.GlobalOptions));
+
var stubEnvironment = compilationAndTargetFramework
- .Combine(context.AnalyzerConfigOptionsProvider)
+ .Combine(stubOptions)
.Select(
static (data, ct) =>
new StubEnvironment(
data.Left.compilation,
data.Left.isSupported,
data.Left.targetFrameworkVersion,
- data.Right.GlobalOptions,
- data.Left.compilation.SourceModule.GetAttributes().Any(attr => attr.AttributeClass?.ToDisplayString() == TypeNames.System_Runtime_CompilerServices_SkipLocalsInitAttribute))
+ data.Left.compilation.SourceModule.GetAttributes().Any(attr => attr.AttributeClass?.ToDisplayString() == TypeNames.System_Runtime_CompilerServices_SkipLocalsInitAttribute),
+ data.Right)
);
var methodSourceAndDiagnostics = methodsToGenerate
@@ -133,12 +135,12 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
}
)
.WithComparer(Comparers.CalculatedContextWithSyntax)
- .Combine(context.AnalyzerConfigOptionsProvider)
+ .Combine(stubOptions)
.Select(
(data, ct) =>
{
IncrementalTracker?.RecordExecutedStep(new IncrementalityTracker.ExecutedStepInfo(IncrementalityTracker.StepName.GenerateSingleStub, data));
- return GenerateSource(data.Left.StubContext, data.Left.Syntax, data.Right.GlobalOptions);
+ return GenerateSource(data.Left.StubContext, data.Left.Syntax, data.Right);
}
)
.WithComparer(Comparers.GeneratedSyntax)
@@ -444,24 +446,196 @@ private static IncrementalStubGenerationContext CalculateStubInformation(MethodD
private (MemberDeclarationSyntax, ImmutableArray) GenerateSource(
IncrementalStubGenerationContext dllImportStub,
MethodDeclarationSyntax originalSyntax,
- AnalyzerConfigOptions options)
+ DllImportGeneratorOptions options)
{
var diagnostics = new GeneratorDiagnostics();
// Generate stub code
- var stubGenerator = new StubCodeGenerator(
- dllImportStub.DllImportData,
+ var stubGenerator = new PInvokeStubCodeGenerator(
dllImportStub.StubContext.ElementTypeInformation,
- options,
- (elementInfo, ex) => diagnostics.ReportMarshallingNotSupported(originalSyntax, elementInfo, ex.NotSupportedDetails));
+ dllImportStub.DllImportData.SetLastError && !options.GenerateForwarders,
+ (elementInfo, ex) => diagnostics.ReportMarshallingNotSupported(originalSyntax, elementInfo, ex.NotSupportedDetails),
+ dllImportStub.StubContext.GeneratorFactory);
ImmutableArray forwardedAttributes = dllImportStub.ForwardedAttributes;
- var code = stubGenerator.GenerateBody(originalSyntax.Identifier.Text, forwardedAttributes: forwardedAttributes.Length != 0 ? AttributeList(SeparatedList(forwardedAttributes)) : null);
+ const string innerPInvokeName = "__PInvoke__";
+
+ var code = stubGenerator.GeneratePInvokeBody(innerPInvokeName);
+
+ var dllImport = CreateTargetFunctionAsLocalStatement(
+ stubGenerator,
+ dllImportStub.StubContext.Options,
+ dllImportStub.DllImportData,
+ innerPInvokeName,
+ originalSyntax.Identifier.Text);
+
+ if (!forwardedAttributes.IsEmpty)
+ {
+ dllImport = dllImport.AddAttributeLists(AttributeList(SeparatedList(forwardedAttributes)));
+ }
+
+ code = code.AddStatements(dllImport);
return (PrintGeneratedSource(originalSyntax, dllImportStub.StubContext, code), dllImportStub.Diagnostics.AddRange(diagnostics.Diagnostics));
}
+
+ private static LocalFunctionStatementSyntax CreateTargetFunctionAsLocalStatement(
+ PInvokeStubCodeGenerator stubGenerator,
+ DllImportGeneratorOptions options,
+ GeneratedDllImportData dllImportData,
+ string stubTargetName,
+ string stubMethodName)
+ {
+ var (parameterList, returnType, returnTypeAttributes) = stubGenerator.GenerateTargetMethodSignatureData();
+ var localDllImport = LocalFunctionStatement(returnType, stubTargetName)
+ .AddModifiers(
+ Token(SyntaxKind.ExternKeyword),
+ Token(SyntaxKind.StaticKeyword),
+ Token(SyntaxKind.UnsafeKeyword))
+ .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))
+ .WithAttributeLists(
+ SingletonList(AttributeList(
+ SingletonSeparatedList(
+ CreateDllImportAttributeForTarget(
+ GetTargetDllImportDataFromStubData(
+ dllImportData,
+ stubMethodName,
+ options.GenerateForwarders))))))
+ .WithParameterList(parameterList);
+ if (returnTypeAttributes is not null)
+ {
+ localDllImport = localDllImport.AddAttributeLists(returnTypeAttributes.WithTarget(AttributeTargetSpecifier(Token(SyntaxKind.ReturnKeyword))));
+ }
+ return localDllImport;
+ }
+
+ private static AttributeSyntax CreateDllImportAttributeForTarget(GeneratedDllImportData targetDllImportData)
+ {
+ var newAttributeArgs = new List
+ {
+ AttributeArgument(LiteralExpression(
+ SyntaxKind.StringLiteralExpression,
+ Literal(targetDllImportData.ModuleName))),
+ AttributeArgument(
+ NameEquals(nameof(DllImportAttribute.EntryPoint)),
+ null,
+ CreateStringExpressionSyntax(targetDllImportData.EntryPoint!))
+ };
+
+ if (targetDllImportData.IsUserDefined.HasFlag(DllImportMember.BestFitMapping))
+ {
+ var name = NameEquals(nameof(DllImportAttribute.BestFitMapping));
+ var value = CreateBoolExpressionSyntax(targetDllImportData.BestFitMapping);
+ newAttributeArgs.Add(AttributeArgument(name, null, value));
+ }
+ if (targetDllImportData.IsUserDefined.HasFlag(DllImportMember.CallingConvention))
+ {
+ var name = NameEquals(nameof(DllImportAttribute.CallingConvention));
+ var value = CreateEnumExpressionSyntax(targetDllImportData.CallingConvention);
+ newAttributeArgs.Add(AttributeArgument(name, null, value));
+ }
+ if (targetDllImportData.IsUserDefined.HasFlag(DllImportMember.CharSet))
+ {
+ var name = NameEquals(nameof(DllImportAttribute.CharSet));
+ var value = CreateEnumExpressionSyntax(targetDllImportData.CharSet);
+ newAttributeArgs.Add(AttributeArgument(name, null, value));
+ }
+ if (targetDllImportData.IsUserDefined.HasFlag(DllImportMember.ExactSpelling))
+ {
+ var name = NameEquals(nameof(DllImportAttribute.ExactSpelling));
+ var value = CreateBoolExpressionSyntax(targetDllImportData.ExactSpelling);
+ newAttributeArgs.Add(AttributeArgument(name, null, value));
+ }
+ if (targetDllImportData.IsUserDefined.HasFlag(DllImportMember.PreserveSig))
+ {
+ var name = NameEquals(nameof(DllImportAttribute.PreserveSig));
+ var value = CreateBoolExpressionSyntax(targetDllImportData.PreserveSig);
+ newAttributeArgs.Add(AttributeArgument(name, null, value));
+ }
+ if (targetDllImportData.IsUserDefined.HasFlag(DllImportMember.SetLastError))
+ {
+ var name = NameEquals(nameof(DllImportAttribute.SetLastError));
+ var value = CreateBoolExpressionSyntax(targetDllImportData.SetLastError);
+ newAttributeArgs.Add(AttributeArgument(name, null, value));
+ }
+ if (targetDllImportData.IsUserDefined.HasFlag(DllImportMember.ThrowOnUnmappableChar))
+ {
+ var name = NameEquals(nameof(DllImportAttribute.ThrowOnUnmappableChar));
+ var value = CreateBoolExpressionSyntax(targetDllImportData.ThrowOnUnmappableChar);
+ newAttributeArgs.Add(AttributeArgument(name, null, value));
+ }
+
+ // Create new attribute
+ return Attribute(
+ ParseName(typeof(DllImportAttribute).FullName),
+ AttributeArgumentList(SeparatedList(newAttributeArgs)));
+
+ static ExpressionSyntax CreateBoolExpressionSyntax(bool trueOrFalse)
+ {
+ return LiteralExpression(
+ trueOrFalse
+ ? SyntaxKind.TrueLiteralExpression
+ : SyntaxKind.FalseLiteralExpression);
+ }
+
+ static ExpressionSyntax CreateStringExpressionSyntax(string str)
+ {
+ return LiteralExpression(
+ SyntaxKind.StringLiteralExpression,
+ Literal(str));
+ }
+
+ static ExpressionSyntax CreateEnumExpressionSyntax(T value) where T : Enum
+ {
+ return MemberAccessExpression(
+ SyntaxKind.SimpleMemberAccessExpression,
+ IdentifierName(typeof(T).FullName),
+ IdentifierName(value.ToString()));
+ }
+ }
+
+ private static GeneratedDllImportData GetTargetDllImportDataFromStubData(GeneratedDllImportData dllImportData, string originalMethodName, bool forwardAll)
+ {
+ DllImportMember membersToForward = DllImportMember.All
+ // https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.dllimportattribute.preservesig
+ // If PreserveSig=false (default is true), the P/Invoke stub checks/converts a returned HRESULT to an exception.
+ & ~DllImportMember.PreserveSig
+ // https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.dllimportattribute.setlasterror
+ // If SetLastError=true (default is false), the P/Invoke stub gets/caches the last error after invoking the native function.
+ & ~DllImportMember.SetLastError;
+ if (forwardAll)
+ {
+ membersToForward = DllImportMember.All;
+ }
+
+ var targetDllImportData = new GeneratedDllImportData(dllImportData.ModuleName)
+ {
+ CharSet = dllImportData.CharSet,
+ BestFitMapping = dllImportData.BestFitMapping,
+ CallingConvention = dllImportData.CallingConvention,
+ EntryPoint = dllImportData.EntryPoint,
+ ExactSpelling = dllImportData.ExactSpelling,
+ SetLastError = dllImportData.SetLastError,
+ PreserveSig = dllImportData.PreserveSig,
+ ThrowOnUnmappableChar = dllImportData.ThrowOnUnmappableChar,
+ IsUserDefined = dllImportData.IsUserDefined & membersToForward
+ };
+
+ // If the EntryPoint property is not set, we will compute and
+ // add it based on existing semantics (i.e. method name).
+ //
+ // N.B. The export discovery logic is identical regardless of where
+ // the name is defined (i.e. method name vs EntryPoint property).
+ if (!targetDllImportData.IsUserDefined.HasFlag(DllImportMember.EntryPoint))
+ {
+ targetDllImportData = targetDllImportData with { EntryPoint = originalMethodName };
+ }
+
+ return targetDllImportData;
+ }
+
private static bool ShouldVisitNode(SyntaxNode syntaxNode)
{
// We only support C# method declarations.
diff --git a/DllImportGenerator/DllImportGenerator/DllImportGenerator.csproj b/DllImportGenerator/DllImportGenerator/DllImportGenerator.csproj
index cda46f7058dc..ca0f1512667e 100644
--- a/DllImportGenerator/DllImportGenerator/DllImportGenerator.csproj
+++ b/DllImportGenerator/DllImportGenerator/DllImportGenerator.csproj
@@ -35,12 +35,12 @@
-
+
+
-
-
+
@@ -58,4 +58,14 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/DllImportGenerator/DllImportGenerator/OptionsHelper.cs b/DllImportGenerator/DllImportGenerator/DllImportGeneratorOptions.cs
similarity index 77%
rename from DllImportGenerator/DllImportGenerator/OptionsHelper.cs
rename to DllImportGenerator/DllImportGenerator/DllImportGeneratorOptions.cs
index 13130369b41d..d63f7c880b9c 100644
--- a/DllImportGenerator/DllImportGenerator/OptionsHelper.cs
+++ b/DllImportGenerator/DllImportGenerator/DllImportGeneratorOptions.cs
@@ -1,12 +1,15 @@
-using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
namespace Microsoft.Interop
{
+ record DllImportGeneratorOptions(bool GenerateForwarders, bool UseMarshalType, bool UseInternalUnsafeType)
+ {
+ public DllImportGeneratorOptions(AnalyzerConfigOptions options)
+ : this(options.GenerateForwarders(), options.UseMarshalType(), options.UseInternalUnsafeType())
+ {
+ }
+ }
+
public static class OptionsHelper
{
public const string UseMarshalTypeOption = "build_property.DllImportGenerator_UseMarshalType";
diff --git a/DllImportGenerator/DllImportGenerator/DllImportStubContext.cs b/DllImportGenerator/DllImportGenerator/DllImportStubContext.cs
index e86b8fdef826..c3bfef462d52 100644
--- a/DllImportGenerator/DllImportGenerator/DllImportStubContext.cs
+++ b/DllImportGenerator/DllImportGenerator/DllImportStubContext.cs
@@ -17,8 +17,8 @@ internal record StubEnvironment(
Compilation Compilation,
bool SupportedTargetFramework,
Version TargetFrameworkVersion,
- AnalyzerConfigOptions Options,
- bool ModuleSkipLocalsInit);
+ bool ModuleSkipLocalsInit,
+ DllImportGeneratorOptions Options);
internal sealed class DllImportStubContext : IEquatable
{
@@ -58,6 +58,10 @@ public IEnumerable StubParameters
public ImmutableArray AdditionalAttributes { get; init; }
+ public DllImportGeneratorOptions Options { get; init; }
+
+ public IMarshallingGeneratorFactory GeneratorFactory { get; init; }
+
public static DllImportStubContext Create(
IMethodSymbol method,
GeneratedDllImportData dllImportData,
@@ -95,7 +99,7 @@ public static DllImportStubContext Create(
currType = currType.ContainingType;
}
- var typeInfos = GenerateTypeInformation(method, dllImportData, diagnostics, env);
+ var (typeInfos, generatorFactory) = GenerateTypeInformation(method, dllImportData, diagnostics, env);
var additionalAttrs = ImmutableArray.CreateBuilder();
@@ -120,10 +124,12 @@ public static DllImportStubContext Create(
StubTypeNamespace = stubTypeNamespace,
StubContainingTypes = containingTypes.ToImmutable(),
AdditionalAttributes = additionalAttrs.ToImmutable(),
+ Options = env.Options,
+ GeneratorFactory = generatorFactory
};
}
- private static ImmutableArray GenerateTypeInformation(IMethodSymbol method, GeneratedDllImportData dllImportData, GeneratorDiagnostics diagnostics, StubEnvironment env)
+ private static (ImmutableArray, IMarshallingGeneratorFactory) GenerateTypeInformation(IMethodSymbol method, GeneratedDllImportData dllImportData, GeneratorDiagnostics diagnostics, StubEnvironment env)
{
// Compute the current default string encoding value.
var defaultEncoding = CharEncoding.Undefined;
@@ -165,36 +171,52 @@ private static ImmutableArray GenerateTypeInformation(IMethodS
NativeIndex = TypePositionInfo.ReturnIndex
};
- var managedRetTypeInfo = retTypeInfo;
- // Do not manually handle PreserveSig when generating forwarders.
- // We want the runtime to handle everything.
- if (!dllImportData.PreserveSig && !env.Options.GenerateForwarders())
+ InteropGenerationOptions options = new(env.Options.UseMarshalType, env.Options.UseInternalUnsafeType);
+ IMarshallingGeneratorFactory generatorFactory;
+
+ if (env.Options.GenerateForwarders)
{
- // Create type info for native HRESULT return
- retTypeInfo = new TypePositionInfo(SpecialTypeInfo.Int32, NoMarshallingInfo.Instance);
- retTypeInfo = retTypeInfo with
+ generatorFactory = new ForwarderMarshallingGeneratorFactory();
+ }
+ else
+ {
+ generatorFactory = new DefaultMarshallingGeneratorFactory(options);
+ AttributedMarshallingModelGeneratorFactory attributedMarshallingFactory = new(generatorFactory, options);
+ generatorFactory = attributedMarshallingFactory;
+ if (!dllImportData.PreserveSig)
{
- NativeIndex = TypePositionInfo.ReturnIndex
- };
+ // Create type info for native out param
+ if (!method.ReturnsVoid)
+ {
+ // Transform the managed return type info into an out parameter and add it as the last param
+ TypePositionInfo nativeOutInfo = retTypeInfo with
+ {
+ InstanceIdentifier = PInvokeStubCodeGenerator.ReturnIdentifier,
+ RefKind = RefKind.Out,
+ RefKindSyntax = SyntaxKind.OutKeyword,
+ ManagedIndex = TypePositionInfo.ReturnIndex,
+ NativeIndex = typeInfos.Count
+ };
+ typeInfos.Add(nativeOutInfo);
+ }
- // Create type info for native out param
- if (!method.ReturnsVoid)
- {
- // Transform the managed return type info into an out parameter and add it as the last param
- TypePositionInfo nativeOutInfo = managedRetTypeInfo with
+ // Use a marshalling generator that supports the HRESULT return->exception marshalling.
+ generatorFactory = new NoPreserveSigMarshallingGeneratorFactory(generatorFactory);
+
+ // Create type info for native HRESULT return
+ retTypeInfo = new TypePositionInfo(SpecialTypeInfo.Int32, NoMarshallingInfo.Instance);
+ retTypeInfo = retTypeInfo with
{
- InstanceIdentifier = StubCodeGenerator.ReturnIdentifier,
- RefKind = RefKind.Out,
- RefKindSyntax = SyntaxKind.OutKeyword,
- ManagedIndex = TypePositionInfo.ReturnIndex,
- NativeIndex = typeInfos.Count
+ NativeIndex = TypePositionInfo.ReturnIndex
};
- typeInfos.Add(nativeOutInfo);
}
+
+ generatorFactory = new ByValueContentsMarshalKindValidator(generatorFactory);
+ attributedMarshallingFactory.ElementMarshallingGeneratorFactory = generatorFactory;
}
typeInfos.Add(retTypeInfo);
- return typeInfos.ToImmutable();
+ return (typeInfos.ToImmutable(), generatorFactory);
}
public override bool Equals(object obj)
@@ -204,12 +226,15 @@ public override bool Equals(object obj)
public bool Equals(DllImportStubContext other)
{
+ // We don't check if the generator factories are equal since
+ // the generator factory is deterministically created based on the ElementTypeInformation and Options.
return other is not null
&& StubTypeNamespace == other.StubTypeNamespace
&& ElementTypeInformation.SequenceEqual(other.ElementTypeInformation)
&& StubContainingTypes.SequenceEqual(other.StubContainingTypes, (IEqualityComparer)new SyntaxEquivalentComparer())
&& StubReturnType.IsEquivalentTo(other.StubReturnType)
- && AdditionalAttributes.SequenceEqual(other.AdditionalAttributes, (IEqualityComparer)new SyntaxEquivalentComparer());
+ && AdditionalAttributes.SequenceEqual(other.AdditionalAttributes, (IEqualityComparer)new SyntaxEquivalentComparer())
+ && Options.Equals(other.Options);
}
public override int GetHashCode()
diff --git a/DllImportGenerator/DllImportGenerator/ForwarderMarshallingGeneratorFactory.cs b/DllImportGenerator/DllImportGenerator/ForwarderMarshallingGeneratorFactory.cs
new file mode 100644
index 000000000000..60c85b4baba0
--- /dev/null
+++ b/DllImportGenerator/DllImportGenerator/ForwarderMarshallingGeneratorFactory.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Microsoft.Interop
+{
+ class ForwarderMarshallingGeneratorFactory : IMarshallingGeneratorFactory
+ {
+ private static readonly Forwarder Forwarder = new Forwarder();
+
+ public IMarshallingGenerator Create(TypePositionInfo info, StubCodeContext context) => Forwarder;
+ }
+}
diff --git a/DllImportGenerator/DllImportGenerator/GeneratorDiagnostics.cs b/DllImportGenerator/DllImportGenerator/GeneratorDiagnostics.cs
index 74abfb3c7149..77b018f4b880 100644
--- a/DllImportGenerator/DllImportGenerator/GeneratorDiagnostics.cs
+++ b/DllImportGenerator/DllImportGenerator/GeneratorDiagnostics.cs
@@ -1,69 +1,18 @@
-using System;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
-using System.Linq;
-
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
+using System.Text;
namespace Microsoft.Interop
{
- internal static class DiagnosticExtensions
- {
- public static Diagnostic CreateDiagnostic(
- this ISymbol symbol,
- DiagnosticDescriptor descriptor,
- params object[] args)
- {
- return symbol.Locations.CreateDiagnostic(descriptor, args);
- }
-
- public static Diagnostic CreateDiagnostic(
- this AttributeData attributeData,
- DiagnosticDescriptor descriptor,
- params object[] args)
- {
- SyntaxReference? syntaxReference = attributeData.ApplicationSyntaxReference;
- Location location = syntaxReference is not null
- ? syntaxReference.GetSyntax().GetLocation()
- : Location.None;
-
- return location.CreateDiagnostic(descriptor, args);
- }
-
- public static Diagnostic CreateDiagnostic(
- this ImmutableArray locations,
- DiagnosticDescriptor descriptor,
- params object[] args)
- {
- IEnumerable locationsInSource = locations.Where(l => l.IsInSource);
- if (!locationsInSource.Any())
- return Diagnostic.Create(descriptor, Location.None, args);
-
- return Diagnostic.Create(
- descriptor,
- location: locationsInSource.First(),
- additionalLocations: locationsInSource.Skip(1),
- messageArgs: args);
- }
-
- public static Diagnostic CreateDiagnostic(
- this Location location,
- DiagnosticDescriptor descriptor,
- params object[] args)
- {
- return Diagnostic.Create(
- descriptor,
- location: location.IsInSource ? location : Location.None,
- messageArgs: args);
- }
- }
///
/// Class for reporting diagnostics in the DLL import generator
///
- public class GeneratorDiagnostics
+ public class GeneratorDiagnostics : IGeneratorDiagnostics
{
public class Ids
{
@@ -213,7 +162,7 @@ public void ReportConfigurationNotSupported(
/// Method with the parameter/return
/// Type info for the parameter/return
/// [Optional] Specific reason for lack of support
- internal void ReportMarshallingNotSupported(
+ public void ReportMarshallingNotSupported(
MethodDeclarationSyntax method,
TypePositionInfo info,
string? notSupportedDetails)
@@ -298,7 +247,7 @@ internal void ReportMarshallingNotSupported(
}
}
- internal void ReportInvalidMarshallingAttributeInfo(
+ public void ReportInvalidMarshallingAttributeInfo(
AttributeData attributeData,
string reasonResourceName,
params string[] reasonArgs)
diff --git a/DllImportGenerator/DllImportGenerator/Marshalling/MarshallingGenerator.cs b/DllImportGenerator/DllImportGenerator/Marshalling/MarshallingGenerator.cs
deleted file mode 100644
index 24fb56ad90bc..000000000000
--- a/DllImportGenerator/DllImportGenerator/Marshalling/MarshallingGenerator.cs
+++ /dev/null
@@ -1,628 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Runtime.InteropServices;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.Diagnostics;
-using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
-
-namespace Microsoft.Interop
-{
- ///
- /// Interface for generation of marshalling code for P/Invoke stubs
- ///
- internal interface IMarshallingGenerator
- {
- ///
- /// Get the native type syntax for
- ///
- /// Object to marshal
- /// Type syntax for the native type representing
- TypeSyntax AsNativeType(TypePositionInfo info);
-
- ///
- /// Get the as a parameter of the P/Invoke declaration
- ///
- /// Object to marshal
- /// Parameter syntax for
- ParameterSyntax AsParameter(TypePositionInfo info);
-
- ///
- /// Get the as an argument to be passed to the P/Invoke
- ///
- /// Object to marshal
- /// Code generation context
- /// Argument syntax for
- ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context);
-
- ///
- /// Generate code for marshalling
- ///
- /// Object to marshal
- /// Code generation context
- /// List of statements to be added to the P/Invoke stub
- ///
- /// The generator should return the appropriate statements based on the
- /// of .
- /// For , any statements not of type
- /// will be ignored.
- ///
- IEnumerable Generate(TypePositionInfo info, StubCodeContext context);
-
- ///
- /// Returns whether or not this marshaller uses an identifier for the native value in addition
- /// to an identifer for the managed value.
- ///
- /// Object to marshal
- /// Code generation context
- /// If the marshaller uses an identifier for the native value, true; otherwise, false.
- ///
- /// of may not be valid.
- ///
- bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context);
-
- ///
- /// Returns if the given ByValueContentsMarshalKind is supported in the current marshalling context.
- /// A supported marshal kind has a different behavior than the default behavior.
- ///
- /// The marshal kind.
- /// The marshalling context.
- ///
- bool SupportsByValueMarshalKind(ByValueContentsMarshalKind marshalKind, StubCodeContext context);
- }
-
- ///
- /// Interface for generating attributes for native return types.
- ///
- internal interface IAttributedReturnTypeMarshallingGenerator : IMarshallingGenerator
- {
- ///
- /// Gets any attributes that should be applied to the return type for this .
- ///
- /// Object to marshal
- /// Attributes for the return type for this , or null if no attributes should be added.
- AttributeListSyntax? GenerateAttributesForReturnType(TypePositionInfo info);
- }
-
- ///
- /// Exception used to indicate marshalling isn't supported.
- ///
- internal class MarshallingNotSupportedException : Exception
- {
- ///
- /// Construct a new instance.
- ///
- /// instance
- /// instance
- public MarshallingNotSupportedException(TypePositionInfo info, StubCodeContext context)
- {
- this.TypePositionInfo = info;
- this.StubCodeContext = context;
- }
-
- ///
- /// Type that is being marshalled.
- ///
- public TypePositionInfo TypePositionInfo { get; private init; }
-
- ///
- /// Context in which the marshalling is taking place.
- ///
- public StubCodeContext StubCodeContext { get; private init; }
-
- ///
- /// [Optional] Specific reason marshalling of the supplied type isn't supported.
- ///
- public string? NotSupportedDetails { get; init; }
- }
-
- internal class MarshallingGenerators
- {
- public static readonly ByteBoolMarshaller ByteBool = new ByteBoolMarshaller();
- public static readonly WinBoolMarshaller WinBool = new WinBoolMarshaller();
- public static readonly VariantBoolMarshaller VariantBool = new VariantBoolMarshaller();
-
- public static readonly Utf16CharMarshaller Utf16Char = new Utf16CharMarshaller();
- public static readonly Utf16StringMarshaller Utf16String = new Utf16StringMarshaller();
- public static readonly Utf8StringMarshaller Utf8String = new Utf8StringMarshaller();
- public static readonly AnsiStringMarshaller AnsiString = new AnsiStringMarshaller(Utf8String);
- public static readonly PlatformDefinedStringMarshaller PlatformDefinedString = new PlatformDefinedStringMarshaller(Utf16String, Utf8String);
-
- public static readonly Forwarder Forwarder = new Forwarder();
- public static readonly BlittableMarshaller Blittable = new BlittableMarshaller();
- public static readonly DelegateMarshaller Delegate = new DelegateMarshaller();
- public static readonly HResultExceptionMarshaller HResultException = new HResultExceptionMarshaller();
-
- ///
- /// Create an instance for marshalling the supplied type in the given position.
- ///
- /// Type details
- /// Metadata about the stub the type is associated with
- /// A instance.
- public static IMarshallingGenerator Create(
- TypePositionInfo info,
- StubCodeContext context,
- AnalyzerConfigOptions options)
- {
- return ValidateByValueMarshalKind(context, info, CreateCore(info, context, options));
- }
-
- private static IMarshallingGenerator ValidateByValueMarshalKind(StubCodeContext context, TypePositionInfo info, IMarshallingGenerator generator)
- {
- if (info.IsByRef && info.ByValueContentsMarshalKind != ByValueContentsMarshalKind.Default)
- {
- throw new MarshallingNotSupportedException(info, context)
- {
- NotSupportedDetails = Resources.InOutAttributeByRefNotSupported
- };
- }
- else if (info.ByValueContentsMarshalKind == ByValueContentsMarshalKind.In)
- {
- throw new MarshallingNotSupportedException(info, context)
- {
- NotSupportedDetails = Resources.InAttributeNotSupportedWithoutOut
- };
- }
- else if (info.ByValueContentsMarshalKind != ByValueContentsMarshalKind.Default
- && !generator.SupportsByValueMarshalKind(info.ByValueContentsMarshalKind, context))
- {
- throw new MarshallingNotSupportedException(info, context)
- {
- NotSupportedDetails = Resources.InOutAttributeMarshalerNotSupported
- };
- }
- return generator;
- }
-
- ///
- /// Create an instance to marshalling the supplied type.
- ///
- /// Type details
- /// Metadata about the stub the type is associated with
- /// A instance.
- private static IMarshallingGenerator CreateCore(
- TypePositionInfo info,
- StubCodeContext context,
- AnalyzerConfigOptions options)
- {
- if (options.GenerateForwarders())
- {
- return MarshallingGenerators.Forwarder;
- }
-
- if (info.IsNativeReturnPosition && !info.IsManagedReturnPosition)
- {
- // Use marshaller for native HRESULT return / exception throwing
- System.Diagnostics.Debug.Assert(info.ManagedType is SpecialTypeInfo { SpecialType: SpecialType.System_Int32 });
- return HResultException;
- }
-
- switch (info)
- {
- // Blittable primitives with no marshalling info or with a compatible [MarshalAs] attribute.
- case { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_SByte }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.I1, _) }
- or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Byte }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.U1, _) }
- or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Int16 }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.I2, _) }
- or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_UInt16 }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.U2, _) }
- or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Int32 }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.I4, _) }
- or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_UInt32 }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.U4, _) }
- or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Int64 }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.I8, _) }
- or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_UInt64 }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.U8, _) }
- or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_IntPtr }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.SysInt, _) }
- or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_UIntPtr }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.SysUInt, _) }
- or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Single }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.R4, _) }
- or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Double }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.R8, _) }:
- return Blittable;
-
- // Enum with no marshalling info
- case { ManagedType: EnumTypeInfo enumType, MarshallingAttributeInfo: NoMarshallingInfo }:
- // Check that the underlying type is not bool or char. C# does not allow this, but ECMA-335 does.
- var underlyingSpecialType = enumType.UnderlyingType;
- if (underlyingSpecialType == SpecialType.System_Boolean || underlyingSpecialType == SpecialType.System_Char)
- {
- throw new MarshallingNotSupportedException(info, context);
- }
- return Blittable;
-
- // Pointer with no marshalling info
- case { ManagedType: PointerTypeInfo(_, _, IsFunctionPointer:false), MarshallingAttributeInfo: NoMarshallingInfo }:
- return Blittable;
-
- // Function pointer with no marshalling info
- case { ManagedType: PointerTypeInfo(_, _, IsFunctionPointer: true), MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.FunctionPtr, _) }:
- return Blittable;
-
- case { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Boolean }, MarshallingAttributeInfo: NoMarshallingInfo }:
- return WinBool; // [Compat] Matching the default for the built-in runtime marshallers.
- case { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Boolean }, MarshallingAttributeInfo: MarshalAsInfo(UnmanagedType.I1 or UnmanagedType.U1, _) }:
- return ByteBool;
- case { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Boolean }, MarshallingAttributeInfo: MarshalAsInfo(UnmanagedType.I4 or UnmanagedType.U4 or UnmanagedType.Bool, _) }:
- return WinBool;
- case { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Boolean }, MarshallingAttributeInfo: MarshalAsInfo(UnmanagedType.VariantBool, _) }:
- return VariantBool;
-
- case { ManagedType: DelegateTypeInfo, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.FunctionPtr, _) }:
- return Delegate;
-
- case { MarshallingAttributeInfo: SafeHandleMarshallingInfo(_, bool isAbstract) }:
- if (!context.AdditionalTemporaryStateLivesAcrossStages)
- {
- throw new MarshallingNotSupportedException(info, context);
- }
- if (info.IsByRef && isAbstract)
- {
- throw new MarshallingNotSupportedException(info, context)
- {
- NotSupportedDetails = Resources.SafeHandleByRefMustBeConcrete
- };
- }
- return new SafeHandleMarshaller(options);
-
- // Marshalling in new model.
- // Must go before the cases that do not explicitly check for marshalling info to support
- // the user overridding the default marshalling rules with a MarshalUsing attribute.
- case { MarshallingAttributeInfo: NativeMarshallingAttributeInfo marshalInfo }:
- return CreateCustomNativeTypeMarshaller(info, context, marshalInfo, options);
-
- case { MarshallingAttributeInfo: BlittableTypeAttributeInfo }:
- return Blittable;
-
- // Simple generated marshalling with new attribute model, only have type name.
- case { MarshallingAttributeInfo: GeneratedNativeMarshallingAttributeInfo(string nativeTypeName) }:
- return Forwarder;
-
- // Cases that just match on type must come after the checks that match only on marshalling attribute info.
- // The checks below do not account for generic marshalling overrides like [MarshalUsing], so those checks must come first.
- case { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Char } }:
- return CreateCharMarshaller(info, context);
-
- case { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_String } }:
- return CreateStringMarshaller(info, context);
-
- case { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Void } }:
- return Forwarder;
-
- default:
- throw new MarshallingNotSupportedException(info, context);
- }
- }
-
- private static IMarshallingGenerator CreateCharMarshaller(TypePositionInfo info, StubCodeContext context)
- {
- MarshallingInfo marshalInfo = info.MarshallingAttributeInfo;
- if (marshalInfo is NoMarshallingInfo)
- {
- // [Compat] Require explicit marshalling information.
- throw new MarshallingNotSupportedException(info, context)
- {
- NotSupportedDetails = Resources.MarshallingStringOrCharAsUndefinedNotSupported
- };
- }
-
- // Explicit MarshalAs takes precedence over string encoding info
- if (marshalInfo is MarshalAsInfo marshalAsInfo)
- {
- switch (marshalAsInfo.UnmanagedType)
- {
- case UnmanagedType.I2:
- case UnmanagedType.U2:
- return Utf16Char;
- }
- }
- else if (marshalInfo is MarshallingInfoStringSupport marshalStringInfo)
- {
- switch (marshalStringInfo.CharEncoding)
- {
- case CharEncoding.Utf16:
- return Utf16Char;
- case CharEncoding.Ansi:
- throw new MarshallingNotSupportedException(info, context) // [Compat] ANSI is not supported for char
- {
- NotSupportedDetails = string.Format(Resources.MarshallingCharAsSpecifiedCharSetNotSupported, CharSet.Ansi)
- };
- case CharEncoding.PlatformDefined:
- throw new MarshallingNotSupportedException(info, context) // [Compat] See conversion of CharSet.Auto.
- {
- NotSupportedDetails = string.Format(Resources.MarshallingCharAsSpecifiedCharSetNotSupported, CharSet.Auto)
- };
- }
- }
-
- throw new MarshallingNotSupportedException(info, context);
- }
-
- private static IMarshallingGenerator CreateStringMarshaller(TypePositionInfo info, StubCodeContext context)
- {
- MarshallingInfo marshalInfo = info.MarshallingAttributeInfo;
- if (marshalInfo is NoMarshallingInfo)
- {
- // [Compat] Require explicit marshalling information.
- throw new MarshallingNotSupportedException(info, context)
- {
- NotSupportedDetails = Resources.MarshallingStringOrCharAsUndefinedNotSupported
- };
- }
-
- // Explicit MarshalAs takes precedence over string encoding info
- if (marshalInfo is MarshalAsInfo marshalAsInfo)
- {
- switch (marshalAsInfo.UnmanagedType)
- {
- case UnmanagedType.LPStr:
- return AnsiString;
- case UnmanagedType.LPTStr:
- case UnmanagedType.LPWStr:
- return Utf16String;
- case (UnmanagedType)0x30:// UnmanagedType.LPUTF8Str
- return Utf8String;
- }
- }
- else if (marshalInfo is MarshallingInfoStringSupport marshalStringInfo)
- {
- switch (marshalStringInfo.CharEncoding)
- {
- case CharEncoding.Ansi:
- return AnsiString;
- case CharEncoding.Utf16:
- return Utf16String;
- case CharEncoding.Utf8:
- return Utf8String;
- case CharEncoding.PlatformDefined:
- return PlatformDefinedString;
- }
- }
-
- throw new MarshallingNotSupportedException(info, context);
- }
-
- private static ExpressionSyntax GetNumElementsExpressionFromMarshallingInfo(TypePositionInfo info, CountInfo count, StubCodeContext context)
- {
- return count switch
- {
- SizeAndParamIndexInfo(int size, SizeAndParamIndexInfo.UnspecifiedParam) => GetConstSizeExpression(size),
- ConstSizeCountInfo(int size) => GetConstSizeExpression(size),
- SizeAndParamIndexInfo(SizeAndParamIndexInfo.UnspecifiedConstSize, TypePositionInfo param) => CheckedExpression(SyntaxKind.CheckedExpression, GetExpressionForParam(param)),
- SizeAndParamIndexInfo(int size, TypePositionInfo param) => CheckedExpression(SyntaxKind.CheckedExpression, BinaryExpression(SyntaxKind.AddExpression, GetConstSizeExpression(size), GetExpressionForParam(param))),
- CountElementCountInfo(TypePositionInfo elementInfo) => CheckedExpression(SyntaxKind.CheckedExpression, GetExpressionForParam(elementInfo)),
- _ => throw new MarshallingNotSupportedException(info, context)
- {
- NotSupportedDetails = Resources.ArraySizeMustBeSpecified
- },
- };
-
- static LiteralExpressionSyntax GetConstSizeExpression(int size)
- {
- return LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(size));
- }
-
- ExpressionSyntax GetExpressionForParam(TypePositionInfo paramInfo)
- {
- ExpressionSyntax numElementsExpression = GetIndexedNumElementsExpression(
- context,
- paramInfo,
- out int numIndirectionLevels);
-
- ManagedTypeInfo type = paramInfo.ManagedType;
- MarshallingInfo marshallingInfo = paramInfo.MarshallingAttributeInfo;
-
- for (int i = 0; i < numIndirectionLevels; i++)
- {
- if (marshallingInfo is NativeContiguousCollectionMarshallingInfo collectionInfo)
- {
- type = collectionInfo.ElementType;
- marshallingInfo = collectionInfo.ElementMarshallingInfo;
- }
- else
- {
- throw new MarshallingNotSupportedException(info, context)
- {
- NotSupportedDetails = Resources.CollectionSizeParamTypeMustBeIntegral
- };
- }
- }
-
- if (type is not SpecialTypeInfo specialType || !specialType.SpecialType.IsIntegralType())
- {
- throw new MarshallingNotSupportedException(info, context)
- {
- NotSupportedDetails = Resources.CollectionSizeParamTypeMustBeIntegral
- };
- }
-
- return CastExpression(
- PredefinedType(Token(SyntaxKind.IntKeyword)),
- ParenthesizedExpression(numElementsExpression));
- }
-
- static ExpressionSyntax GetIndexedNumElementsExpression(StubCodeContext context, TypePositionInfo numElementsInfo, out int numIndirectionLevels)
- {
- Stack indexerStack = new();
-
- StubCodeContext? currentContext = context;
- StubCodeContext lastContext = null!;
-
- while (currentContext is not null)
- {
- if (currentContext is ContiguousCollectionElementMarshallingCodeContext collectionContext)
- {
- indexerStack.Push(collectionContext.IndexerIdentifier);
- }
- lastContext = currentContext;
- currentContext = currentContext.ParentContext;
- }
-
- numIndirectionLevels = indexerStack.Count;
-
- ExpressionSyntax indexedNumElements = IdentifierName(lastContext.GetIdentifiers(numElementsInfo).managed);
- while (indexerStack.Count > 0)
- {
- NameSyntax indexer = IdentifierName(indexerStack.Pop());
- indexedNumElements = ElementAccessExpression(indexedNumElements)
- .AddArgumentListArguments(Argument(indexer));
- }
-
- return indexedNumElements;
- }
- }
-
- private static IMarshallingGenerator CreateCustomNativeTypeMarshaller(TypePositionInfo info, StubCodeContext context, NativeMarshallingAttributeInfo marshalInfo, AnalyzerConfigOptions options)
- {
- ValidateCustomNativeTypeMarshallingSupported(info, context, marshalInfo);
-
- ICustomNativeTypeMarshallingStrategy marshallingStrategy = new SimpleCustomNativeTypeMarshalling(marshalInfo.NativeMarshallingType.Syntax);
-
- if ((marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedToNativeStackalloc) != 0)
- {
- marshallingStrategy = new StackallocOptimizationMarshalling(marshallingStrategy);
- }
-
- if ((marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.FreeNativeResources) != 0)
- {
- marshallingStrategy = new FreeNativeCleanupStrategy(marshallingStrategy);
- }
-
- // Collections have extra configuration, so handle them here.
- if (marshalInfo is NativeContiguousCollectionMarshallingInfo collectionMarshallingInfo)
- {
- return CreateNativeCollectionMarshaller(info, context, collectionMarshallingInfo, options, marshallingStrategy);
- }
-
- if (marshalInfo.ValuePropertyType is not null)
- {
- marshallingStrategy = DecorateWithValuePropertyStrategy(marshalInfo, marshallingStrategy);
- }
-
- IMarshallingGenerator marshallingGenerator = new CustomNativeTypeMarshallingGenerator(marshallingStrategy, enableByValueContentsMarshalling: false);
-
- if ((marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedTypePinning) != 0)
- {
- return new PinnableManagedValueMarshaller(marshallingGenerator);
- }
-
- return marshallingGenerator;
- }
-
- private static void ValidateCustomNativeTypeMarshallingSupported(TypePositionInfo info, StubCodeContext context, NativeMarshallingAttributeInfo marshalInfo)
- {
- // The marshalling method for this type doesn't support marshalling from native to managed,
- // but our scenario requires marshalling from native to managed.
- if ((info.RefKind == RefKind.Ref || info.RefKind == RefKind.Out || info.IsManagedReturnPosition)
- && (marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.NativeToManaged) == 0)
- {
- throw new MarshallingNotSupportedException(info, context)
- {
- NotSupportedDetails = string.Format(Resources.CustomTypeMarshallingNativeToManagedUnsupported, marshalInfo.NativeMarshallingType.FullTypeName)
- };
- }
- // The marshalling method for this type doesn't support marshalling from managed to native by value,
- // but our scenario requires marshalling from managed to native by value.
- else if (!info.IsByRef
- && (marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedToNative) == 0
- && (context.SingleFrameSpansNativeContext && (marshalInfo.MarshallingFeatures & (CustomMarshallingFeatures.ManagedTypePinning | CustomMarshallingFeatures.ManagedToNativeStackalloc)) == 0))
- {
- throw new MarshallingNotSupportedException(info, context)
- {
- NotSupportedDetails = string.Format(Resources.CustomTypeMarshallingManagedToNativeUnsupported, marshalInfo.NativeMarshallingType.FullTypeName)
- };
- }
- // The marshalling method for this type doesn't support marshalling from managed to native by reference,
- // but our scenario requires marshalling from managed to native by reference.
- // "in" byref supports stack marshalling.
- else if (info.RefKind == RefKind.In
- && (marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedToNative) == 0
- && !(context.SingleFrameSpansNativeContext && (marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedToNativeStackalloc) != 0))
- {
- throw new MarshallingNotSupportedException(info, context)
- {
- NotSupportedDetails = string.Format(Resources.CustomTypeMarshallingManagedToNativeUnsupported, marshalInfo.NativeMarshallingType.FullTypeName)
- };
- }
- // The marshalling method for this type doesn't support marshalling from managed to native by reference,
- // but our scenario requires marshalling from managed to native by reference.
- // "ref" byref marshalling doesn't support stack marshalling
- else if (info.RefKind == RefKind.Ref
- && (marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedToNative) == 0)
- {
- throw new MarshallingNotSupportedException(info, context)
- {
- NotSupportedDetails = string.Format(Resources.CustomTypeMarshallingManagedToNativeUnsupported, marshalInfo.NativeMarshallingType.FullTypeName)
- };
- }
- }
-
- private static ICustomNativeTypeMarshallingStrategy DecorateWithValuePropertyStrategy(NativeMarshallingAttributeInfo marshalInfo, ICustomNativeTypeMarshallingStrategy nativeTypeMarshaller)
- {
- TypeSyntax valuePropertyTypeSyntax = marshalInfo.ValuePropertyType!.Syntax;
-
- if ((marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.NativeTypePinning) != 0)
- {
- return new PinnableMarshallerTypeMarshalling(nativeTypeMarshaller, valuePropertyTypeSyntax);
- }
-
- return new CustomNativeTypeWithValuePropertyMarshalling(nativeTypeMarshaller, valuePropertyTypeSyntax);
- }
-
- private static IMarshallingGenerator CreateNativeCollectionMarshaller(
- TypePositionInfo info,
- StubCodeContext context,
- NativeContiguousCollectionMarshallingInfo collectionInfo,
- AnalyzerConfigOptions options,
- ICustomNativeTypeMarshallingStrategy marshallingStrategy)
- {
- var elementInfo = new TypePositionInfo(collectionInfo.ElementType, collectionInfo.ElementMarshallingInfo) { ManagedIndex = info.ManagedIndex };
- var elementMarshaller = Create(
- elementInfo,
- new ContiguousCollectionElementMarshallingCodeContext(StubCodeContext.Stage.Setup, string.Empty, context),
- options);
- var elementType = elementMarshaller.AsNativeType(elementInfo);
-
- bool isBlittable = elementMarshaller == Blittable;
-
- if (isBlittable)
- {
- marshallingStrategy = new ContiguousBlittableElementCollectionMarshalling(marshallingStrategy, collectionInfo.ElementType.Syntax);
- }
- else
- {
- marshallingStrategy = new ContiguousNonBlittableElementCollectionMarshalling(marshallingStrategy, elementMarshaller, elementInfo);
- }
-
- // Explicitly insert the Value property handling here (before numElements handling) so that the numElements handling will be emitted before the Value property handling in unmarshalling.
- if (collectionInfo.ValuePropertyType is not null)
- {
- marshallingStrategy = DecorateWithValuePropertyStrategy(collectionInfo, marshallingStrategy);
- }
-
- ExpressionSyntax numElementsExpression = LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(0));
- if (info.IsManagedReturnPosition || (info.IsByRef && info.RefKind != RefKind.In))
- {
- // In this case, we need a numElementsExpression supplied from metadata, so we'll calculate it here.
- numElementsExpression = GetNumElementsExpressionFromMarshallingInfo(info, collectionInfo.ElementCountInfo, context);
- }
-
- marshallingStrategy = new NumElementsExpressionMarshalling(
- marshallingStrategy,
- numElementsExpression,
- SizeOfExpression(elementType));
-
- if (collectionInfo.UseDefaultMarshalling && info.ManagedType is SzArrayType)
- {
- return new ArrayMarshaller(
- new CustomNativeTypeMarshallingGenerator(marshallingStrategy, enableByValueContentsMarshalling: true),
- elementType,
- isBlittable,
- options);
- }
-
- IMarshallingGenerator marshallingGenerator = new CustomNativeTypeMarshallingGenerator(marshallingStrategy, enableByValueContentsMarshalling: false);
-
- if ((collectionInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedTypePinning) != 0)
- {
- return new PinnableManagedValueMarshaller(marshallingGenerator);
- }
-
- return marshallingGenerator;
- }
- }
-}
diff --git a/DllImportGenerator/DllImportGenerator/NoPreserveSigMarshallingGeneratorFactory.cs b/DllImportGenerator/DllImportGenerator/NoPreserveSigMarshallingGeneratorFactory.cs
new file mode 100644
index 000000000000..1e8ae0159e45
--- /dev/null
+++ b/DllImportGenerator/DllImportGenerator/NoPreserveSigMarshallingGeneratorFactory.cs
@@ -0,0 +1,30 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Microsoft.Interop
+{
+ class NoPreserveSigMarshallingGeneratorFactory : IMarshallingGeneratorFactory
+ {
+ private static readonly HResultExceptionMarshaller HResultException = new HResultExceptionMarshaller();
+ private readonly IMarshallingGeneratorFactory inner;
+
+ public NoPreserveSigMarshallingGeneratorFactory(IMarshallingGeneratorFactory inner)
+ {
+ this.inner = inner;
+ }
+
+ public IMarshallingGenerator Create(TypePositionInfo info, StubCodeContext context)
+ {
+ if (info.IsNativeReturnPosition && !info.IsManagedReturnPosition)
+ {
+ // Use marshaller for native HRESULT return / exception throwing
+ System.Diagnostics.Debug.Assert(info.ManagedType.Equals(SpecialTypeInfo.Int32));
+ return HResultException;
+ }
+ return inner.Create(info, context);
+ }
+ }
+}
diff --git a/DllImportGenerator/DllImportGenerator/StubCodeGenerator.cs b/DllImportGenerator/DllImportGenerator/PInvokeStubCodeGenerator.cs
similarity index 71%
rename from DllImportGenerator/DllImportGenerator/StubCodeGenerator.cs
rename to DllImportGenerator/DllImportGenerator/PInvokeStubCodeGenerator.cs
index 2732414adc42..a7ecd31f8e45 100644
--- a/DllImportGenerator/DllImportGenerator/StubCodeGenerator.cs
+++ b/DllImportGenerator/DllImportGenerator/PInvokeStubCodeGenerator.cs
@@ -7,13 +7,26 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.Diagnostics;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
using static Microsoft.Interop.StubCodeContext;
namespace Microsoft.Interop
{
- internal sealed class StubCodeGenerator : StubCodeContext
+ ///
+ /// Base code generator for generating the body of a source-generated P/Invoke and providing customization for how to invoke/define the native method.
+ ///
+ ///
+ /// This type enables multiple code generators for P/Invoke-style marshalling
+ /// to reuse the same basic method body, but with different designs of how to emit the target native method.
+ /// This enables users to write code generators that work with slightly different semantics.
+ /// For example, the source generator for [GeneratedDllImport] emits the target P/Invoke as
+ /// a local function inside the generated stub body.
+ /// However, other managed-to-native code generators using a P/Invoke style might want to define
+ /// the target DllImport outside of the stub as a static non-local function or as a function pointer field.
+ /// This refactoring allows the code generator to have control over where the target method is declared
+ /// and how it is declared.
+ ///
+ internal sealed class PInvokeStubCodeGenerator : StubCodeContext
{
private record struct BoundGenerator(TypePositionInfo TypeInfo, IMarshallingGenerator Generator);
@@ -39,21 +52,19 @@ private record struct BoundGenerator(TypePositionInfo TypeInfo, IMarshallingGene
// Error code representing success. This maps to S_OK for Windows HRESULT semantics and 0 for POSIX errno semantics.
private const int SuccessErrorCode = 0;
- private readonly AnalyzerConfigOptions options;
- private readonly GeneratedDllImportData dllImportData;
+ private readonly bool setLastError;
private readonly List paramMarshallers;
private readonly BoundGenerator retMarshaller;
private readonly List sortedMarshallers;
private readonly bool stubReturnsVoid;
- public StubCodeGenerator(
- GeneratedDllImportData dllImportData,
+ public PInvokeStubCodeGenerator(
IEnumerable argTypes,
- AnalyzerConfigOptions options,
- Action marshallingNotSupportedCallback)
+ bool setLastError,
+ Action marshallingNotSupportedCallback,
+ IMarshallingGeneratorFactory generatorFactory)
{
- this.dllImportData = dllImportData;
- this.options = options;
+ this.setLastError = setLastError;
List allMarshallers = new();
List paramMarshallers = new();
@@ -156,12 +167,12 @@ BoundGenerator CreateGenerator(TypePositionInfo p)
{
try
{
- return new BoundGenerator(p, MarshallingGenerators.Create(p, this, options));
+ return new BoundGenerator(p, generatorFactory.Create(p, this));
}
catch (MarshallingNotSupportedException e)
{
marshallingNotSupportedCallback(p, e);
- return new BoundGenerator(p, MarshallingGenerators.Forwarder);
+ return new BoundGenerator(p, new Forwarder());
}
}
}
@@ -196,9 +207,8 @@ public override (string managed, string native) GetIdentifiers(TypePositionInfo
}
}
- public BlockSyntax GenerateBody(string methodName, AttributeListSyntax? forwardedAttributes)
+ public BlockSyntax GeneratePInvokeBody(string dllImportName)
{
- string dllImportName = methodName + "__PInvoke__";
var setupStatements = new List();
foreach (var marshaller in paramMarshallers)
@@ -228,9 +238,6 @@ public BlockSyntax GenerateBody(string methodName, AttributeListSyntax? forwarde
// Stub return is not the same as invoke return
if (!stubReturnsVoid && !retMarshaller.TypeInfo.IsManagedReturnPosition)
{
- // Should only happen when PreserveSig=false
- Debug.Assert(!dllImportData.PreserveSig, "Expected PreserveSig=false when invoke return is not the stub return");
-
// Stub return should be the last parameter for the invoke
Debug.Assert(paramMarshallers.Any() && paramMarshallers.Last().TypeInfo.IsManagedReturnPosition, "Expected stub return to be the last parameter for the invoke");
@@ -248,7 +255,7 @@ public BlockSyntax GenerateBody(string methodName, AttributeListSyntax? forwarde
// Do not manually handle SetLastError when generating forwarders.
// We want the runtime to handle everything.
- if (this.dllImportData.SetLastError && !options.GenerateForwarders())
+ if (this.setLastError)
{
// Declare variable for last error
setupStatements.Add(MarshallerHelpers.DeclareWithDefault(
@@ -294,7 +301,7 @@ public BlockSyntax GenerateBody(string methodName, AttributeListSyntax? forwarde
allStatements.AddRange(tryStatements);
}
- if (this.dllImportData.SetLastError && !options.GenerateForwarders())
+ if (this.setLastError)
{
// Marshal.SetLastPInvokeError();
allStatements.Add(ExpressionStatement(
@@ -312,40 +319,7 @@ public BlockSyntax GenerateBody(string methodName, AttributeListSyntax? forwarde
allStatements.Add(ReturnStatement(IdentifierName(ReturnIdentifier)));
// Wrap all statements in an unsafe block
- var codeBlock = Block(UnsafeStatement(Block(allStatements)));
-
- // Define P/Invoke declaration
- var dllImport = LocalFunctionStatement(retMarshaller.Generator.AsNativeType(retMarshaller.TypeInfo), dllImportName)
- .AddModifiers(
- Token(SyntaxKind.ExternKeyword),
- Token(SyntaxKind.StaticKeyword),
- Token(SyntaxKind.UnsafeKeyword))
- .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))
- .WithAttributeLists(
- SingletonList(AttributeList(
- SingletonSeparatedList(CreateDllImportAttributeForTarget(GetTargetDllImportDataFromStubData(methodName))))));
-
- if (retMarshaller.Generator is IAttributedReturnTypeMarshallingGenerator retGenerator)
- {
- AttributeListSyntax? returnAttribute = retGenerator.GenerateAttributesForReturnType(retMarshaller.TypeInfo);
- if (returnAttribute is not null)
- {
- dllImport = dllImport.AddAttributeLists(returnAttribute.WithTarget(AttributeTargetSpecifier(Identifier("return"))));
- }
- }
-
- if (forwardedAttributes is not null)
- {
- dllImport = dllImport.AddAttributeLists(forwardedAttributes);
- }
-
- foreach (var marshaller in paramMarshallers)
- {
- ParameterSyntax paramSyntax = marshaller.Generator.AsParameter(marshaller.TypeInfo);
- dllImport = dllImport.AddParameterListParameters(paramSyntax);
- }
-
- return codeBlock.AddStatements(dllImport);
+ return Block(UnsafeStatement(Block(allStatements)));
void GenerateStatementsForStage(Stage stage, List statementsToUpdate)
{
@@ -435,7 +409,7 @@ void GenerateStatementsForInvoke(List statementsToUpdate, Invoc
// Do not manually handle SetLastError when generating forwarders.
// We want the runtime to handle everything.
- if (this.dllImportData.SetLastError && !options.GenerateForwarders())
+ if (setLastError)
{
// Marshal.SetLastSystemError(0);
var clearLastError = ExpressionStatement(
@@ -482,6 +456,19 @@ void GenerateStatementsForInvoke(List statementsToUpdate, Invoc
}
}
+ public (ParameterListSyntax ParameterList, TypeSyntax ReturnType, AttributeListSyntax? ReturnTypeAttributes) GenerateTargetMethodSignatureData()
+ {
+ return (
+ ParameterList(
+ SeparatedList(
+ paramMarshallers.Select(marshaler => marshaler.Generator.AsParameter(marshaler.TypeInfo)))),
+ retMarshaller.Generator.AsNativeType(retMarshaller.TypeInfo),
+ retMarshaller.Generator is IAttributedReturnTypeMarshallingGenerator attributedReturn
+ ? attributedReturn.GenerateAttributesForReturnType(retMarshaller.TypeInfo)
+ : null
+ );
+ }
+
private void AppendVariableDeclations(List statementsToUpdate, TypePositionInfo info, IMarshallingGenerator generator)
{
var (managed, native) = this.GetIdentifiers(info);
@@ -502,123 +489,5 @@ private void AppendVariableDeclations(List statementsToUpdate,
native));
}
}
-
- private static AttributeSyntax CreateDllImportAttributeForTarget(GeneratedDllImportData targetDllImportData)
- {
- Debug.Assert(targetDllImportData.EntryPoint is not null);
- var newAttributeArgs = new List
- {
- AttributeArgument(LiteralExpression(
- SyntaxKind.StringLiteralExpression,
- Literal(targetDllImportData.ModuleName))),
- AttributeArgument(
- NameEquals(nameof(DllImportAttribute.EntryPoint)),
- null,
- CreateStringExpressionSyntax(targetDllImportData.EntryPoint!))
- };
-
- if (targetDllImportData.IsUserDefined.HasFlag(DllImportMember.BestFitMapping))
- {
- var name = NameEquals(nameof(DllImportAttribute.BestFitMapping));
- var value = CreateBoolExpressionSyntax(targetDllImportData.BestFitMapping);
- newAttributeArgs.Add(AttributeArgument(name, null, value));
- }
- if (targetDllImportData.IsUserDefined.HasFlag(DllImportMember.CallingConvention))
- {
- var name = NameEquals(nameof(DllImportAttribute.CallingConvention));
- var value = CreateEnumExpressionSyntax(targetDllImportData.CallingConvention);
- newAttributeArgs.Add(AttributeArgument(name, null, value));
- }
- if (targetDllImportData.IsUserDefined.HasFlag(DllImportMember.CharSet))
- {
- var name = NameEquals(nameof(DllImportAttribute.CharSet));
- var value = CreateEnumExpressionSyntax(targetDllImportData.CharSet);
- newAttributeArgs.Add(AttributeArgument(name, null, value));
- }
- if (targetDllImportData.IsUserDefined.HasFlag(DllImportMember.ExactSpelling))
- {
- var name = NameEquals(nameof(DllImportAttribute.ExactSpelling));
- var value = CreateBoolExpressionSyntax(targetDllImportData.ExactSpelling);
- newAttributeArgs.Add(AttributeArgument(name, null, value));
- }
- if (targetDllImportData.IsUserDefined.HasFlag(DllImportMember.PreserveSig))
- {
- var name = NameEquals(nameof(DllImportAttribute.PreserveSig));
- var value = CreateBoolExpressionSyntax(targetDllImportData.PreserveSig);
- newAttributeArgs.Add(AttributeArgument(name, null, value));
- }
- if (targetDllImportData.IsUserDefined.HasFlag(DllImportMember.SetLastError))
- {
- var name = NameEquals(nameof(DllImportAttribute.SetLastError));
- var value = CreateBoolExpressionSyntax(targetDllImportData.SetLastError);
- newAttributeArgs.Add(AttributeArgument(name, null, value));
- }
- if (targetDllImportData.IsUserDefined.HasFlag(DllImportMember.ThrowOnUnmappableChar))
- {
- var name = NameEquals(nameof(DllImportAttribute.ThrowOnUnmappableChar));
- var value = CreateBoolExpressionSyntax(targetDllImportData.ThrowOnUnmappableChar);
- newAttributeArgs.Add(AttributeArgument(name, null, value));
- }
-
- // Create new attribute
- return Attribute(
- ParseName(typeof(DllImportAttribute).FullName),
- AttributeArgumentList(SeparatedList(newAttributeArgs)));
-
- static ExpressionSyntax CreateBoolExpressionSyntax(bool trueOrFalse)
- {
- return LiteralExpression(
- trueOrFalse
- ? SyntaxKind.TrueLiteralExpression
- : SyntaxKind.FalseLiteralExpression);
- }
-
- static ExpressionSyntax CreateStringExpressionSyntax(string str)
- {
- return LiteralExpression(
- SyntaxKind.StringLiteralExpression,
- Literal(str));
- }
-
- static ExpressionSyntax CreateEnumExpressionSyntax(T value) where T : Enum
- {
- return MemberAccessExpression(
- SyntaxKind.SimpleMemberAccessExpression,
- IdentifierName(typeof(T).FullName),
- IdentifierName(value.ToString()));
- }
- }
-
- GeneratedDllImportData GetTargetDllImportDataFromStubData(string methodName)
- {
- DllImportMember membersToForward = DllImportMember.All
- // https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.dllimportattribute.preservesig
- // If PreserveSig=false (default is true), the P/Invoke stub checks/converts a returned HRESULT to an exception.
- & ~DllImportMember.PreserveSig
- // https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.dllimportattribute.setlasterror
- // If SetLastError=true (default is false), the P/Invoke stub gets/caches the last error after invoking the native function.
- & ~DllImportMember.SetLastError;
- if (options.GenerateForwarders())
- {
- membersToForward = DllImportMember.All;
- }
-
- var targetDllImportData = dllImportData with
- {
- IsUserDefined = dllImportData.IsUserDefined & membersToForward
- };
-
- // If the EntryPoint property is not set, we will compute and
- // add it based on existing semantics (i.e. method name).
- //
- // N.B. The export discovery logic is identical regardless of where
- // the name is defined (i.e. method name vs EntryPoint property).
- if (!targetDllImportData.IsUserDefined.HasFlag(DllImportMember.EntryPoint))
- {
- targetDllImportData = targetDllImportData with { EntryPoint = methodName };
- }
-
- return targetDllImportData;
- }
}
}
diff --git a/DllImportGenerator/DllImportGenerator/Resources.Designer.cs b/DllImportGenerator/DllImportGenerator/Resources.Designer.cs
index d43d6c82b3bd..eb6bfa6e52e0 100644
--- a/DllImportGenerator/DllImportGenerator/Resources.Designer.cs
+++ b/DllImportGenerator/DllImportGenerator/Resources.Designer.cs
@@ -19,7 +19,7 @@ namespace Microsoft.Interop {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
@@ -60,15 +60,6 @@ internal Resources() {
}
}
- ///
- /// Looks up a localized string similar to Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'..
- ///
- internal static string ArraySizeMustBeSpecified {
- get {
- return ResourceManager.GetString("ArraySizeMustBeSpecified", resourceCulture);
- }
- }
-
///
/// Looks up a localized string similar to A type marked with 'BlittableTypeAttribute' must be blittable..
///
@@ -123,15 +114,6 @@ internal static string CollectionNativeTypeMustHaveRequiredShapeMessage {
}
}
- ///
- /// Looks up a localized string similar to The specified collection size parameter for an collection must be an integer type. If the size information is applied to a nested collection, the size parameter must be a collection of one less level of nesting with an integral element..
- ///
- internal static string CollectionSizeParamTypeMustBeIntegral {
- get {
- return ResourceManager.GetString("CollectionSizeParamTypeMustBeIntegral", resourceCulture);
- }
- }
-
///
/// Looks up a localized string similar to Source-generated P/Invokes will ignore any configuration that is not supported..
///
@@ -151,7 +133,7 @@ internal static string ConfigurationNotSupportedMessage {
}
///
- /// Looks up a localized string similar to The specified marshalling configuration is not supported by source-generated P/Invokes. {0}.
+ /// Looks up a localized string similar to The specified marshalling configuration is not supported by source-generated P/Invokes. {0}..
///
internal static string ConfigurationNotSupportedMessageMarshallingInfo {
get {
@@ -276,42 +258,6 @@ internal static string CustomTypeMarshallingNativeToManagedUnsupported {
}
}
- ///
- /// Looks up a localized string similar to This element cannot depend on '{0}' for collection size information without creating a dependency cycle.
- ///
- internal static string CyclicalCountInfo {
- get {
- return ResourceManager.GetString("CyclicalCountInfo", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Count information for a given element at a given indirection level can only be specified once.
- ///
- internal static string DuplicateCountInfo {
- get {
- return ResourceManager.GetString("DuplicateCountInfo", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Multiple marshalling attributes per element per indirection level is unsupported, but duplicate information was provided for indirection level {0}.
- ///
- internal static string DuplicateMarshallingInfo {
- get {
- return ResourceManager.GetString("DuplicateMarshallingInfo", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Marshalling info was specified for 'ElementIndirectionLevel' {0}, but marshalling info was only needed for {1} levels of indirection.
- ///
- internal static string ExtraneousMarshallingInfo {
- get {
- return ResourceManager.GetString("ExtraneousMarshallingInfo", resourceCulture);
- }
- }
-
///
/// Looks up a localized string similar to Types that contain methods marked with 'GeneratedDllImportAttribute' must be 'partial'. P/Invoke source generation will ignore methods contained within non-partial types..
///
@@ -403,56 +349,11 @@ internal static string GetPinnableReferenceShouldSupportAllocatingMarshallingFal
}
///
- /// Looks up a localized string similar to The provided graph has cycles and cannot be topologically sorted..
- ///
- internal static string GraphHasCycles {
- get {
- return ResourceManager.GetString("GraphHasCycles", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to The '[In]' attribute is not supported unless the '[Out]' attribute is also used. The behavior of the '[In]' attribute without the '[Out]' attribute is the same as the default behavior..
- ///
- internal static string InAttributeNotSupportedWithoutOut {
- get {
- return ResourceManager.GetString("InAttributeNotSupportedWithoutOut", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to The '[In]' and '[Out]' attributes are unsupported on parameters passed by reference. Use the 'in', 'ref', or 'out' keywords instead..
- ///
- internal static string InOutAttributeByRefNotSupported {
- get {
- return ResourceManager.GetString("InOutAttributeByRefNotSupported", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to The provided '[In]' and '[Out]' attributes on this parameter are unsupported on this parameter..
+ /// Looks up a localized string similar to The native type '{0}' must be a closed generic so the emitted code can use a specific instantiation..
///
- internal static string InOutAttributeMarshalerNotSupported {
+ internal static string NativeGenericTypeMustBeClosedDescription {
get {
- return ResourceManager.GetString("InOutAttributeMarshalerNotSupported", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Marshalling char with 'CharSet.{0}' is not supported. Instead, manually convert the char type to the desired byte representation and pass to the source-generated P/Invoke..
- ///
- internal static string MarshallingCharAsSpecifiedCharSetNotSupported {
- get {
- return ResourceManager.GetString("MarshallingCharAsSpecifiedCharSetNotSupported", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Marshalling string or char without explicit marshalling information is not supported. Specify either 'GeneratedDllImportAttribute.CharSet' or 'MarshalAsAttribute'..
- ///
- internal static string MarshallingStringOrCharAsUndefinedNotSupported {
- get {
- return ResourceManager.GetString("MarshallingStringOrCharAsUndefinedNotSupported", resourceCulture);
+ return ResourceManager.GetString("NativeGenericTypeMustBeClosedDescription", resourceCulture);
}
}
@@ -546,24 +447,6 @@ internal static string NativeTypeMustHaveRequiredShapeMessage {
}
}
- ///
- /// Looks up a localized string similar to The '[Out]' attribute is only supported on array parameters..
- ///
- internal static string OutByValueNotSupportedDescription {
- get {
- return ResourceManager.GetString("OutByValueNotSupportedDescription", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to The '[Out]' attribute is not supported on the '{0}' parameter..
- ///
- internal static string OutByValueNotSupportedMessage {
- get {
- return ResourceManager.GetString("OutByValueNotSupportedMessage", resourceCulture);
- }
- }
-
///
/// Looks up a localized string similar to The 'Value' property must not be a 'ref' or 'readonly ref' property..
///
diff --git a/DllImportGenerator/DllImportGenerator/Resources.resx b/DllImportGenerator/DllImportGenerator/Resources.resx
index d2d2adeffc2c..3124872bc317 100644
--- a/DllImportGenerator/DllImportGenerator/Resources.resx
+++ b/DllImportGenerator/DllImportGenerator/Resources.resx
@@ -117,9 +117,6 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
- Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.
-
A type marked with 'BlittableTypeAttribute' must be blittable.
@@ -132,8 +129,11 @@
Type '{0}' is marked with 'BlittableTypeAttribute' and 'NativeMarshallingAttribute'. A type can only have one of these two attributes.
-
- The specified collection size parameter for an collection must be an integer type. If the size information is applied to a nested collection, the size parameter must be a collection of one less level of nesting with an integral element.
+
+ A native type with the 'GenericContiguousCollectionMarshallerAttribute' must have at least one of the two marshalling methods as well as a 'ManagedValues' property of type 'Span<T>' for some 'T' and a 'NativeValueStorage' property of type 'Span<byte>' to enable marshalling the managed type.
+
+
+ The native type '{0}' must be a value type and have a constructor that takes two parameters, one of type '{1}' and an 'int', or have a parameterless instance method named 'ToManaged' that returns '{1}' as well as a 'ManagedValues' property of type 'Span<T>' for some 'T' and a 'NativeValueStorage' property of type 'Span<byte>'
Source-generated P/Invokes will ignore any configuration that is not supported.
@@ -184,18 +184,6 @@
The specified parameter needs to be marshalled from native to managed, but the native type '{0}' does not support it.
-
- This element cannot depend on '{0}' for collection size information without creating a dependency cycle
-
-
- Count information for a given element at a given indirection level can only be specified once
-
-
- Multiple marshalling attributes per element per indirection level is unsupported, but duplicate information was provided for indirection level {0}
-
-
- Marshalling info was specified for 'ElementIndirectionLevel' {0}, but marshalling info was only needed for {1} level(s) of indirection
-
Types that contain methods marked with 'GeneratedDllImportAttribute' must be 'partial'. P/Invoke source generation will ignore methods contained within non-partial types.
@@ -226,23 +214,8 @@
Type '{0}' has a 'GetPinnableReference' method but its native type does not support marshalling in scenarios where pinning is impossible
-
- The provided graph has cycles and cannot be topologically sorted.
-
-
- The '[In]' attribute is not supported unless the '[Out]' attribute is also used. The behavior of the '[In]' attribute without the '[Out]' attribute is the same as the default behavior.
-
-
- The '[In]' and '[Out]' attributes are unsupported on parameters passed by reference. Use the 'in', 'ref', or 'out' keywords instead.
-
-
- The provided '[In]' and '[Out]' attributes on this parameter are unsupported on this parameter.
-
-
- Marshalling char with 'CharSet.{0}' is not supported. Instead, manually convert the char type to the desired byte representation and pass to the source-generated P/Invoke.
-
-
- Marshalling string or char without explicit marshalling information is not supported. Specify either 'GeneratedDllImportAttribute.CharSet' or 'MarshalAsAttribute'.
+
+ The native type '{0}' must be a closed generic so the emitted code can use a specific instantiation.
The native type '{0}' must be a closed generic or have the same number of generic parameters as the managed type so the emitted code can use a specific instantiation.
@@ -274,18 +247,6 @@
The native type '{0}' must be a value type and have a constructor that takes one parameter of type '{1}' or a parameterless instance method named 'ToManaged' that returns '{1}'
-
- A native type with the 'GenericContiguousCollectionMarshallerAttribute' must have at least one of the two marshalling methods as well as a 'ManagedValues' property of type 'Span<T>' for some 'T' and a 'NativeValueStorage' property of type 'Span<byte>' to enable marshalling the managed type.
-
-
- The native type '{0}' must be a value type and have a constructor that takes two parameters, one of type '{1}' and an 'int', or have a parameterless instance method named 'ToManaged' that returns '{1}' as well as a 'ManagedValues' property of type 'Span<T>' for some 'T' and a 'NativeValueStorage' property of type 'Span<byte>'
-
-
- The '[Out]' attribute is only supported on array parameters.
-
-
- The '[Out]' attribute is not supported on the '{0}' parameter.
-
The 'Value' property must not be a 'ref' or 'readonly ref' property.
@@ -352,4 +313,4 @@
The 'Value' property on the native type '{0}' must have a setter
-
+
\ No newline at end of file
diff --git a/DllImportGenerator/DllImportGenerator/TypeNames.cs b/DllImportGenerator/DllImportGenerator/TypeNames.cs
index 678040e4e6b7..32dc72b3bce3 100644
--- a/DllImportGenerator/DllImportGenerator/TypeNames.cs
+++ b/DllImportGenerator/DllImportGenerator/TypeNames.cs
@@ -2,11 +2,14 @@
using System.Collections.Generic;
using System.Text;
using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.Interop;
namespace Microsoft.Interop
{
static class TypeNames
{
+ public const string DllImportAttribute = "System.Runtime.InteropServices.DllImportAttribute";
+
public const string GeneratedDllImportAttribute = "System.Runtime.InteropServices.GeneratedDllImportAttribute";
public const string GeneratedMarshallingAttribute = "System.Runtime.InteropServices.GeneratedMarshallingAttribute";
@@ -28,8 +31,6 @@ static class TypeNames
public const string System_Span_Metadata = "System.Span`1";
public const string System_Span = "System.Span";
- public const string System_Activator = "System.Activator";
-
public const string System_Runtime_InteropServices_StructLayoutAttribute = "System.Runtime.InteropServices.StructLayoutAttribute";
public const string System_Runtime_InteropServices_MarshalAsAttribute = "System.Runtime.InteropServices.MarshalAsAttribute";
@@ -38,25 +39,10 @@ static class TypeNames
public const string System_Runtime_InteropServices_Marshal = "System.Runtime.InteropServices.Marshal";
- private const string System_Runtime_InteropServices_MarshalEx = "System.Runtime.InteropServices.MarshalEx";
-
- public static string MarshalEx(AnalyzerConfigOptions options)
- {
- return options.UseMarshalType() ? System_Runtime_InteropServices_Marshal : System_Runtime_InteropServices_MarshalEx;
- }
-
public const string System_Runtime_InteropServices_GeneratedMarshalling_ArrayMarshaller_Metadata = "System.Runtime.InteropServices.GeneratedMarshalling.ArrayMarshaller`1";
public const string System_Runtime_InteropServices_GeneratedMarshalling_PtrArrayMarshaller_Metadata = "System.Runtime.InteropServices.GeneratedMarshalling.PtrArrayMarshaller`1";
- public const string System_Runtime_InteropServices_MemoryMarshal = "System.Runtime.InteropServices.MemoryMarshal";
-
- public const string System_Runtime_InteropServices_SafeHandle = "System.Runtime.InteropServices.SafeHandle";
-
- public const string System_Runtime_InteropServices_OutAttribute = "System.Runtime.InteropServices.OutAttribute";
-
- public const string System_Runtime_InteropServices_InAttribute = "System.Runtime.InteropServices.InAttribute";
-
public const string System_Runtime_CompilerServices_SkipLocalsInitAttribute = "System.Runtime.CompilerServices.SkipLocalsInitAttribute";
private const string System_Runtime_CompilerServices_Unsafe = "System.Runtime.CompilerServices.Unsafe";
diff --git a/DllImportGenerator/DllImportGenerator/ContiguousCollectionElementMarshallingCodeContext.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/ContiguousCollectionElementMarshallingCodeContext.cs
similarity index 100%
rename from DllImportGenerator/DllImportGenerator/ContiguousCollectionElementMarshallingCodeContext.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/ContiguousCollectionElementMarshallingCodeContext.cs
diff --git a/DllImportGenerator/Microsoft.Interop.SourceGeneration/IGeneratorDiagnostics.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/IGeneratorDiagnostics.cs
new file mode 100644
index 000000000000..f02f7c28957e
--- /dev/null
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/IGeneratorDiagnostics.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Diagnostics;
+using System.Linq;
+
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace Microsoft.Interop
+{
+ public static class DiagnosticExtensions
+ {
+ public static Diagnostic CreateDiagnostic(
+ this ISymbol symbol,
+ DiagnosticDescriptor descriptor,
+ params object[] args)
+ {
+ return symbol.Locations.CreateDiagnostic(descriptor, args);
+ }
+
+ public static Diagnostic CreateDiagnostic(
+ this AttributeData attributeData,
+ DiagnosticDescriptor descriptor,
+ params object[] args)
+ {
+ SyntaxReference? syntaxReference = attributeData.ApplicationSyntaxReference;
+ Location location = syntaxReference is not null
+ ? syntaxReference.GetSyntax().GetLocation()
+ : Location.None;
+
+ return location.CreateDiagnostic(descriptor, args);
+ }
+
+ public static Diagnostic CreateDiagnostic(
+ this ImmutableArray locations,
+ DiagnosticDescriptor descriptor,
+ params object[] args)
+ {
+ IEnumerable locationsInSource = locations.Where(l => l.IsInSource);
+ if (!locationsInSource.Any())
+ return Diagnostic.Create(descriptor, Location.None, args);
+
+ return Diagnostic.Create(
+ descriptor,
+ location: locationsInSource.First(),
+ additionalLocations: locationsInSource.Skip(1),
+ messageArgs: args);
+ }
+
+ public static Diagnostic CreateDiagnostic(
+ this Location location,
+ DiagnosticDescriptor descriptor,
+ params object[] args)
+ {
+ return Diagnostic.Create(
+ descriptor,
+ location: location.IsInSource ? location : Location.None,
+ messageArgs: args);
+ }
+ }
+
+
+ public interface IGeneratorDiagnostics
+ {
+ ///
+ /// Report diagnostic for marshalling of a parameter/return that is not supported
+ ///
+ /// Method with the parameter/return
+ /// Type info for the parameter/return
+ /// [Optional] Specific reason for lack of support
+ void ReportMarshallingNotSupported(
+ MethodDeclarationSyntax method,
+ TypePositionInfo info,
+ string? notSupportedDetails);
+
+ ///
+ /// Report diagnostic for configuration that is not supported by the DLL import source generator
+ ///
+ /// Attribute specifying the unsupported configuration
+ /// Name of the configuration
+ /// [Optiona] Unsupported configuration value
+ void ReportConfigurationNotSupported(
+ AttributeData attributeData,
+ string configurationName,
+ string? unsupportedValue);
+
+ void ReportInvalidMarshallingAttributeInfo(
+ AttributeData attributeData,
+ string reasonResourceName,
+ params string[] reasonArgs);
+ }
+
+ public static class IGeneratorDiagnosticsExtensions
+ {
+ public static void ReportConfigurationNotSupported(this IGeneratorDiagnostics diagnostics, AttributeData attributeData, string configurationName)
+ => diagnostics.ReportConfigurationNotSupported(attributeData, configurationName, null);
+ }
+}
diff --git a/DllImportGenerator/Microsoft.Interop.SourceGeneration/InteropGenerationOptions.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/InteropGenerationOptions.cs
new file mode 100644
index 000000000000..fa4e46a3f3d3
--- /dev/null
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/InteropGenerationOptions.cs
@@ -0,0 +1,8 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Microsoft.Interop
+{
+ public record InteropGenerationOptions(bool UseMarshalType, bool UseInternalUnsafeType);
+}
diff --git a/DllImportGenerator/Microsoft.Interop.SourceGeneration/LanguageSupport.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/LanguageSupport.cs
new file mode 100644
index 000000000000..ddf2c4203111
--- /dev/null
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/LanguageSupport.cs
@@ -0,0 +1,10 @@
+// Types defined to enable language support of various features
+// in the source generator.
+
+
+namespace System.Runtime.CompilerServices
+{
+ // Define IsExternalInit type to support records.
+ internal class IsExternalInit
+ {}
+}
\ No newline at end of file
diff --git a/DllImportGenerator/DllImportGenerator/ManagedTypeInfo.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/ManagedTypeInfo.cs
similarity index 68%
rename from DllImportGenerator/DllImportGenerator/ManagedTypeInfo.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/ManagedTypeInfo.cs
index 9e2bd6f70d8a..fe789e2e0886 100644
--- a/DllImportGenerator/DllImportGenerator/ManagedTypeInfo.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/ManagedTypeInfo.cs
@@ -10,7 +10,7 @@ namespace Microsoft.Interop
///
/// A discriminated union that contains enough info about a managed type to determine a marshalling generator and generate code.
///
- internal abstract record ManagedTypeInfo(string FullTypeName, string DiagnosticFormattedName)
+ public abstract record ManagedTypeInfo(string FullTypeName, string DiagnosticFormattedName)
{
public TypeSyntax Syntax { get; } = SyntaxFactory.ParseTypeName(FullTypeName);
@@ -46,7 +46,7 @@ public static ManagedTypeInfo CreateTypeInfoForTypeSymbol(ITypeSymbol type)
}
}
- internal sealed record SpecialTypeInfo(string FullTypeName, string DiagnosticFormattedName, SpecialType SpecialType) : ManagedTypeInfo(FullTypeName, DiagnosticFormattedName)
+ public sealed record SpecialTypeInfo(string FullTypeName, string DiagnosticFormattedName, SpecialType SpecialType) : ManagedTypeInfo(FullTypeName, DiagnosticFormattedName)
{
public static readonly SpecialTypeInfo Int32 = new("int", "int", SpecialType.System_Int32);
public static readonly SpecialTypeInfo Void = new("void", "void", SpecialType.System_Void);
@@ -62,13 +62,13 @@ public override int GetHashCode()
}
}
- internal sealed record EnumTypeInfo(string FullTypeName, string DiagnosticFormattedName, SpecialType UnderlyingType) : ManagedTypeInfo(FullTypeName, DiagnosticFormattedName);
+ public sealed record EnumTypeInfo(string FullTypeName, string DiagnosticFormattedName, SpecialType UnderlyingType) : ManagedTypeInfo(FullTypeName, DiagnosticFormattedName);
- internal sealed record PointerTypeInfo(string FullTypeName, string DiagnosticFormattedName, bool IsFunctionPointer) : ManagedTypeInfo(FullTypeName, DiagnosticFormattedName);
+ public sealed record PointerTypeInfo(string FullTypeName, string DiagnosticFormattedName, bool IsFunctionPointer) : ManagedTypeInfo(FullTypeName, DiagnosticFormattedName);
- internal sealed record SzArrayType(ManagedTypeInfo ElementTypeInfo) : ManagedTypeInfo($"{ElementTypeInfo.FullTypeName}[]", $"{ElementTypeInfo.DiagnosticFormattedName}[]");
+ public sealed record SzArrayType(ManagedTypeInfo ElementTypeInfo) : ManagedTypeInfo($"{ElementTypeInfo.FullTypeName}[]", $"{ElementTypeInfo.DiagnosticFormattedName}[]");
- internal sealed record DelegateTypeInfo(string FullTypeName, string DiagnosticFormattedName) : ManagedTypeInfo(FullTypeName, DiagnosticFormattedName);
+ public sealed record DelegateTypeInfo(string FullTypeName, string DiagnosticFormattedName) : ManagedTypeInfo(FullTypeName, DiagnosticFormattedName);
- internal sealed record SimpleManagedTypeInfo(string FullTypeName, string DiagnosticFormattedName) : ManagedTypeInfo(FullTypeName, DiagnosticFormattedName);
+ public sealed record SimpleManagedTypeInfo(string FullTypeName, string DiagnosticFormattedName) : ManagedTypeInfo(FullTypeName, DiagnosticFormattedName);
}
diff --git a/DllImportGenerator/DllImportGenerator/ManualTypeMarshallingHelper.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs
similarity index 99%
rename from DllImportGenerator/DllImportGenerator/ManualTypeMarshallingHelper.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs
index 1d073064a39d..137f45f1040d 100644
--- a/DllImportGenerator/DllImportGenerator/ManualTypeMarshallingHelper.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/ManualTypeMarshallingHelper.cs
@@ -5,7 +5,7 @@
namespace Microsoft.Interop
{
- static class ManualTypeMarshallingHelper
+ public static class ManualTypeMarshallingHelper
{
public const string ValuePropertyName = "Value";
public const string GetPinnableReferenceName = "GetPinnableReference";
diff --git a/DllImportGenerator/DllImportGenerator/Marshalling/ArrayMarshaller.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/ArrayMarshaller.cs
similarity index 96%
rename from DllImportGenerator/DllImportGenerator/Marshalling/ArrayMarshaller.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/ArrayMarshaller.cs
index 46af295b524b..53fc3655af91 100644
--- a/DllImportGenerator/DllImportGenerator/Marshalling/ArrayMarshaller.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/ArrayMarshaller.cs
@@ -6,14 +6,14 @@
namespace Microsoft.Interop
{
- internal sealed class ArrayMarshaller : IMarshallingGenerator
+ public sealed class ArrayMarshaller : IMarshallingGenerator
{
private readonly IMarshallingGenerator manualMarshallingGenerator;
private readonly TypeSyntax elementType;
private readonly bool enablePinning;
- private readonly AnalyzerConfigOptions options;
+ private readonly InteropGenerationOptions options;
- public ArrayMarshaller(IMarshallingGenerator manualMarshallingGenerator, TypeSyntax elementType, bool enablePinning, AnalyzerConfigOptions options)
+ public ArrayMarshaller(IMarshallingGenerator manualMarshallingGenerator, TypeSyntax elementType, bool enablePinning, InteropGenerationOptions options)
{
this.manualMarshallingGenerator = manualMarshallingGenerator;
this.elementType = elementType;
diff --git a/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs
new file mode 100644
index 000000000000..1346356eee12
--- /dev/null
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs
@@ -0,0 +1,292 @@
+using Microsoft.CodeAnalysis.CSharp;
+using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace Microsoft.Interop
+{
+ public class AttributedMarshallingModelGeneratorFactory : IMarshallingGeneratorFactory
+ {
+ private static readonly BlittableMarshaller Blittable = new BlittableMarshaller();
+ private static readonly Forwarder Forwarder = new Forwarder();
+
+ private readonly IMarshallingGeneratorFactory innerMarshallingGenerator;
+
+ public AttributedMarshallingModelGeneratorFactory(IMarshallingGeneratorFactory innerMarshallingGenerator, InteropGenerationOptions options)
+ {
+ Options = options;
+ this.innerMarshallingGenerator = innerMarshallingGenerator;
+ ElementMarshallingGeneratorFactory = this;
+ }
+
+ public InteropGenerationOptions Options { get; }
+
+ ///
+ /// The to use for collection elements.
+ /// This property is settable to enable decorating factories to ensure that element marshalling also goes through the decorator support.
+ ///
+ public IMarshallingGeneratorFactory ElementMarshallingGeneratorFactory { get; set; }
+
+ public IMarshallingGenerator Create(TypePositionInfo info, StubCodeContext context)
+ {
+ return info.MarshallingAttributeInfo switch
+ {
+ NativeMarshallingAttributeInfo marshalInfo => CreateCustomNativeTypeMarshaller(info, context, marshalInfo),
+ BlittableTypeAttributeInfo => Blittable,
+ GeneratedNativeMarshallingAttributeInfo => Forwarder,
+ _ => innerMarshallingGenerator.Create(info, context)
+ };
+ }
+
+ private static ExpressionSyntax GetNumElementsExpressionFromMarshallingInfo(TypePositionInfo info, CountInfo count, StubCodeContext context)
+ {
+ return count switch
+ {
+ SizeAndParamIndexInfo(int size, SizeAndParamIndexInfo.UnspecifiedParam) => GetConstSizeExpression(size),
+ ConstSizeCountInfo(int size) => GetConstSizeExpression(size),
+ SizeAndParamIndexInfo(SizeAndParamIndexInfo.UnspecifiedConstSize, TypePositionInfo param) => CheckedExpression(SyntaxKind.CheckedExpression, GetExpressionForParam(param)),
+ SizeAndParamIndexInfo(int size, TypePositionInfo param) => CheckedExpression(SyntaxKind.CheckedExpression, BinaryExpression(SyntaxKind.AddExpression, GetConstSizeExpression(size), GetExpressionForParam(param))),
+ CountElementCountInfo(TypePositionInfo elementInfo) => CheckedExpression(SyntaxKind.CheckedExpression, GetExpressionForParam(elementInfo)),
+ _ => throw new MarshallingNotSupportedException(info, context)
+ {
+ NotSupportedDetails = Resources.ArraySizeMustBeSpecified
+ },
+ };
+
+ static LiteralExpressionSyntax GetConstSizeExpression(int size)
+ {
+ return LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(size));
+ }
+
+ ExpressionSyntax GetExpressionForParam(TypePositionInfo paramInfo)
+ {
+ ExpressionSyntax numElementsExpression = GetIndexedNumElementsExpression(
+ context,
+ paramInfo,
+ out int numIndirectionLevels);
+
+ ManagedTypeInfo type = paramInfo.ManagedType;
+ MarshallingInfo marshallingInfo = paramInfo.MarshallingAttributeInfo;
+
+ for (int i = 0; i < numIndirectionLevels; i++)
+ {
+ if (marshallingInfo is NativeContiguousCollectionMarshallingInfo collectionInfo)
+ {
+ type = collectionInfo.ElementType;
+ marshallingInfo = collectionInfo.ElementMarshallingInfo;
+ }
+ else
+ {
+ throw new MarshallingNotSupportedException(info, context)
+ {
+ NotSupportedDetails = Resources.CollectionSizeParamTypeMustBeIntegral
+ };
+ }
+ }
+
+ if (type is not SpecialTypeInfo specialType || !specialType.SpecialType.IsIntegralType())
+ {
+ throw new MarshallingNotSupportedException(info, context)
+ {
+ NotSupportedDetails = Resources.CollectionSizeParamTypeMustBeIntegral
+ };
+ }
+
+ return CastExpression(
+ PredefinedType(Token(SyntaxKind.IntKeyword)),
+ ParenthesizedExpression(numElementsExpression));
+ }
+
+ static ExpressionSyntax GetIndexedNumElementsExpression(StubCodeContext context, TypePositionInfo numElementsInfo, out int numIndirectionLevels)
+ {
+ Stack indexerStack = new();
+
+ StubCodeContext? currentContext = context;
+ StubCodeContext lastContext = null!;
+
+ while (currentContext is not null)
+ {
+ if (currentContext is ContiguousCollectionElementMarshallingCodeContext collectionContext)
+ {
+ indexerStack.Push(collectionContext.IndexerIdentifier);
+ }
+ lastContext = currentContext;
+ currentContext = currentContext.ParentContext;
+ }
+
+ numIndirectionLevels = indexerStack.Count;
+
+ ExpressionSyntax indexedNumElements = IdentifierName(lastContext.GetIdentifiers(numElementsInfo).managed);
+ while (indexerStack.Count > 0)
+ {
+ NameSyntax indexer = IdentifierName(indexerStack.Pop());
+ indexedNumElements = ElementAccessExpression(indexedNumElements)
+ .AddArgumentListArguments(Argument(indexer));
+ }
+
+ return indexedNumElements;
+ }
+ }
+
+ private IMarshallingGenerator CreateCustomNativeTypeMarshaller(TypePositionInfo info, StubCodeContext context, NativeMarshallingAttributeInfo marshalInfo)
+ {
+ ValidateCustomNativeTypeMarshallingSupported(info, context, marshalInfo);
+
+ ICustomNativeTypeMarshallingStrategy marshallingStrategy = new SimpleCustomNativeTypeMarshalling(marshalInfo.NativeMarshallingType.Syntax);
+
+ if ((marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedToNativeStackalloc) != 0)
+ {
+ marshallingStrategy = new StackallocOptimizationMarshalling(marshallingStrategy);
+ }
+
+ if ((marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.FreeNativeResources) != 0)
+ {
+ marshallingStrategy = new FreeNativeCleanupStrategy(marshallingStrategy);
+ }
+
+ // Collections have extra configuration, so handle them here.
+ if (marshalInfo is NativeContiguousCollectionMarshallingInfo collectionMarshallingInfo)
+ {
+ return CreateNativeCollectionMarshaller(info, context, collectionMarshallingInfo, marshallingStrategy);
+ }
+
+ if (marshalInfo.ValuePropertyType is not null)
+ {
+ marshallingStrategy = DecorateWithValuePropertyStrategy(marshalInfo, marshallingStrategy);
+ }
+
+ IMarshallingGenerator marshallingGenerator = new CustomNativeTypeMarshallingGenerator(marshallingStrategy, enableByValueContentsMarshalling: false);
+
+ if ((marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedTypePinning) != 0)
+ {
+ return new PinnableManagedValueMarshaller(marshallingGenerator);
+ }
+
+ return marshallingGenerator;
+ }
+
+ private void ValidateCustomNativeTypeMarshallingSupported(TypePositionInfo info, StubCodeContext context, NativeMarshallingAttributeInfo marshalInfo)
+ {
+ // The marshalling method for this type doesn't support marshalling from native to managed,
+ // but our scenario requires marshalling from native to managed.
+ if ((info.RefKind == RefKind.Ref || info.RefKind == RefKind.Out || info.IsManagedReturnPosition)
+ && (marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.NativeToManaged) == 0)
+ {
+ throw new MarshallingNotSupportedException(info, context)
+ {
+ NotSupportedDetails = string.Format(Resources.CustomTypeMarshallingNativeToManagedUnsupported, marshalInfo.NativeMarshallingType.FullTypeName)
+ };
+ }
+ // The marshalling method for this type doesn't support marshalling from managed to native by value,
+ // but our scenario requires marshalling from managed to native by value.
+ else if (!info.IsByRef
+ && (marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedToNative) == 0
+ && (context.SingleFrameSpansNativeContext && (marshalInfo.MarshallingFeatures & (CustomMarshallingFeatures.ManagedTypePinning | CustomMarshallingFeatures.ManagedToNativeStackalloc)) == 0))
+ {
+ throw new MarshallingNotSupportedException(info, context)
+ {
+ NotSupportedDetails = string.Format(Resources.CustomTypeMarshallingManagedToNativeUnsupported, marshalInfo.NativeMarshallingType.FullTypeName)
+ };
+ }
+ // The marshalling method for this type doesn't support marshalling from managed to native by reference,
+ // but our scenario requires marshalling from managed to native by reference.
+ // "in" byref supports stack marshalling.
+ else if (info.RefKind == RefKind.In
+ && (marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedToNative) == 0
+ && !(context.SingleFrameSpansNativeContext && (marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedToNativeStackalloc) != 0))
+ {
+ throw new MarshallingNotSupportedException(info, context)
+ {
+ NotSupportedDetails = string.Format(Resources.CustomTypeMarshallingManagedToNativeUnsupported, marshalInfo.NativeMarshallingType.FullTypeName)
+ };
+ }
+ // The marshalling method for this type doesn't support marshalling from managed to native by reference,
+ // but our scenario requires marshalling from managed to native by reference.
+ // "ref" byref marshalling doesn't support stack marshalling
+ else if (info.RefKind == RefKind.Ref
+ && (marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedToNative) == 0)
+ {
+ throw new MarshallingNotSupportedException(info, context)
+ {
+ NotSupportedDetails = string.Format(Resources.CustomTypeMarshallingManagedToNativeUnsupported, marshalInfo.NativeMarshallingType.FullTypeName)
+ };
+ }
+ }
+
+ private ICustomNativeTypeMarshallingStrategy DecorateWithValuePropertyStrategy(NativeMarshallingAttributeInfo marshalInfo, ICustomNativeTypeMarshallingStrategy nativeTypeMarshaller)
+ {
+ TypeSyntax valuePropertyTypeSyntax = marshalInfo.ValuePropertyType!.Syntax;
+
+ if ((marshalInfo.MarshallingFeatures & CustomMarshallingFeatures.NativeTypePinning) != 0)
+ {
+ return new PinnableMarshallerTypeMarshalling(nativeTypeMarshaller, valuePropertyTypeSyntax);
+ }
+
+ return new CustomNativeTypeWithValuePropertyMarshalling(nativeTypeMarshaller, valuePropertyTypeSyntax);
+ }
+
+ private IMarshallingGenerator CreateNativeCollectionMarshaller(
+ TypePositionInfo info,
+ StubCodeContext context,
+ NativeContiguousCollectionMarshallingInfo collectionInfo,
+ ICustomNativeTypeMarshallingStrategy marshallingStrategy)
+ {
+ var elementInfo = new TypePositionInfo(collectionInfo.ElementType, collectionInfo.ElementMarshallingInfo) { ManagedIndex = info.ManagedIndex };
+ var elementMarshaller = Create(
+ elementInfo,
+ new ContiguousCollectionElementMarshallingCodeContext(StubCodeContext.Stage.Setup, string.Empty, context));
+ var elementType = elementMarshaller.AsNativeType(elementInfo);
+
+ bool isBlittable = elementMarshaller is BlittableMarshaller;
+
+ if (isBlittable)
+ {
+ marshallingStrategy = new ContiguousBlittableElementCollectionMarshalling(marshallingStrategy, collectionInfo.ElementType.Syntax);
+ }
+ else
+ {
+ marshallingStrategy = new ContiguousNonBlittableElementCollectionMarshalling(marshallingStrategy, elementMarshaller, elementInfo);
+ }
+
+ // Explicitly insert the Value property handling here (before numElements handling) so that the numElements handling will be emitted before the Value property handling in unmarshalling.
+ if (collectionInfo.ValuePropertyType is not null)
+ {
+ marshallingStrategy = DecorateWithValuePropertyStrategy(collectionInfo, marshallingStrategy);
+ }
+
+ ExpressionSyntax numElementsExpression = LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(0));
+ if (info.IsManagedReturnPosition || (info.IsByRef && info.RefKind != RefKind.In))
+ {
+ // In this case, we need a numElementsExpression supplied from metadata, so we'll calculate it here.
+ numElementsExpression = GetNumElementsExpressionFromMarshallingInfo(info, collectionInfo.ElementCountInfo, context);
+ }
+
+ marshallingStrategy = new NumElementsExpressionMarshalling(
+ marshallingStrategy,
+ numElementsExpression,
+ SizeOfExpression(elementType));
+
+ if (collectionInfo.UseDefaultMarshalling && info.ManagedType is SzArrayType)
+ {
+ return new ArrayMarshaller(
+ new CustomNativeTypeMarshallingGenerator(marshallingStrategy, enableByValueContentsMarshalling: true),
+ elementType,
+ isBlittable,
+ Options);
+ }
+
+ IMarshallingGenerator marshallingGenerator = new CustomNativeTypeMarshallingGenerator(marshallingStrategy, enableByValueContentsMarshalling: false);
+
+ if ((collectionInfo.MarshallingFeatures & CustomMarshallingFeatures.ManagedTypePinning) != 0)
+ {
+ return new PinnableManagedValueMarshaller(marshallingGenerator);
+ }
+
+ return marshallingGenerator;
+ }
+ }
+}
diff --git a/DllImportGenerator/DllImportGenerator/Marshalling/BlittableMarshaller.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/BlittableMarshaller.cs
similarity index 98%
rename from DllImportGenerator/DllImportGenerator/Marshalling/BlittableMarshaller.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/BlittableMarshaller.cs
index 15fa7774a996..8925ffc62555 100644
--- a/DllImportGenerator/DllImportGenerator/Marshalling/BlittableMarshaller.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/BlittableMarshaller.cs
@@ -7,7 +7,7 @@
namespace Microsoft.Interop
{
- internal class BlittableMarshaller : IMarshallingGenerator
+ public sealed class BlittableMarshaller : IMarshallingGenerator
{
public TypeSyntax AsNativeType(TypePositionInfo info)
{
diff --git a/DllImportGenerator/DllImportGenerator/Marshalling/BoolMarshaller.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/BoolMarshaller.cs
similarity index 95%
rename from DllImportGenerator/DllImportGenerator/Marshalling/BoolMarshaller.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/BoolMarshaller.cs
index 2b5af8d2a5cd..7ceab5830c0d 100644
--- a/DllImportGenerator/DllImportGenerator/Marshalling/BoolMarshaller.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/BoolMarshaller.cs
@@ -8,7 +8,7 @@
namespace Microsoft.Interop
{
- internal abstract class BoolMarshallerBase : IMarshallingGenerator
+ public abstract class BoolMarshallerBase : IMarshallingGenerator
{
private readonly PredefinedTypeSyntax _nativeType;
private readonly int _trueValue;
@@ -114,7 +114,7 @@ public IEnumerable Generate(TypePositionInfo info, StubCodeCont
/// and C++, but those is implementation defined.
/// Consult your compiler specification.
///
- internal class ByteBoolMarshaller : BoolMarshallerBase
+ public sealed class ByteBoolMarshaller : BoolMarshallerBase
{
public ByteBoolMarshaller()
: base(PredefinedType(Token(SyntaxKind.ByteKeyword)), trueValue: 1, falseValue: 0, compareToTrue: false)
@@ -128,7 +128,7 @@ public ByteBoolMarshaller()
///
/// Corresponds to the definition of BOOL.
///
- internal class WinBoolMarshaller : BoolMarshallerBase
+ public sealed class WinBoolMarshaller : BoolMarshallerBase
{
public WinBoolMarshaller()
: base(PredefinedType(Token(SyntaxKind.IntKeyword)), trueValue: 1, falseValue: 0, compareToTrue: false)
@@ -139,7 +139,7 @@ public WinBoolMarshaller()
///
/// Marshal a boolean value as a VARIANT_BOOL (Windows OLE/Automation type).
///
- internal class VariantBoolMarshaller : BoolMarshallerBase
+ public sealed class VariantBoolMarshaller : BoolMarshallerBase
{
private const short VARIANT_TRUE = -1;
private const short VARIANT_FALSE = 0;
diff --git a/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/ByValueContentsMarshalKindValidator.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/ByValueContentsMarshalKindValidator.cs
new file mode 100644
index 000000000000..dc9f64fde908
--- /dev/null
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/ByValueContentsMarshalKindValidator.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Microsoft.Interop
+{
+ ///
+ /// An implementation that wraps an inner instance and validates that the on the provided is valid in the current marshalling scenario.
+ ///
+ public class ByValueContentsMarshalKindValidator : IMarshallingGeneratorFactory
+ {
+ private readonly IMarshallingGeneratorFactory inner;
+
+ public ByValueContentsMarshalKindValidator(IMarshallingGeneratorFactory inner)
+ {
+ this.inner = inner;
+ }
+
+ public IMarshallingGenerator Create(TypePositionInfo info, StubCodeContext context)
+ {
+ return ValidateByValueMarshalKind(info, context, inner.Create(info, context));
+ }
+
+ private static IMarshallingGenerator ValidateByValueMarshalKind(TypePositionInfo info, StubCodeContext context, IMarshallingGenerator generator)
+ {
+ if (info.IsByRef && info.ByValueContentsMarshalKind != ByValueContentsMarshalKind.Default)
+ {
+ throw new MarshallingNotSupportedException(info, context)
+ {
+ NotSupportedDetails = Resources.InOutAttributeByRefNotSupported
+ };
+ }
+ else if (info.ByValueContentsMarshalKind == ByValueContentsMarshalKind.In)
+ {
+ throw new MarshallingNotSupportedException(info, context)
+ {
+ NotSupportedDetails = Resources.InAttributeNotSupportedWithoutOut
+ };
+ }
+ else if (info.ByValueContentsMarshalKind != ByValueContentsMarshalKind.Default
+ && !generator.SupportsByValueMarshalKind(info.ByValueContentsMarshalKind, context))
+ {
+ throw new MarshallingNotSupportedException(info, context)
+ {
+ NotSupportedDetails = Resources.InOutAttributeMarshalerNotSupported
+ };
+ }
+ return generator;
+ }
+ }
+}
diff --git a/DllImportGenerator/DllImportGenerator/Marshalling/CharMarshaller.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/CharMarshaller.cs
similarity index 97%
rename from DllImportGenerator/DllImportGenerator/Marshalling/CharMarshaller.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/CharMarshaller.cs
index d04a78c2460a..ce3c97230ada 100644
--- a/DllImportGenerator/DllImportGenerator/Marshalling/CharMarshaller.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/CharMarshaller.cs
@@ -9,7 +9,7 @@
namespace Microsoft.Interop
{
- internal class Utf16CharMarshaller : IMarshallingGenerator
+ public sealed class Utf16CharMarshaller : IMarshallingGenerator
{
private static readonly PredefinedTypeSyntax NativeType = PredefinedType(Token(SyntaxKind.UShortKeyword));
diff --git a/DllImportGenerator/DllImportGenerator/Marshalling/ConditionalStackallocMarshallingGenerator.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/ConditionalStackallocMarshallingGenerator.cs
similarity index 99%
rename from DllImportGenerator/DllImportGenerator/Marshalling/ConditionalStackallocMarshallingGenerator.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/ConditionalStackallocMarshallingGenerator.cs
index 2994ec8df75c..c2c0788b196f 100644
--- a/DllImportGenerator/DllImportGenerator/Marshalling/ConditionalStackallocMarshallingGenerator.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/ConditionalStackallocMarshallingGenerator.cs
@@ -6,7 +6,7 @@
namespace Microsoft.Interop
{
- internal abstract class ConditionalStackallocMarshallingGenerator : IMarshallingGenerator
+ public abstract class ConditionalStackallocMarshallingGenerator : IMarshallingGenerator
{
protected static string GetAllocationMarkerIdentifier(TypePositionInfo info, StubCodeContext context) => context.GetAdditionalIdentifier(info, "allocated");
diff --git a/DllImportGenerator/DllImportGenerator/Marshalling/CustomNativeTypeMarshallingGenerator.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/CustomNativeTypeMarshallingGenerator.cs
similarity index 100%
rename from DllImportGenerator/DllImportGenerator/Marshalling/CustomNativeTypeMarshallingGenerator.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/CustomNativeTypeMarshallingGenerator.cs
diff --git a/DllImportGenerator/DllImportGenerator/Marshalling/DelegateMarshaller.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/DelegateMarshaller.cs
similarity index 98%
rename from DllImportGenerator/DllImportGenerator/Marshalling/DelegateMarshaller.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/DelegateMarshaller.cs
index b5aca0f44207..c8854abb54bd 100644
--- a/DllImportGenerator/DllImportGenerator/Marshalling/DelegateMarshaller.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/DelegateMarshaller.cs
@@ -6,7 +6,7 @@
namespace Microsoft.Interop
{
- internal class DelegateMarshaller : IMarshallingGenerator
+ public sealed class DelegateMarshaller : IMarshallingGenerator
{
public TypeSyntax AsNativeType(TypePositionInfo info)
{
diff --git a/DllImportGenerator/DllImportGenerator/Marshalling/Forwarder.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/Forwarder.cs
similarity index 98%
rename from DllImportGenerator/DllImportGenerator/Marshalling/Forwarder.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/Forwarder.cs
index e86c422ec482..1f8f1c1756f2 100644
--- a/DllImportGenerator/DllImportGenerator/Marshalling/Forwarder.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/Forwarder.cs
@@ -8,7 +8,7 @@
namespace Microsoft.Interop
{
- internal class Forwarder : IMarshallingGenerator, IAttributedReturnTypeMarshallingGenerator
+ public sealed class Forwarder : IMarshallingGenerator, IAttributedReturnTypeMarshallingGenerator
{
public TypeSyntax AsNativeType(TypePositionInfo info)
{
diff --git a/DllImportGenerator/DllImportGenerator/Marshalling/HResultExceptionMarshaller.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/HResultExceptionMarshaller.cs
similarity index 96%
rename from DllImportGenerator/DllImportGenerator/Marshalling/HResultExceptionMarshaller.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/HResultExceptionMarshaller.cs
index 09ce81431e6a..349a651a9d5b 100644
--- a/DllImportGenerator/DllImportGenerator/Marshalling/HResultExceptionMarshaller.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/HResultExceptionMarshaller.cs
@@ -9,7 +9,7 @@
namespace Microsoft.Interop
{
- internal sealed class HResultExceptionMarshaller : IMarshallingGenerator
+ public sealed class HResultExceptionMarshaller : IMarshallingGenerator
{
private static readonly TypeSyntax NativeType = PredefinedType(Token(SyntaxKind.IntKeyword));
diff --git a/DllImportGenerator/DllImportGenerator/Marshalling/ICustomNativeTypeMarshallingStrategy.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/ICustomNativeTypeMarshallingStrategy.cs
similarity index 100%
rename from DllImportGenerator/DllImportGenerator/Marshalling/ICustomNativeTypeMarshallingStrategy.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/ICustomNativeTypeMarshallingStrategy.cs
diff --git a/DllImportGenerator/DllImportGenerator/Marshalling/MarshallerHelpers.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/MarshallerHelpers.cs
similarity index 99%
rename from DllImportGenerator/DllImportGenerator/Marshalling/MarshallerHelpers.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/MarshallerHelpers.cs
index 256fc939ec7b..f3ee0df3ea33 100644
--- a/DllImportGenerator/DllImportGenerator/Marshalling/MarshallerHelpers.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/MarshallerHelpers.cs
@@ -7,7 +7,7 @@
namespace Microsoft.Interop
{
- internal static class MarshallerHelpers
+ public static class MarshallerHelpers
{
public static readonly ExpressionSyntax IsWindows = InvocationExpression(
MemberAccessExpression(
diff --git a/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs
new file mode 100644
index 000000000000..e97191550f18
--- /dev/null
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace Microsoft.Interop
+{
+ ///
+ /// Interface for generation of marshalling code for P/Invoke stubs
+ ///
+ public interface IMarshallingGenerator
+ {
+ ///
+ /// Get the native type syntax for
+ ///
+ /// Object to marshal
+ /// Type syntax for the native type representing
+ TypeSyntax AsNativeType(TypePositionInfo info);
+
+ ///
+ /// Get the as a parameter of the P/Invoke declaration
+ ///
+ /// Object to marshal
+ /// Parameter syntax for
+ ParameterSyntax AsParameter(TypePositionInfo info);
+
+ ///
+ /// Get the as an argument to be passed to the P/Invoke
+ ///
+ /// Object to marshal
+ /// Code generation context
+ /// Argument syntax for
+ ArgumentSyntax AsArgument(TypePositionInfo info, StubCodeContext context);
+
+ ///
+ /// Generate code for marshalling
+ ///
+ /// Object to marshal
+ /// Code generation context
+ /// List of statements to be added to the P/Invoke stub
+ ///
+ /// The generator should return the appropriate statements based on the
+ /// of .
+ /// For , any statements not of type
+ /// will be ignored.
+ ///
+ IEnumerable Generate(TypePositionInfo info, StubCodeContext context);
+
+ ///
+ /// Returns whether or not this marshaller uses an identifier for the native value in addition
+ /// to an identifer for the managed value.
+ ///
+ /// Object to marshal
+ /// Code generation context
+ /// If the marshaller uses an identifier for the native value, true; otherwise, false.
+ ///
+ /// of may not be valid.
+ ///
+ bool UsesNativeIdentifier(TypePositionInfo info, StubCodeContext context);
+
+ ///
+ /// Returns if the given ByValueContentsMarshalKind is supported in the current marshalling context.
+ /// A supported marshal kind has a different behavior than the default behavior.
+ ///
+ /// The marshal kind.
+ /// The marshalling context.
+ ///
+ bool SupportsByValueMarshalKind(ByValueContentsMarshalKind marshalKind, StubCodeContext context);
+ }
+
+ ///
+ /// Interface for generating attributes for native return types.
+ ///
+ public interface IAttributedReturnTypeMarshallingGenerator : IMarshallingGenerator
+ {
+ ///
+ /// Gets any attributes that should be applied to the return type for this .
+ ///
+ /// Object to marshal
+ /// Attributes for the return type for this , or null if no attributes should be added.
+ AttributeListSyntax? GenerateAttributesForReturnType(TypePositionInfo info);
+ }
+
+
+ ///
+ /// Exception used to indicate marshalling isn't supported.
+ ///
+ public sealed class MarshallingNotSupportedException : Exception
+ {
+ ///
+ /// Construct a new instance.
+ ///
+ /// instance
+ /// instance
+ public MarshallingNotSupportedException(TypePositionInfo info, StubCodeContext context)
+ {
+ this.TypePositionInfo = info;
+ this.StubCodeContext = context;
+ }
+
+ ///
+ /// Type that is being marshalled.
+ ///
+ public TypePositionInfo TypePositionInfo { get; private init; }
+
+ ///
+ /// Context in which the marshalling is taking place.
+ ///
+ public StubCodeContext StubCodeContext { get; private init; }
+
+ ///
+ /// [Optional] Specific reason marshalling of the supplied type isn't supported.
+ ///
+ public string? NotSupportedDetails { get; init; }
+ }
+}
diff --git a/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGeneratorFactory.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGeneratorFactory.cs
new file mode 100644
index 000000000000..1efa6e495e57
--- /dev/null
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGeneratorFactory.cs
@@ -0,0 +1,221 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
+
+namespace Microsoft.Interop
+{
+ public interface IMarshallingGeneratorFactory
+ {
+ ///
+ /// Create an instance for marshalling the supplied type in the given position.
+ ///
+ /// Type details
+ /// Metadata about the stub the type is associated with
+ /// A instance.
+ public IMarshallingGenerator Create(
+ TypePositionInfo info,
+ StubCodeContext context);
+ }
+
+ public sealed class DefaultMarshallingGeneratorFactory : IMarshallingGeneratorFactory
+ {
+ private static readonly ByteBoolMarshaller ByteBool = new();
+ private static readonly WinBoolMarshaller WinBool = new();
+ private static readonly VariantBoolMarshaller VariantBool = new();
+
+ private static readonly Utf16CharMarshaller Utf16Char = new();
+ private static readonly Utf16StringMarshaller Utf16String = new();
+ private static readonly Utf8StringMarshaller Utf8String = new();
+ private static readonly AnsiStringMarshaller AnsiString = new AnsiStringMarshaller(Utf8String);
+ private static readonly PlatformDefinedStringMarshaller PlatformDefinedString = new PlatformDefinedStringMarshaller(Utf16String, Utf8String);
+
+ private static readonly Forwarder Forwarder = new();
+ private static readonly BlittableMarshaller Blittable = new();
+ private static readonly DelegateMarshaller Delegate = new();
+ private static readonly SafeHandleMarshaller SafeHandle = new();
+ private InteropGenerationOptions Options { get; }
+
+ public DefaultMarshallingGeneratorFactory(InteropGenerationOptions options)
+ {
+ this.Options = options;
+ }
+
+ ///
+ /// Create an instance for marshalling the supplied type in the given position.
+ ///
+ /// Type details
+ /// Metadata about the stub the type is associated with
+ /// A instance.
+ public IMarshallingGenerator Create(
+ TypePositionInfo info,
+ StubCodeContext context)
+ {
+ switch (info)
+ {
+ // Blittable primitives with no marshalling info or with a compatible [MarshalAs] attribute.
+ case { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_SByte }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.I1, _) }
+ or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Byte }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.U1, _) }
+ or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Int16 }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.I2, _) }
+ or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_UInt16 }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.U2, _) }
+ or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Int32 }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.I4, _) }
+ or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_UInt32 }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.U4, _) }
+ or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Int64 }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.I8, _) }
+ or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_UInt64 }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.U8, _) }
+ or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_IntPtr }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.SysInt, _) }
+ or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_UIntPtr }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.SysUInt, _) }
+ or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Single }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.R4, _) }
+ or { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Double }, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.R8, _) }:
+ return Blittable;
+
+ // Enum with no marshalling info
+ case { ManagedType: EnumTypeInfo enumType, MarshallingAttributeInfo: NoMarshallingInfo }:
+ // Check that the underlying type is not bool or char. C# does not allow this, but ECMA-335 does.
+ var underlyingSpecialType = enumType.UnderlyingType;
+ if (underlyingSpecialType == SpecialType.System_Boolean || underlyingSpecialType == SpecialType.System_Char)
+ {
+ throw new MarshallingNotSupportedException(info, context);
+ }
+ return Blittable;
+
+ // Pointer with no marshalling info
+ case { ManagedType: PointerTypeInfo(_, _, IsFunctionPointer: false), MarshallingAttributeInfo: NoMarshallingInfo }:
+ return Blittable;
+
+ // Function pointer with no marshalling info
+ case { ManagedType: PointerTypeInfo(_, _, IsFunctionPointer: true), MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.FunctionPtr, _) }:
+ return Blittable;
+
+ case { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Boolean }, MarshallingAttributeInfo: NoMarshallingInfo }:
+ return WinBool; // [Compat] Matching the default for the built-in runtime marshallers.
+ case { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Boolean }, MarshallingAttributeInfo: MarshalAsInfo(UnmanagedType.I1 or UnmanagedType.U1, _) }:
+ return ByteBool;
+ case { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Boolean }, MarshallingAttributeInfo: MarshalAsInfo(UnmanagedType.I4 or UnmanagedType.U4 or UnmanagedType.Bool, _) }:
+ return WinBool;
+ case { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Boolean }, MarshallingAttributeInfo: MarshalAsInfo(UnmanagedType.VariantBool, _) }:
+ return VariantBool;
+
+ case { ManagedType: DelegateTypeInfo, MarshallingAttributeInfo: NoMarshallingInfo or MarshalAsInfo(UnmanagedType.FunctionPtr, _) }:
+ return Delegate;
+
+ case { MarshallingAttributeInfo: SafeHandleMarshallingInfo(_, bool isAbstract) }:
+ if (!context.AdditionalTemporaryStateLivesAcrossStages)
+ {
+ throw new MarshallingNotSupportedException(info, context);
+ }
+ if (info.IsByRef && isAbstract)
+ {
+ throw new MarshallingNotSupportedException(info, context)
+ {
+ NotSupportedDetails = Resources.SafeHandleByRefMustBeConcrete
+ };
+ }
+ return new SafeHandleMarshaller();
+
+ case { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Char } }:
+ return CreateCharMarshaller(info, context);
+
+ case { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_String } }:
+ return CreateStringMarshaller(info, context);
+
+ case { ManagedType: SpecialTypeInfo { SpecialType: SpecialType.System_Void } }:
+ return Forwarder;
+
+ default:
+ throw new MarshallingNotSupportedException(info, context);
+ }
+ }
+
+ private IMarshallingGenerator CreateCharMarshaller(TypePositionInfo info, StubCodeContext context)
+ {
+ MarshallingInfo marshalInfo = info.MarshallingAttributeInfo;
+ if (marshalInfo is NoMarshallingInfo)
+ {
+ // [Compat] Require explicit marshalling information.
+ throw new MarshallingNotSupportedException(info, context)
+ {
+ NotSupportedDetails = Resources.MarshallingStringOrCharAsUndefinedNotSupported
+ };
+ }
+
+ // Explicit MarshalAs takes precedence over string encoding info
+ if (marshalInfo is MarshalAsInfo marshalAsInfo)
+ {
+ switch (marshalAsInfo.UnmanagedType)
+ {
+ case UnmanagedType.I2:
+ case UnmanagedType.U2:
+ return Utf16Char;
+ }
+ }
+ else if (marshalInfo is MarshallingInfoStringSupport marshalStringInfo)
+ {
+ switch (marshalStringInfo.CharEncoding)
+ {
+ case CharEncoding.Utf16:
+ return Utf16Char;
+ case CharEncoding.Ansi:
+ throw new MarshallingNotSupportedException(info, context) // [Compat] ANSI is not supported for char
+ {
+ NotSupportedDetails = string.Format(Resources.MarshallingCharAsSpecifiedCharSetNotSupported, CharSet.Ansi)
+ };
+ case CharEncoding.PlatformDefined:
+ throw new MarshallingNotSupportedException(info, context) // [Compat] See conversion of CharSet.Auto.
+ {
+ NotSupportedDetails = string.Format(Resources.MarshallingCharAsSpecifiedCharSetNotSupported, CharSet.Auto)
+ };
+ }
+ }
+
+ throw new MarshallingNotSupportedException(info, context);
+ }
+
+ private IMarshallingGenerator CreateStringMarshaller(TypePositionInfo info, StubCodeContext context)
+ {
+ MarshallingInfo marshalInfo = info.MarshallingAttributeInfo;
+ if (marshalInfo is NoMarshallingInfo)
+ {
+ // [Compat] Require explicit marshalling information.
+ throw new MarshallingNotSupportedException(info, context)
+ {
+ NotSupportedDetails = Resources.MarshallingStringOrCharAsUndefinedNotSupported
+ };
+ }
+
+ // Explicit MarshalAs takes precedence over string encoding info
+ if (marshalInfo is MarshalAsInfo marshalAsInfo)
+ {
+ switch (marshalAsInfo.UnmanagedType)
+ {
+ case UnmanagedType.LPStr:
+ return AnsiString;
+ case UnmanagedType.LPTStr:
+ case UnmanagedType.LPWStr:
+ return Utf16String;
+ case (UnmanagedType)0x30:// UnmanagedType.LPUTF8Str
+ return Utf8String;
+ }
+ }
+ else if (marshalInfo is MarshallingInfoStringSupport marshalStringInfo)
+ {
+ switch (marshalStringInfo.CharEncoding)
+ {
+ case CharEncoding.Ansi:
+ return AnsiString;
+ case CharEncoding.Utf16:
+ return Utf16String;
+ case CharEncoding.Utf8:
+ return Utf8String;
+ case CharEncoding.PlatformDefined:
+ return PlatformDefinedString;
+ }
+ }
+
+ throw new MarshallingNotSupportedException(info, context);
+ }
+ }
+}
diff --git a/DllImportGenerator/DllImportGenerator/Marshalling/PinnableManagedValueMarshaller.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/PinnableManagedValueMarshaller.cs
similarity index 97%
rename from DllImportGenerator/DllImportGenerator/Marshalling/PinnableManagedValueMarshaller.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/PinnableManagedValueMarshaller.cs
index e14cfbf25b27..d8e26f8d6334 100644
--- a/DllImportGenerator/DllImportGenerator/Marshalling/PinnableManagedValueMarshaller.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/PinnableManagedValueMarshaller.cs
@@ -5,7 +5,7 @@
namespace Microsoft.Interop
{
- internal sealed class PinnableManagedValueMarshaller : IMarshallingGenerator
+ public sealed class PinnableManagedValueMarshaller : IMarshallingGenerator
{
private readonly IMarshallingGenerator manualMarshallingGenerator;
diff --git a/DllImportGenerator/DllImportGenerator/Marshalling/SafeHandleMarshaller.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/SafeHandleMarshaller.cs
similarity index 98%
rename from DllImportGenerator/DllImportGenerator/Marshalling/SafeHandleMarshaller.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/SafeHandleMarshaller.cs
index e3b32f94a5c6..262de1be2d9b 100644
--- a/DllImportGenerator/DllImportGenerator/Marshalling/SafeHandleMarshaller.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/SafeHandleMarshaller.cs
@@ -8,15 +8,8 @@
namespace Microsoft.Interop
{
- internal class SafeHandleMarshaller : IMarshallingGenerator
+ public sealed class SafeHandleMarshaller : IMarshallingGenerator
{
- private readonly AnalyzerConfigOptions options;
-
- public SafeHandleMarshaller(AnalyzerConfigOptions options)
- {
- this.options = options;
- }
-
public TypeSyntax AsNativeType(TypePositionInfo info)
{
return MarshallerHelpers.SystemIntPtrType;
diff --git a/DllImportGenerator/DllImportGenerator/Marshalling/StringMarshaller.Ansi.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Ansi.cs
similarity index 98%
rename from DllImportGenerator/DllImportGenerator/Marshalling/StringMarshaller.Ansi.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Ansi.cs
index a63ecd4ab7f8..97dd9328c875 100644
--- a/DllImportGenerator/DllImportGenerator/Marshalling/StringMarshaller.Ansi.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Ansi.cs
@@ -9,7 +9,7 @@
namespace Microsoft.Interop
{
- internal sealed class AnsiStringMarshaller : ConditionalStackallocMarshallingGenerator
+ public sealed class AnsiStringMarshaller : ConditionalStackallocMarshallingGenerator
{
private static readonly TypeSyntax NativeType = PointerType(PredefinedType(Token(SyntaxKind.ByteKeyword)));
diff --git a/DllImportGenerator/DllImportGenerator/Marshalling/StringMarshaller.PlatformDefined.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.PlatformDefined.cs
similarity index 98%
rename from DllImportGenerator/DllImportGenerator/Marshalling/StringMarshaller.PlatformDefined.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.PlatformDefined.cs
index a9b665f88b09..3de4c48a724b 100644
--- a/DllImportGenerator/DllImportGenerator/Marshalling/StringMarshaller.PlatformDefined.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.PlatformDefined.cs
@@ -10,7 +10,7 @@
namespace Microsoft.Interop
{
- internal sealed class PlatformDefinedStringMarshaller : ConditionalStackallocMarshallingGenerator
+ public sealed class PlatformDefinedStringMarshaller : ConditionalStackallocMarshallingGenerator
{
private static readonly TypeSyntax NativeType = PointerType(PredefinedType(Token(SyntaxKind.VoidKeyword)));
diff --git a/DllImportGenerator/DllImportGenerator/Marshalling/StringMarshaller.Utf16.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Utf16.cs
similarity index 99%
rename from DllImportGenerator/DllImportGenerator/Marshalling/StringMarshaller.Utf16.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Utf16.cs
index 9ae9bb48c454..a1ceb12d0adf 100644
--- a/DllImportGenerator/DllImportGenerator/Marshalling/StringMarshaller.Utf16.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Utf16.cs
@@ -8,7 +8,7 @@
namespace Microsoft.Interop
{
- internal sealed class Utf16StringMarshaller : ConditionalStackallocMarshallingGenerator
+ public sealed class Utf16StringMarshaller : ConditionalStackallocMarshallingGenerator
{
// [Compat] Equivalent of MAX_PATH on Windows to match built-in system
// The assumption is file paths are the most common case for marshalling strings,
diff --git a/DllImportGenerator/DllImportGenerator/Marshalling/StringMarshaller.Utf8.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Utf8.cs
similarity index 99%
rename from DllImportGenerator/DllImportGenerator/Marshalling/StringMarshaller.Utf8.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Utf8.cs
index a4c52bffa9a2..2a4801e8d3c3 100644
--- a/DllImportGenerator/DllImportGenerator/Marshalling/StringMarshaller.Utf8.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Marshalling/StringMarshaller.Utf8.cs
@@ -8,7 +8,7 @@
namespace Microsoft.Interop
{
- internal sealed class Utf8StringMarshaller : ConditionalStackallocMarshallingGenerator
+ public sealed class Utf8StringMarshaller : ConditionalStackallocMarshallingGenerator
{
// [Compat] Equivalent of MAX_PATH on Windows to match built-in system
// The assumption is file paths are the most common case for marshalling strings,
diff --git a/DllImportGenerator/DllImportGenerator/MarshallingAttributeInfo.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs
similarity index 96%
rename from DllImportGenerator/DllImportGenerator/MarshallingAttributeInfo.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs
index 96988216005c..bbc2d7789145 100644
--- a/DllImportGenerator/DllImportGenerator/MarshallingAttributeInfo.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs
@@ -12,7 +12,7 @@ namespace Microsoft.Interop
///
/// Type used to pass on default marshalling details.
///
- internal sealed record DefaultMarshallingInfo(
+ public sealed record DefaultMarshallingInfo(
CharEncoding CharEncoding
);
@@ -20,11 +20,15 @@ CharEncoding CharEncoding
// for C# vNext discriminated unions. Once discriminated unions are released,
// these should be updated to be implemented as a discriminated union.
- internal abstract record MarshallingInfo
+ public abstract record MarshallingInfo
{
+ // Add a constructor that can only be called by derived types in the same assembly
+ // to enforce that this type cannot be extended by users of this library.
+ private protected MarshallingInfo()
+ {}
}
- internal sealed record NoMarshallingInfo : MarshallingInfo
+ public sealed record NoMarshallingInfo : MarshallingInfo
{
public static readonly MarshallingInfo Instance = new NoMarshallingInfo();
@@ -34,7 +38,7 @@ private NoMarshallingInfo() { }
///
/// Character encoding enumeration.
///
- internal enum CharEncoding
+ public enum CharEncoding
{
Undefined,
Utf8,
@@ -46,14 +50,14 @@ internal enum CharEncoding
///
/// Details that are required when scenario supports strings.
///
- internal record MarshallingInfoStringSupport(
+ public record MarshallingInfoStringSupport(
CharEncoding CharEncoding
) : MarshallingInfo;
///
/// Simple User-application of System.Runtime.InteropServices.MarshalAsAttribute
///
- internal sealed record MarshalAsInfo(
+ public sealed record MarshalAsInfo(
UnmanagedType UnmanagedType,
CharEncoding CharEncoding) : MarshallingInfoStringSupport(CharEncoding)
{
@@ -64,10 +68,10 @@ internal sealed record MarshalAsInfo(
/// or System.Runtime.InteropServices.GeneratedMarshallingAttribute on a blittable type
/// in source in this compilation.
///
- internal sealed record BlittableTypeAttributeInfo : MarshallingInfo;
+ public sealed record BlittableTypeAttributeInfo : MarshallingInfo;
[Flags]
- internal enum CustomMarshallingFeatures
+ public enum CustomMarshallingFeatures
{
None = 0,
ManagedToNative = 0x1,
@@ -78,23 +82,26 @@ internal enum CustomMarshallingFeatures
FreeNativeResources = 0x20,
}
- internal abstract record CountInfo;
+ public abstract record CountInfo
+ {
+ private protected CountInfo() {}
+ }
- internal sealed record NoCountInfo : CountInfo
+ public sealed record NoCountInfo : CountInfo
{
public static readonly NoCountInfo Instance = new NoCountInfo();
private NoCountInfo() { }
}
- internal sealed record ConstSizeCountInfo(int Size) : CountInfo;
+ public sealed record ConstSizeCountInfo(int Size) : CountInfo;
- internal sealed record CountElementCountInfo(TypePositionInfo ElementInfo) : CountInfo
+ public sealed record CountElementCountInfo(TypePositionInfo ElementInfo) : CountInfo
{
public const string ReturnValueElementName = "return-value";
}
- internal sealed record SizeAndParamIndexInfo(int ConstSize, TypePositionInfo? ParamAtIndex) : CountInfo
+ public sealed record SizeAndParamIndexInfo(int ConstSize, TypePositionInfo? ParamAtIndex) : CountInfo
{
public const int UnspecifiedConstSize = -1;
@@ -106,7 +113,7 @@ internal sealed record SizeAndParamIndexInfo(int ConstSize, TypePositionInfo? Pa
///
/// User-applied System.Runtime.InteropServices.NativeMarshallingAttribute
///
- internal record NativeMarshallingAttributeInfo(
+ public record NativeMarshallingAttributeInfo(
ManagedTypeInfo NativeMarshallingType,
ManagedTypeInfo? ValuePropertyType,
CustomMarshallingFeatures MarshallingFeatures,
@@ -116,18 +123,18 @@ internal record NativeMarshallingAttributeInfo(
/// User-applied System.Runtime.InteropServices.GeneratedMarshallingAttribute
/// on a non-blittable type in source in this compilation.
///
- internal sealed record GeneratedNativeMarshallingAttributeInfo(
+ public sealed record GeneratedNativeMarshallingAttributeInfo(
string NativeMarshallingFullyQualifiedTypeName) : MarshallingInfo;
///
/// The type of the element is a SafeHandle-derived type with no marshalling attributes.
///
- internal sealed record SafeHandleMarshallingInfo(bool AccessibleDefaultConstructor, bool IsAbstract) : MarshallingInfo;
+ public sealed record SafeHandleMarshallingInfo(bool AccessibleDefaultConstructor, bool IsAbstract) : MarshallingInfo;
///
/// User-applied System.Runtime.InteropServices.NativeMarshallingAttribute
/// with a contiguous collection marshaller
- internal sealed record NativeContiguousCollectionMarshallingInfo(
+ public sealed record NativeContiguousCollectionMarshallingInfo(
ManagedTypeInfo NativeMarshallingType,
ManagedTypeInfo? ValuePropertyType,
CustomMarshallingFeatures MarshallingFeatures,
@@ -141,10 +148,10 @@ internal sealed record NativeContiguousCollectionMarshallingInfo(
UseDefaultMarshalling
);
- internal class MarshallingAttributeInfoParser
+ public sealed class MarshallingAttributeInfoParser
{
private readonly Compilation _compilation;
- private readonly GeneratorDiagnostics _diagnostics;
+ private readonly IGeneratorDiagnostics _diagnostics;
private readonly DefaultMarshallingInfo _defaultInfo;
private readonly ISymbol _contextSymbol;
private readonly ITypeSymbol _marshalAsAttribute;
@@ -152,7 +159,7 @@ internal class MarshallingAttributeInfoParser
public MarshallingAttributeInfoParser(
Compilation compilation,
- GeneratorDiagnostics diagnostics,
+ IGeneratorDiagnostics diagnostics,
DefaultMarshallingInfo defaultInfo,
ISymbol contextSymbol)
{
diff --git a/DllImportGenerator/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj
new file mode 100644
index 000000000000..8317b0a45f8e
--- /dev/null
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj
@@ -0,0 +1,30 @@
+
+
+
+ netstandard2.0
+ false
+ enable
+ Microsoft.Interop
+
+
+
+
+
+
+
+
+
+ Resources.resx
+ True
+ True
+
+
+
+
+
+ Designer
+ Resources.Designer.cs
+ ResXFileCodeGenerator
+
+
+
diff --git a/DllImportGenerator/Microsoft.Interop.SourceGeneration/Resources.Designer.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Resources.Designer.cs
new file mode 100644
index 000000000000..1d254e29a5c2
--- /dev/null
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Resources.Designer.cs
@@ -0,0 +1,369 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Microsoft.Interop {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.Interop.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'..
+ ///
+ internal static string ArraySizeMustBeSpecified {
+ get {
+ return ResourceManager.GetString("ArraySizeMustBeSpecified", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The 'SizeParamIndex' value in the 'MarshalAsAttribute' is out of range..
+ ///
+ internal static string ArraySizeParamIndexOutOfRange {
+ get {
+ return ResourceManager.GetString("ArraySizeParamIndexOutOfRange", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The 'BlittableTypeAttribute' and 'NativeMarshallingAttribute' attributes are mutually exclusive..
+ ///
+ internal static string CannotHaveMultipleMarshallingAttributesDescription {
+ get {
+ return ResourceManager.GetString("CannotHaveMultipleMarshallingAttributesDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Type '{0}' is marked with 'BlittableTypeAttribute' and 'NativeMarshallingAttribute'. A type can only have one of these two attributes..
+ ///
+ internal static string CannotHaveMultipleMarshallingAttributesMessage {
+ get {
+ return ResourceManager.GetString("CannotHaveMultipleMarshallingAttributesMessage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to A native type with the 'GenericContiguousCollectionMarshallerAttribute' must have at least one of the two marshalling methods as well as a 'ManagedValues' property of type 'Span<T>' for some 'T' and a 'NativeValueStorage' property of type 'Span<byte>' to enable marshalling the managed type..
+ ///
+ internal static string CollectionNativeTypeMustHaveRequiredShapeDescription {
+ get {
+ return ResourceManager.GetString("CollectionNativeTypeMustHaveRequiredShapeDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The native type '{0}' must be a value type and have a constructor that takes two parameters, one of type '{1}' and an 'int', or have a parameterless instance method named 'ToManaged' that returns '{1}' as well as a 'ManagedValues' property of type 'Span<T>' for some 'T' and a 'NativeValueStorage' property of type 'Span<byte>'.
+ ///
+ internal static string CollectionNativeTypeMustHaveRequiredShapeMessage {
+ get {
+ return ResourceManager.GetString("CollectionNativeTypeMustHaveRequiredShapeMessage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The specified collection size parameter for an collection must be an integer type. If the size information is applied to a nested collection, the size parameter must be a collection of one less level of nesting with an integral element..
+ ///
+ internal static string CollectionSizeParamTypeMustBeIntegral {
+ get {
+ return ResourceManager.GetString("CollectionSizeParamTypeMustBeIntegral", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Only one of 'ConstantElementCount' or 'ElementCountInfo' may be used in a 'MarshalUsingAttribute' for a given 'ElementIndirectionLevel'.
+ ///
+ internal static string ConstantAndElementCountInfoDisallowed {
+ get {
+ return ResourceManager.GetString("ConstantAndElementCountInfoDisallowed", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The specified parameter needs to be marshalled from managed to native, but the native type '{0}' does not support it..
+ ///
+ internal static string CustomTypeMarshallingManagedToNativeUnsupported {
+ get {
+ return ResourceManager.GetString("CustomTypeMarshallingManagedToNativeUnsupported", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The specified parameter needs to be marshalled from native to managed, but the native type '{0}' does not support it..
+ ///
+ internal static string CustomTypeMarshallingNativeToManagedUnsupported {
+ get {
+ return ResourceManager.GetString("CustomTypeMarshallingNativeToManagedUnsupported", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to This element cannot depend on '{0}' for collection size information without creating a dependency cycle.
+ ///
+ internal static string CyclicalCountInfo {
+ get {
+ return ResourceManager.GetString("CyclicalCountInfo", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Count information for a given element at a given indirection level can only be specified once.
+ ///
+ internal static string DuplicateCountInfo {
+ get {
+ return ResourceManager.GetString("DuplicateCountInfo", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Multiple marshalling attributes per element per indirection level is unsupported, but duplicate information was provided for indirection level {0}.
+ ///
+ internal static string DuplicateMarshallingInfo {
+ get {
+ return ResourceManager.GetString("DuplicateMarshallingInfo", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Marshalling info was specified for 'ElementIndirectionLevel' {0}, but marshalling info was only needed for {1} level(s) of indirection.
+ ///
+ internal static string ExtraneousMarshallingInfo {
+ get {
+ return ResourceManager.GetString("ExtraneousMarshallingInfo", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The provided graph has cycles and cannot be topologically sorted..
+ ///
+ internal static string GraphHasCycles {
+ get {
+ return ResourceManager.GetString("GraphHasCycles", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The '[In]' attribute is not supported unless the '[Out]' attribute is also used. The behavior of the '[In]' attribute without the '[Out]' attribute is the same as the default behavior..
+ ///
+ internal static string InAttributeNotSupportedWithoutOut {
+ get {
+ return ResourceManager.GetString("InAttributeNotSupportedWithoutOut", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The '[In]' and '[Out]' attributes are unsupported on parameters passed by reference. Use the 'in', 'ref', or 'out' keywords instead..
+ ///
+ internal static string InOutAttributeByRefNotSupported {
+ get {
+ return ResourceManager.GetString("InOutAttributeByRefNotSupported", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The provided '[In]' and '[Out]' attributes on this parameter are unsupported on this parameter..
+ ///
+ internal static string InOutAttributeMarshalerNotSupported {
+ get {
+ return ResourceManager.GetString("InOutAttributeMarshalerNotSupported", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Marshalling char with 'CharSet.{0}' is not supported. Instead, manually convert the char type to the desired byte representation and pass to the source-generated P/Invoke..
+ ///
+ internal static string MarshallingCharAsSpecifiedCharSetNotSupported {
+ get {
+ return ResourceManager.GetString("MarshallingCharAsSpecifiedCharSetNotSupported", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Marshalling string or char without explicit marshalling information is not supported. Specify either 'GeneratedDllImportAttribute.CharSet' or 'MarshalAsAttribute'..
+ ///
+ internal static string MarshallingStringOrCharAsUndefinedNotSupported {
+ get {
+ return ResourceManager.GetString("MarshallingStringOrCharAsUndefinedNotSupported", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The native type '{0}' for managed type '{1}' must be a closed generic type or have the same arity as the managed type..
+ ///
+ internal static string NativeGenericTypeMustBeClosedOrMatchArityMessage {
+ get {
+ return ResourceManager.GetString("NativeGenericTypeMustBeClosedOrMatchArityMessage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The native type must have at least one of the two marshalling methods to enable marshalling the managed type..
+ ///
+ internal static string NativeTypeMustHaveRequiredShapeDescription {
+ get {
+ return ResourceManager.GetString("NativeTypeMustHaveRequiredShapeDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The native type '{0}' must be a value type and have a constructor that takes one parameter of type '{1}' or a parameterless instance method named 'ToManaged' that returns '{1}'.
+ ///
+ internal static string NativeTypeMustHaveRequiredShapeMessage {
+ get {
+ return ResourceManager.GetString("NativeTypeMustHaveRequiredShapeMessage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The '[Out]' attribute is only supported on array parameters..
+ ///
+ internal static string OutByValueNotSupportedDescription {
+ get {
+ return ResourceManager.GetString("OutByValueNotSupportedDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The '[Out]' attribute is not supported on the '{0}' parameter..
+ ///
+ internal static string OutByValueNotSupportedMessage {
+ get {
+ return ResourceManager.GetString("OutByValueNotSupportedMessage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The 'Value' property must not be a 'ref' or 'readonly ref' property..
+ ///
+ internal static string RefValuePropertyUnsupportedDescription {
+ get {
+ return ResourceManager.GetString("RefValuePropertyUnsupportedDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The 'Value' property on the native type '{0}' must not be a 'ref' or 'readonly ref' property..
+ ///
+ internal static string RefValuePropertyUnsupportedMessage {
+ get {
+ return ResourceManager.GetString("RefValuePropertyUnsupportedMessage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to An abstract type derived from 'SafeHandle' cannot be marshalled by reference. The provided type must be concrete..
+ ///
+ internal static string SafeHandleByRefMustBeConcrete {
+ get {
+ return ResourceManager.GetString("SafeHandleByRefMustBeConcrete", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Specified type is not supported by source-generated P/Invokes.
+ ///
+ internal static string TypeNotSupportedTitle {
+ get {
+ return ResourceManager.GetString("TypeNotSupportedTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Marshalling a value between managed and native with a native type with a 'Value' property requires extra state, which is not supported in this context..
+ ///
+ internal static string ValuePropertyMarshallingRequiresAdditionalState {
+ get {
+ return ResourceManager.GetString("ValuePropertyMarshallingRequiresAdditionalState", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The native type's 'Value' property must have a getter to support marshalling from managed to native..
+ ///
+ internal static string ValuePropertyMustHaveGetterDescription {
+ get {
+ return ResourceManager.GetString("ValuePropertyMustHaveGetterDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The 'Value' property on the native type '{0}' must have a getter.
+ ///
+ internal static string ValuePropertyMustHaveGetterMessage {
+ get {
+ return ResourceManager.GetString("ValuePropertyMustHaveGetterMessage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The native type's 'Value' property must have a setter to support marshalling from native to managed..
+ ///
+ internal static string ValuePropertyMustHaveSetterDescription {
+ get {
+ return ResourceManager.GetString("ValuePropertyMustHaveSetterDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The 'Value' property on the native type '{0}' must have a setter.
+ ///
+ internal static string ValuePropertyMustHaveSetterMessage {
+ get {
+ return ResourceManager.GetString("ValuePropertyMustHaveSetterMessage", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/DllImportGenerator/Microsoft.Interop.SourceGeneration/Resources.resx b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Resources.resx
new file mode 100644
index 000000000000..544a1ea46a21
--- /dev/null
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/Resources.resx
@@ -0,0 +1,222 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Marshalling an array from unmanaged to managed requires either the 'SizeParamIndex' or 'SizeConst' fields to be set on a 'MarshalAsAttribute' or the 'ConstantElementCount' or 'CountElementName' properties to be set on a 'MarshalUsingAttribute'.
+
+
+ The 'SizeParamIndex' value in the 'MarshalAsAttribute' is out of range.
+
+
+ The 'BlittableTypeAttribute' and 'NativeMarshallingAttribute' attributes are mutually exclusive.
+
+
+ Type '{0}' is marked with 'BlittableTypeAttribute' and 'NativeMarshallingAttribute'. A type can only have one of these two attributes.
+
+
+ The specified collection size parameter for an collection must be an integer type. If the size information is applied to a nested collection, the size parameter must be a collection of one less level of nesting with an integral element.
+
+
+ The specified parameter needs to be marshalled from managed to native, but the native type '{0}' does not support it.
+
+
+ The specified parameter needs to be marshalled from native to managed, but the native type '{0}' does not support it.
+
+
+ The provided graph has cycles and cannot be topologically sorted.
+
+
+ The '[In]' attribute is not supported unless the '[Out]' attribute is also used. The behavior of the '[In]' attribute without the '[Out]' attribute is the same as the default behavior.
+
+
+ The '[In]' and '[Out]' attributes are unsupported on parameters passed by reference. Use the 'in', 'ref', or 'out' keywords instead.
+
+
+ The provided '[In]' and '[Out]' attributes on this parameter are unsupported on this parameter.
+
+
+ Marshalling char with 'CharSet.{0}' is not supported. Instead, manually convert the char type to the desired byte representation and pass to the source-generated P/Invoke.
+
+
+ Marshalling string or char without explicit marshalling information is not supported. Specify either 'GeneratedDllImportAttribute.CharSet' or 'MarshalAsAttribute'.
+
+
+ The '[Out]' attribute is only supported on array parameters.
+
+
+ The '[Out]' attribute is not supported on the '{0}' parameter.
+
+
+ The 'Value' property must not be a 'ref' or 'readonly ref' property.
+
+
+ The 'Value' property on the native type '{0}' must not be a 'ref' or 'readonly ref' property.
+
+
+ An abstract type derived from 'SafeHandle' cannot be marshalled by reference. The provided type must be concrete.
+
+
+ Specified type is not supported by source-generated P/Invokes
+
+
+ Marshalling a value between managed and native with a native type with a 'Value' property requires extra state, which is not supported in this context.
+
+
+ The native type's 'Value' property must have a getter to support marshalling from managed to native.
+
+
+ The 'Value' property on the native type '{0}' must have a getter
+
+
+ The native type's 'Value' property must have a setter to support marshalling from native to managed.
+
+
+ The 'Value' property on the native type '{0}' must have a setter
+
+
+ This element cannot depend on '{0}' for collection size information without creating a dependency cycle
+
+
+ Count information for a given element at a given indirection level can only be specified once
+
+
+ Multiple marshalling attributes per element per indirection level is unsupported, but duplicate information was provided for indirection level {0}
+
+
+ Marshalling info was specified for 'ElementIndirectionLevel' {0}, but marshalling info was only needed for {1} level(s) of indirection
+
+
+ The native type '{0}' for managed type '{1}' must be a closed generic type or have the same arity as the managed type.
+
+
+ The native type must have at least one of the two marshalling methods to enable marshalling the managed type.
+
+
+ The native type '{0}' must be a value type and have a constructor that takes one parameter of type '{1}' or a parameterless instance method named 'ToManaged' that returns '{1}'
+
+
+ A native type with the 'GenericContiguousCollectionMarshallerAttribute' must have at least one of the two marshalling methods as well as a 'ManagedValues' property of type 'Span<T>' for some 'T' and a 'NativeValueStorage' property of type 'Span<byte>' to enable marshalling the managed type.
+
+
+ The native type '{0}' must be a value type and have a constructor that takes two parameters, one of type '{1}' and an 'int', or have a parameterless instance method named 'ToManaged' that returns '{1}' as well as a 'ManagedValues' property of type 'Span<T>' for some 'T' and a 'NativeValueStorage' property of type 'Span<byte>'
+
+
+ Only one of 'ConstantElementCount' or 'ElementCountInfo' may be used in a 'MarshalUsingAttribute' for a given 'ElementIndirectionLevel'
+
+
\ No newline at end of file
diff --git a/DllImportGenerator/DllImportGenerator/StubCodeContext.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/StubCodeContext.cs
similarity index 98%
rename from DllImportGenerator/DllImportGenerator/StubCodeContext.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/StubCodeContext.cs
index 1fcacdb07a72..ab414c504269 100644
--- a/DllImportGenerator/DllImportGenerator/StubCodeContext.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/StubCodeContext.cs
@@ -3,7 +3,7 @@
namespace Microsoft.Interop
{
- internal abstract class StubCodeContext
+ public abstract class StubCodeContext
{
///
/// Code generation stage
diff --git a/DllImportGenerator/Microsoft.Interop.SourceGeneration/TypeNames.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/TypeNames.cs
new file mode 100644
index 000000000000..a0bb19753fa4
--- /dev/null
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/TypeNames.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.Interop;
+
+namespace Microsoft.Interop
+{
+ static class TypeNames
+ {
+ public const string GeneratedDllImportAttribute = "System.Runtime.InteropServices.GeneratedDllImportAttribute";
+
+ public const string GeneratedMarshallingAttribute = "System.Runtime.InteropServices.GeneratedMarshallingAttribute";
+
+ public const string BlittableTypeAttribute = "System.Runtime.InteropServices.BlittableTypeAttribute";
+
+ public const string NativeMarshallingAttribute = "System.Runtime.InteropServices.NativeMarshallingAttribute";
+
+ public const string MarshalUsingAttribute = "System.Runtime.InteropServices.MarshalUsingAttribute";
+
+ public const string GenericContiguousCollectionMarshallerAttribute = "System.Runtime.InteropServices.GenericContiguousCollectionMarshallerAttribute";
+
+ public const string LCIDConversionAttribute = "System.Runtime.InteropServices.LCIDConversionAttribute";
+
+ public const string System_Span_Metadata = "System.Span`1";
+ public const string System_Span = "System.Span";
+
+ public const string System_Activator = "System.Activator";
+
+ public const string System_Runtime_InteropServices_StructLayoutAttribute = "System.Runtime.InteropServices.StructLayoutAttribute";
+
+ public const string System_Runtime_InteropServices_MarshalAsAttribute = "System.Runtime.InteropServices.MarshalAsAttribute";
+
+ public const string System_Runtime_InteropServices_Marshal = "System.Runtime.InteropServices.Marshal";
+
+ private const string System_Runtime_InteropServices_MarshalEx = "System.Runtime.InteropServices.MarshalEx";
+
+ public static string MarshalEx(InteropGenerationOptions options)
+ {
+ return options.UseMarshalType ? System_Runtime_InteropServices_Marshal : System_Runtime_InteropServices_MarshalEx;
+ }
+
+ public const string System_Runtime_InteropServices_UnmanagedType = "System.Runtime.InteropServices.UnmanagedType";
+
+ public const string System_Runtime_InteropServices_MemoryMarshal = "System.Runtime.InteropServices.MemoryMarshal";
+
+ public const string System_Runtime_InteropServices_GeneratedMarshalling_ArrayMarshaller_Metadata = "System.Runtime.InteropServices.GeneratedMarshalling.ArrayMarshaller`1";
+
+ public const string System_Runtime_InteropServices_GeneratedMarshalling_PtrArrayMarshaller_Metadata = "System.Runtime.InteropServices.GeneratedMarshalling.PtrArrayMarshaller`1";
+
+ public const string System_Runtime_InteropServices_SafeHandle = "System.Runtime.InteropServices.SafeHandle";
+
+ public const string System_Runtime_InteropServices_OutAttribute = "System.Runtime.InteropServices.OutAttribute";
+
+ public const string System_Runtime_InteropServices_InAttribute = "System.Runtime.InteropServices.InAttribute";
+
+ public const string System_Runtime_CompilerServices_SkipLocalsInitAttribute = "System.Runtime.CompilerServices.SkipLocalsInitAttribute";
+
+ private const string System_Runtime_CompilerServices_Unsafe = "System.Runtime.CompilerServices.Unsafe";
+
+ private const string Internal_Runtime_CompilerServices_Unsafe = "Internal.Runtime.CompilerServices.Unsafe";
+
+ public static string Unsafe(InteropGenerationOptions options)
+ {
+ return options.UseInternalUnsafeType ? Internal_Runtime_CompilerServices_Unsafe : System_Runtime_CompilerServices_Unsafe;
+ }
+ }
+}
diff --git a/DllImportGenerator/DllImportGenerator/TypePositionInfo.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/TypePositionInfo.cs
similarity index 96%
rename from DllImportGenerator/DllImportGenerator/TypePositionInfo.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/TypePositionInfo.cs
index 2cbbcb87becc..a7d730d08b08 100644
--- a/DllImportGenerator/DllImportGenerator/TypePositionInfo.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/TypePositionInfo.cs
@@ -15,7 +15,7 @@ namespace Microsoft.Interop
/// contents of the managed array.
///
[Flags]
- internal enum ByValueContentsMarshalKind
+ public enum ByValueContentsMarshalKind
{
///
/// Marshal contents from managed to native only.
@@ -40,7 +40,7 @@ internal enum ByValueContentsMarshalKind
///
/// Positional type information involved in unmanaged/managed scenarios.
///
- internal sealed record TypePositionInfo(ManagedTypeInfo ManagedType, MarshallingInfo MarshallingAttributeInfo)
+ public sealed record TypePositionInfo(ManagedTypeInfo ManagedType, MarshallingInfo MarshallingAttributeInfo)
{
public const int UnsetIndex = int.MinValue;
public const int ReturnIndex = UnsetIndex + 1;
diff --git a/DllImportGenerator/DllImportGenerator/TypeSymbolExtensions.cs b/DllImportGenerator/Microsoft.Interop.SourceGeneration/TypeSymbolExtensions.cs
similarity index 99%
rename from DllImportGenerator/DllImportGenerator/TypeSymbolExtensions.cs
rename to DllImportGenerator/Microsoft.Interop.SourceGeneration/TypeSymbolExtensions.cs
index e9b3b8261a95..8587c0780acc 100644
--- a/DllImportGenerator/DllImportGenerator/TypeSymbolExtensions.cs
+++ b/DllImportGenerator/Microsoft.Interop.SourceGeneration/TypeSymbolExtensions.cs
@@ -11,7 +11,7 @@
namespace Microsoft.Interop
{
- static class TypeSymbolExtensions
+ public static class TypeSymbolExtensions
{
public static bool HasOnlyBlittableFields(this ITypeSymbol type) => HasOnlyBlittableFields(type, ImmutableHashSet.Create(SymbolEqualityComparer.Default));