// The .NET Foundation licenses this file to you under the MIT license.
using System;
-using System.Collections.Generic;
using System.Collections.Immutable;
-using System.Diagnostics;
+using System.IO;
using System.Linq;
using System.Threading;
-using System.Xml.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
[Generator]
public sealed class ComInterfaceGenerator : IIncrementalGenerator
{
- private sealed record ComInterfaceContext(int MethodStartIndex, Guid InterfaceId);
+ private sealed record ComInterfaceContext(
+ ManagedTypeInfo InterfaceType,
+ ContainingSyntaxContext TypeDefinitionContext,
+ ContainingSyntax InterfaceTypeSyntax,
+ int MethodStartIndex,
+ Guid InterfaceId);
+
+ private sealed record class GeneratedStubCodeContext(
+ ManagedTypeInfo OriginalDefiningType,
+ ContainingSyntaxContext ContainingSyntaxContext,
+ SyntaxEquivalentNode<MethodDeclarationSyntax> Stub,
+ SequenceEqualImmutableArray<Diagnostic> Diagnostics) : GeneratedMethodContextBase(OriginalDefiningType, Diagnostics);
+
+ private sealed record SkippedStubContext(ManagedTypeInfo OriginalDefiningType) : GeneratedMethodContextBase(OriginalDefiningType, new(ImmutableArray<Diagnostic>.Empty));
public static class StepNames
{
public const string CalculateStubInformation = nameof(CalculateStubInformation);
public const string GenerateManagedToNativeStub = nameof(GenerateManagedToNativeStub);
public const string GenerateNativeToManagedStub = nameof(GenerateNativeToManagedStub);
+ public const string GenerateManagedToNativeInterfaceImplementation = nameof(GenerateManagedToNativeInterfaceImplementation);
+ public const string GenerateNativeToManagedVTableMethods = nameof(GenerateNativeToManagedVTableMethods);
+ public const string GenerateNativeToManagedVTable = nameof(GenerateNativeToManagedVTable);
+ public const string GenerateInterfaceInformation = nameof(GenerateInterfaceInformation);
+ public const string GenerateIUnknownDerivedAttribute = nameof(GenerateIUnknownDerivedAttribute);
}
- private static readonly ContainingSyntax NativeTypeContainingSyntax = new(
- TokenList(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.PartialKeyword)),
- SyntaxKind.InterfaceDeclaration,
- Identifier("Native"),
- null);
-
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// Get all methods with the [GeneratedComInterface] attribute.
{
// Start at offset 3 as 0-2 are IUnknown.
// TODO: Calculate starting offset based on base types.
- // TODO: Extract IID from source.
- return new ComInterfaceContext(3, Guid.Empty);
+ Guid? guid = null;
+ var guidAttr = data.Symbol.GetAttributes().Where(attr => attr.AttributeClass.ToDisplayString() == TypeNames.System_Runtime_InteropServices_GuidAttribute).SingleOrDefault();
+ if (guidAttr is not null)
+ {
+ string? guidstr = guidAttr.ConstructorArguments.SingleOrDefault().Value as string;
+ if (guidstr is not null)
+ guid = new Guid(guidstr);
+ }
+ return new ComInterfaceContext(
+ ManagedTypeInfo.CreateTypeInfoForTypeSymbol(data.Symbol),
+ new ContainingSyntaxContext(data.Syntax),
+ new ContainingSyntax(data.Syntax.Modifiers, data.Syntax.Kind(), data.Syntax.Identifier, data.Syntax.TypeParameterList),
+ 3,
+ guid ?? Guid.Empty);
});
- context.RegisterSourceOutput(invalidTypeDiagnostics, static (context, invalidType) =>
- {
- context.ReportDiagnostic(invalidType.Diagnostic);
- });
+ context.RegisterDiagnostics(invalidTypeDiagnostics.Select((data, ct) => data.Diagnostic));
// Zip the incremental interface context back with the symbols and syntax for the interface
// to calculate the methods to generate.
// The generator infrastructure preserves ordering of the tables once Select statements are in use,
// so we can rely on the order matching here.
- var methodsWithDiagnostics = interfacesToGenerate
+ var interfacesWithMethods = interfacesToGenerate
.Zip(interfaceContexts)
- .SelectMany(static (data, ct) =>
+ .Select(static (data, ct) =>
{
var (interfaceData, interfaceContext) = data;
- ContainingSyntaxContext containingSyntax = new(interfaceData.Syntax);
Location interfaceLocation = interfaceData.Syntax.GetLocation();
var methods = ImmutableArray.CreateBuilder<(MethodDeclarationSyntax Syntax, IMethodSymbol Symbol, int Index, Diagnostic? Diagnostic)>();
int methodVtableOffset = interfaceContext.MethodStartIndex;
}
}
}
- return methods.ToImmutable();
+ return (Interface: interfaceContext, Methods: methods.ToImmutable());
});
+ var interfaceWithMethodsContexts = interfacesWithMethods
+ .Where(data => data.Methods.Length > 0)
+ .Select(static (data, ct) => data.Interface);
+
+ // Marker interfaces are COM interfaces that don't have any methods.
+ // The lack of methods breaks the mechanism we use later to stitch back together interface-level data
+ // and method-level data, but that's okay because marker interfaces are much simpler.
+ // We'll handle them seperately because they are so simple.
+ var markerInterfaces = interfacesWithMethods
+ .Where(data => data.Methods.Length == 0)
+ .Select(static (data, ct) => data.Interface);
+
+ var markerInterfaceIUnknownDerived = markerInterfaces.Select(static (context, ct) => GenerateIUnknownDerivedAttributeApplication(context))
+ .WithComparer(SyntaxEquivalentComparer.Instance)
+ .SelectNormalized();
+
+ context.RegisterSourceOutput(markerInterfaces.Zip(markerInterfaceIUnknownDerived), (context, data) =>
+ {
+ var (interfaceContext, iUnknownDerivedAttributeApplication) = data;
+ context.AddSource(
+ interfaceContext.InterfaceType.FullTypeName.Replace("global::", ""),
+ GenerateMarkerInterfaceSource(interfaceContext) + iUnknownDerivedAttributeApplication);
+ });
+
+ var methodsWithDiagnostics = interfacesWithMethods.SelectMany(static (data, ct) => data.Methods);
+
// Split the methods we want to generate and the ones we don't into two separate groups.
var methodsToGenerate = methodsWithDiagnostics.Where(static data => data.Diagnostic is null);
var invalidMethodDiagnostics = methodsWithDiagnostics.Where(static data => data.Diagnostic is not null);
.WithTrackingName(StepNames.CalculateStubInformation);
// Generate the code for the managed-to-unmanaged stubs and the diagnostics from code-generation.
- IncrementalValuesProvider<(MemberDeclarationSyntax, ImmutableArray<Diagnostic>)> generateManagedToNativeStub = generateStubInformation
- .Where(data => data.VtableIndexData.Direction is MarshalDirection.ManagedToUnmanaged or MarshalDirection.Bidirectional)
+ var generateManagedToNativeStub = generateStubInformation
.Select(
- static (data, ct) => VtableIndexStubGenerator.GenerateManagedToNativeStub(data)
+ static (data, ct) =>
+ {
+ if (data.VtableIndexData.Direction is not (MarshalDirection.ManagedToUnmanaged or MarshalDirection.Bidirectional))
+ {
+ return (GeneratedMethodContextBase)new SkippedStubContext(data.OriginalDefiningType);
+ }
+ var (methodStub, diagnostics) = VirtualMethodPointerStubGenerator.GenerateManagedToNativeStub(data);
+ return new GeneratedStubCodeContext(data.TypeKeyOwner, data.ContainingSyntaxContext, new(methodStub), new(diagnostics));
+ }
)
- .WithComparer(Comparers.GeneratedSyntax)
.WithTrackingName(StepNames.GenerateManagedToNativeStub);
- context.RegisterDiagnostics(generateManagedToNativeStub.SelectMany((stubInfo, ct) => stubInfo.Item2));
+ context.RegisterDiagnostics(generateManagedToNativeStub.SelectMany((stubInfo, ct) => stubInfo.Diagnostics.Array));
- context.RegisterConcatenatedSyntaxOutputs(generateManagedToNativeStub.Select((data, ct) => data.Item1), "ManagedToNativeStubs.g.cs");
+ var managedToNativeInterfaceImplementations = generateManagedToNativeStub
+ .Collect()
+ .SelectMany(static (stubs, ct) => GroupContextsForInterfaceGeneration(stubs))
+ .Select(static (interfaceGroup, ct) => GenerateImplementationInterface(interfaceGroup.Array))
+ .WithTrackingName(StepNames.GenerateManagedToNativeInterfaceImplementation)
+ .WithComparer(SyntaxEquivalentComparer.Instance)
+ .SelectNormalized();
// Filter the list of all stubs to only the stubs that requested unmanaged-to-managed stub generation.
IncrementalValuesProvider<IncrementalMethodStubGenerationContext> nativeToManagedStubContexts =
generateStubInformation
- .Where(data => data.VtableIndexData.Direction is MarshalDirection.UnmanagedToManaged or MarshalDirection.Bidirectional);
+ .Where(static data => data.VtableIndexData.Direction is MarshalDirection.UnmanagedToManaged or MarshalDirection.Bidirectional);
// Generate the code for the unmanaged-to-managed stubs and the diagnostics from code-generation.
- IncrementalValuesProvider<(MemberDeclarationSyntax, ImmutableArray<Diagnostic>)> generateNativeToManagedStub = nativeToManagedStubContexts
+ var generateNativeToManagedStub = generateStubInformation
.Select(
- static (data, ct) => VtableIndexStubGenerator.GenerateNativeToManagedStub(data)
+ static (data, ct) =>
+ {
+ if (data.VtableIndexData.Direction is not (MarshalDirection.UnmanagedToManaged or MarshalDirection.Bidirectional))
+ {
+ return (GeneratedMethodContextBase)new SkippedStubContext(data.OriginalDefiningType);
+ }
+ var (methodStub, diagnostics) = VirtualMethodPointerStubGenerator.GenerateNativeToManagedStub(data);
+ return new GeneratedStubCodeContext(data.OriginalDefiningType, data.ContainingSyntaxContext, new(methodStub), new(diagnostics));
+ }
)
- .WithComparer(Comparers.GeneratedSyntax)
.WithTrackingName(StepNames.GenerateNativeToManagedStub);
- context.RegisterDiagnostics(generateNativeToManagedStub.SelectMany((stubInfo, ct) => stubInfo.Item2));
-
- context.RegisterConcatenatedSyntaxOutputs(generateNativeToManagedStub.Select((data, ct) => data.Item1), "NativeToManagedStubs.g.cs");
+ context.RegisterDiagnostics(generateNativeToManagedStub.SelectMany((stubInfo, ct) => stubInfo.Diagnostics.Array));
- // Generate the native interface metadata for each interface that contains a method with the [VirtualMethodIndex] attribute.
- IncrementalValuesProvider<MemberDeclarationSyntax> generateNativeInterface = generateStubInformation
- .Select(static (context, ct) => context.ContainingSyntaxContext)
+ var nativeToManagedVtableMethods = generateNativeToManagedStub
.Collect()
- .SelectMany(static (syntaxContexts, ct) => syntaxContexts.Distinct())
- .Select(static (context, ct) => GenerateNativeInterfaceMetadata(context));
+ .SelectMany(static (stubs, ct) => GroupContextsForInterfaceGeneration(stubs))
+ .Select(static (interfaceGroup, ct) => GenerateImplementationVTableMethods(interfaceGroup.Array))
+ .WithTrackingName(StepNames.GenerateNativeToManagedVTableMethods)
+ .WithComparer(SyntaxEquivalentComparer.Instance)
+ .SelectNormalized();
+
+ // Generate the native interface metadata for each [GeneratedComInterface]-attributed interface.
+ var nativeInterfaceInformation = interfaceWithMethodsContexts
+ .Select(static (context, ct) => GenerateInterfaceInformation(context))
+ .WithTrackingName(StepNames.GenerateInterfaceInformation)
+ .WithComparer(SyntaxEquivalentComparer.Instance)
+ .SelectNormalized();
+
+ // Generate a method named CreateManagedVirtualFunctionTable on the native interface implementation
+ // that allocates and fills in the memory for the vtable.
+ var nativeToManagedVtables =
+ generateStubInformation
+ .Collect()
+ .SelectMany(static (data, ct) => GroupContextsForInterfaceGeneration(data.CastArray<GeneratedMethodContextBase>()))
+ .Select(static (vtable, ct) => GenerateImplementationVTable(ImmutableArray.CreateRange(vtable.Array.Cast<IncrementalMethodStubGenerationContext>())))
+ .WithTrackingName(StepNames.GenerateNativeToManagedVTable)
+ .WithComparer(SyntaxEquivalentComparer.Instance)
+ .SelectNormalized();
+
+ var iUnknownDerivedAttributeApplication = interfaceWithMethodsContexts
+ .Select(static (context, ct) => GenerateIUnknownDerivedAttributeApplication(context))
+ .WithTrackingName(StepNames.GenerateIUnknownDerivedAttribute)
+ .WithComparer(SyntaxEquivalentComparer.Instance)
+ .SelectNormalized();
+
+ var filesToGenerate = interfaceWithMethodsContexts
+ .Zip(nativeInterfaceInformation)
+ .Zip(managedToNativeInterfaceImplementations)
+ .Zip(nativeToManagedVtableMethods)
+ .Zip(nativeToManagedVtables)
+ .Zip(iUnknownDerivedAttributeApplication)
+ .Select(static (data, ct) =>
+ {
+ var (((((interfaceContext, interfaceInfo), managedToNativeStubs), nativeToManagedStubs), nativeToManagedVtable), iUnknownDerivedAttribute) = data;
+
+ using StringWriter source = new();
+ interfaceInfo.WriteTo(source);
+ // Two newlines looks cleaner than one
+ source.WriteLine();
+ source.WriteLine();
+ // TODO: Merge the three InterfaceImplementation partials? We have them all right here.
+ managedToNativeStubs.WriteTo(source);
+ source.WriteLine();
+ source.WriteLine();
+ nativeToManagedStubs.WriteTo(source);
+ source.WriteLine();
+ source.WriteLine();
+ nativeToManagedVtable.WriteTo(source);
+ source.WriteLine();
+ source.WriteLine();
+ iUnknownDerivedAttribute.WriteTo(source);
+ return new { TypeName = interfaceContext.InterfaceType.FullTypeName, Source = source.ToString() };
+ });
+
+ context.RegisterSourceOutput(filesToGenerate, (context, data) =>
+ {
+ context.AddSource(data.TypeName.Replace("global::", ""), data.Source);
+ });
+ }
- context.RegisterConcatenatedSyntaxOutputs(generateNativeInterface, "NativeInterfaces.g.cs");
+ private static string GenerateMarkerInterfaceSource(ComInterfaceContext iface) => $$"""
+ file unsafe class InterfaceInformation : global::System.Runtime.InteropServices.Marshalling.IIUnknownInterfaceType
+ {
+ public static global::System.Guid Iid => new(new global::System.ReadOnlySpan<byte>(new byte[] { {{string.Join(",", iface.InterfaceId.ToByteArray())}} }));
- // Generate a method named PopulateUnmanagedVirtualMethodTable on the native interface implementation
- // that fills in a span with the addresses of the unmanaged-to-managed stub functions at their correct
- // indices.
- IncrementalValuesProvider<MemberDeclarationSyntax> populateVTable =
- nativeToManagedStubContexts
- .Collect()
- .SelectMany(static (data, ct) => data.GroupBy(stub => stub.ContainingSyntaxContext))
- .Select(static (vtable, ct) => GeneratePopulateVTableMethod(vtable));
+ private static void** m_vtable;
- context.RegisterConcatenatedSyntaxOutputs(populateVTable, "PopulateVTable.g.cs");
- }
+ public static void* VirtualMethodTableManagedImplementation
+ {
+ get
+ {
+ if (m_vtable == null)
+ {
+ nint* vtable = (nint*)global::System.Runtime.CompilerServices.RuntimeHelpers.AllocateTypeAssociatedMemory(typeof({{iface.InterfaceType.FullTypeName}}), sizeof(nint) * 3);
+ global::System.Runtime.InteropServices.ComWrappers.GetIUnknownImpl(out vtable[0], out vtable[1], out vtable[2]);
+ m_vtable = (void**)vtable;
+ }
+ return m_vtable;
+ }
+ }
+ }
+
+ [global::System.Runtime.InteropServices.DynamicInterfaceCastableImplementation]
+ file interface InterfaceImplementation : {{iface.InterfaceType.FullTypeName}}
+ {}
+ """;
+
+ private static readonly AttributeSyntax s_iUnknownDerivedAttributeTemplate =
+ Attribute(
+ GenericName(TypeNames.IUnknownDerivedAttribute)
+ .AddTypeArgumentListArguments(
+ IdentifierName("InterfaceInformation"),
+ IdentifierName("InterfaceImplementation")));
+
+ private static MemberDeclarationSyntax GenerateIUnknownDerivedAttributeApplication(ComInterfaceContext context)
+ => context.TypeDefinitionContext.WrapMemberInContainingSyntaxWithUnsafeModifier(
+ TypeDeclaration(context.InterfaceTypeSyntax.TypeKind, context.InterfaceTypeSyntax.Identifier)
+ .WithModifiers(context.InterfaceTypeSyntax.Modifiers)
+ .WithTypeParameterList(context.InterfaceTypeSyntax.TypeParameters)
+ .AddAttributeLists(AttributeList(SingletonSeparatedList(s_iUnknownDerivedAttributeTemplate))));
private static IncrementalMethodStubGenerationContext CalculateStubInformation(MethodDeclarationSyntax syntax, IMethodSymbol symbol, int index, StubEnvironment environment, CancellationToken ct)
{
return Diagnostic.Create(GeneratorDiagnostics.InvalidAttributedMethodContainingTypeMissingModifiers, syntax.Identifier.GetLocation(), type.Name, typeDecl.Identifier);
}
}
+ var guidAttr = type.GetAttributes().Where(attr => attr.AttributeClass.ToDisplayString() == TypeNames.System_Runtime_InteropServices_GuidAttribute).SingleOrDefault();
+ var interfaceTypeAttr = type.GetAttributes().Where(attr => attr.AttributeClass.ToDisplayString() == TypeNames.InterfaceTypeAttribute).SingleOrDefault();
+ // Assume interfaceType is IUnknown for now
+ if (interfaceTypeAttr is not null
+ && (guidAttr is null
+ || guidAttr.ConstructorArguments.SingleOrDefault().Value as string is null))
+ {
+ return Diagnostic.Create(GeneratorDiagnostics.InvalidAttributedInterfaceMissingGuidAttribute, syntax.Identifier.GetLocation(), type.ToDisplayString());
+ // Missing Guid
+ }
return null;
}
return null;
}
- private static MemberDeclarationSyntax GenerateNativeInterfaceMetadata(ContainingSyntaxContext context)
+ private static ImmutableArray<SequenceEqualImmutableArray<GeneratedMethodContextBase>> GroupContextsForInterfaceGeneration(ImmutableArray<GeneratedMethodContextBase> contexts)
+ {
+ // We can end up with an empty set of contexts here as the compiler will call a SelectMany
+ // after a Collect with no input entries
+ if (contexts.IsEmpty)
+ {
+ return ImmutableArray<SequenceEqualImmutableArray<GeneratedMethodContextBase>>.Empty;
+ }
+
+ ImmutableArray<SequenceEqualImmutableArray<GeneratedMethodContextBase>>.Builder allGroupsBuilder = ImmutableArray.CreateBuilder<SequenceEqualImmutableArray<GeneratedMethodContextBase>>();
+
+ // Due to how the source generator driver processes the input item tables and our limitation that methods on COM interfaces can only be defined in a single partial definition of the type,
+ // we can guarantee that the method contexts are ordered as follows:
+ // - I1.M1
+ // - I1.M2
+ // - I1.M3
+ // - I2.M1
+ // - I2.M2
+ // - I2.M3
+ // - I3.M1
+ // - etc...
+ // This enable us to group our contexts by their containing syntax rather simply.
+ ManagedTypeInfo? lastSeenDefiningType = null;
+ ImmutableArray<GeneratedMethodContextBase>.Builder groupBuilder = ImmutableArray.CreateBuilder<GeneratedMethodContextBase>();
+ foreach (var context in contexts)
+ {
+ if (lastSeenDefiningType is null || lastSeenDefiningType == context.OriginalDefiningType)
+ {
+ groupBuilder.Add(context);
+ }
+ else
+ {
+ allGroupsBuilder.Add(new(groupBuilder.ToImmutable()));
+ groupBuilder.Clear();
+ groupBuilder.Add(context);
+ }
+ lastSeenDefiningType = context.OriginalDefiningType;
+ }
+
+ allGroupsBuilder.Add(new(groupBuilder.ToImmutable()));
+ return allGroupsBuilder.ToImmutable();
+ }
+
+ private static readonly InterfaceDeclarationSyntax ImplementationInterfaceTemplate = InterfaceDeclaration("InterfaceImplementation")
+ .WithModifiers(TokenList(Token(SyntaxKind.FileKeyword), Token(SyntaxKind.UnsafeKeyword), Token(SyntaxKind.PartialKeyword)));
+ private static InterfaceDeclarationSyntax GenerateImplementationInterface(ImmutableArray<GeneratedMethodContextBase> interfaceGroup)
+ {
+ var definingType = interfaceGroup[0].OriginalDefiningType;
+ return ImplementationInterfaceTemplate
+ .AddBaseListTypes(SimpleBaseType(definingType.Syntax))
+ .WithMembers(List<MemberDeclarationSyntax>(interfaceGroup.OfType<GeneratedStubCodeContext>().Select(context => context.Stub.Node)))
+ .AddAttributeLists(AttributeList(SingletonSeparatedList(Attribute(ParseName(TypeNames.System_Runtime_InteropServices_DynamicInterfaceCastableImplementationAttribute)))));
+ }
+ private static InterfaceDeclarationSyntax GenerateImplementationVTableMethods(ImmutableArray<GeneratedMethodContextBase> interfaceGroup)
{
- return context.WrapMemberInContainingSyntaxWithUnsafeModifier(
- InterfaceDeclaration("Native")
- .WithModifiers(TokenList(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.PartialKeyword)))
- .WithBaseList(BaseList(SingletonSeparatedList((BaseTypeSyntax)SimpleBaseType(IdentifierName(context.ContainingSyntax[0].Identifier)))))
- .AddAttributeLists(AttributeList(SingletonSeparatedList(Attribute(ParseName(TypeNames.System_Runtime_InteropServices_DynamicInterfaceCastableImplementationAttribute))))));
+ return ImplementationInterfaceTemplate
+ .WithMembers(List<MemberDeclarationSyntax>(interfaceGroup.OfType<GeneratedStubCodeContext>().Select(context => context.Stub.Node)));
}
- private const string VTableParameterName = "vtable";
- private static readonly MethodDeclarationSyntax ManagedVirtualMethodTableImplementationSyntaxTemplate =
- MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)),
- "PopulateUnmanagedVirtualMethodTable")
- .WithModifiers(TokenList(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.StaticKeyword)))
- .AddParameterListParameters(
- Parameter(Identifier(VTableParameterName))
- .WithType(GenericName(TypeNames.System_Span).AddTypeArgumentListArguments(IdentifierName("nint"))));
+ private static readonly TypeSyntax VoidStarStarSyntax = PointerType(PointerType(PredefinedType(Token(SyntaxKind.VoidKeyword))));
- private static MemberDeclarationSyntax GeneratePopulateVTableMethod(IGrouping<ContainingSyntaxContext, IncrementalMethodStubGenerationContext> vtableMethods)
+ private const string CreateManagedVirtualFunctionTableMethodName = "CreateManagedVirtualFunctionTable";
+
+ private static readonly MethodDeclarationSyntax CreateManagedVirtualFunctionTableMethodTemplate = MethodDeclaration(VoidStarStarSyntax, CreateManagedVirtualFunctionTableMethodName)
+ .AddModifiers(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.StaticKeyword));
+ private static InterfaceDeclarationSyntax GenerateImplementationVTable(ImmutableArray<IncrementalMethodStubGenerationContext> interfaceMethodStubs)
{
- ContainingSyntaxContext containingSyntax = vtableMethods.Key.AddContainingSyntax(NativeTypeContainingSyntax);
- MethodDeclarationSyntax populateVtableMethod = ManagedVirtualMethodTableImplementationSyntaxTemplate;
+ const string vtableLocalName = "vtable";
+ var interfaceType = interfaceMethodStubs[0].OriginalDefiningType;
+
+ ImmutableArray<IncrementalMethodStubGenerationContext> vtableExposedContexts = interfaceMethodStubs
+ .Where(c => c.VtableIndexData.Direction is MarshalDirection.UnmanagedToManaged or MarshalDirection.Bidirectional)
+ .ToImmutableArray();
- foreach (var method in vtableMethods)
+ // If none of the methods are exposed as part of the vtable, then don't emit
+ // a vtable (return null).
+ if (vtableExposedContexts.Length == 0)
{
- FunctionPointerTypeSyntax functionPointerType = VtableIndexStubGenerator.GenerateUnmanagedFunctionPointerTypeForMethod(method);
+ return ImplementationInterfaceTemplate
+ .AddMembers(
+ CreateManagedVirtualFunctionTableMethodTemplate
+ .WithBody(
+ Block(
+ ReturnStatement(LiteralExpression(SyntaxKind.NullLiteralExpression)))));
+ }
- // <vtableParameter>[<index>] = (nint)(<functionPointerType>)&ABI_<methodIdentifier>;
- populateVtableMethod = populateVtableMethod.AddBodyStatements(
+ // void** vtable = (void**)RuntimeHelpers.AllocateTypeAssociatedMemory(<interfaceType>, sizeof(void*) * <interfaceMethodStubs.Array.Length>);
+ var vtableDeclarationStatement =
+ LocalDeclarationStatement(
+ VariableDeclaration(
+ VoidStarStarSyntax,
+ SingletonSeparatedList(
+ VariableDeclarator(vtableLocalName)
+ .WithInitializer(
+ EqualsValueClause(
+ CastExpression(VoidStarStarSyntax,
+ InvocationExpression(
+ MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
+ ParseTypeName(TypeNames.System_Runtime_CompilerServices_RuntimeHelpers),
+ IdentifierName("AllocateTypeAssociatedMemory")))
+ .AddArgumentListArguments(
+ Argument(TypeOfExpression(interfaceType.Syntax)),
+ Argument(
+ BinaryExpression(
+ SyntaxKind.MultiplyExpression,
+ SizeOfExpression(PointerType(PredefinedType(Token(SyntaxKind.VoidKeyword)))),
+ LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(interfaceMethodStubs.Length)))))))))));
+
+ var fillIUnknownSlots = Block()
+ .AddStatements(
+ // nint v0, v1, v2;
+ LocalDeclarationStatement(VariableDeclaration(ParseTypeName("nint"))
+ .AddVariables(
+ VariableDeclarator("v0"),
+ VariableDeclarator("v1"),
+ VariableDeclarator("v2")
+ )),
+ // ComWrappers.GetIUnknownImpl(out v0, out v1, out v2);
ExpressionStatement(
- AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
+ InvocationExpression(
+ MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
+ ParseTypeName(TypeNames.System_Runtime_InteropServices_ComWrappers),
+ IdentifierName("GetIUnknownImpl")))
+ .AddArgumentListArguments(
+ Argument(IdentifierName("v0"))
+ .WithRefKindKeyword(Token(SyntaxKind.OutKeyword)),
+ Argument(IdentifierName("v1"))
+ .WithRefKindKeyword(Token(SyntaxKind.OutKeyword)),
+ Argument(IdentifierName("v2"))
+ .WithRefKindKeyword(Token(SyntaxKind.OutKeyword)))),
+ // m_vtable[0] = (void*)v0;
+ ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
ElementAccessExpression(
- IdentifierName(VTableParameterName))
- .AddArgumentListArguments(Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(method.VtableIndexData.Index)))),
- CastExpression(IdentifierName("nint"),
- CastExpression(functionPointerType,
- PrefixUnaryExpression(SyntaxKind.AddressOfExpression,
- IdentifierName($"ABI_{method.StubMethodSyntaxTemplate.Identifier}")))))));
- }
+ IdentifierName(vtableLocalName),
+ BracketedArgumentList(
+ SingletonSeparatedList(
+ Argument(
+ LiteralExpression(
+ SyntaxKind.NumericLiteralExpression,
+ Literal(0)))))),
+ CastExpression(
+ PointerType(
+ PredefinedType(Token(SyntaxKind.VoidKeyword))),
+ IdentifierName("v0")))),
+ // m_vtable[1] = (void*)v1;
+ ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
+ ElementAccessExpression(
+ IdentifierName(vtableLocalName),
+ BracketedArgumentList(
+ SingletonSeparatedList(
+ Argument(
+ LiteralExpression(
+ SyntaxKind.NumericLiteralExpression,
+ Literal(1)))))),
+ CastExpression(
+ PointerType(
+ PredefinedType(Token(SyntaxKind.VoidKeyword))),
+ IdentifierName("v1")))),
+ // m_vtable[2] = (void*)v2;
+ ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
+ ElementAccessExpression(
+ IdentifierName(vtableLocalName),
+ BracketedArgumentList(
+ SingletonSeparatedList(
+ Argument(
+ LiteralExpression(
+ SyntaxKind.NumericLiteralExpression,
+ Literal(2)))))),
+ CastExpression(
+ PointerType(
+ PredefinedType(Token(SyntaxKind.VoidKeyword))),
+ IdentifierName("v2")))));
+
+ var vtableSlotAssignments = VirtualMethodPointerStubGenerator.GenerateVirtualMethodTableSlotAssignments(interfaceMethodStubs, vtableLocalName);
+
+ return ImplementationInterfaceTemplate
+ .AddMembers(
+ CreateManagedVirtualFunctionTableMethodTemplate
+ .WithBody(
+ Block(
+ vtableDeclarationStatement,
+ fillIUnknownSlots,
+ vtableSlotAssignments,
+ ReturnStatement(IdentifierName(vtableLocalName)))));
+ }
+
+ private static readonly ClassDeclarationSyntax InterfaceInformationTypeTemplate =
+ ClassDeclaration("InterfaceInformation")
+ .AddModifiers(Token(SyntaxKind.FileKeyword), Token(SyntaxKind.UnsafeKeyword))
+ .AddBaseListTypes(SimpleBaseType(ParseTypeName(TypeNames.IIUnknownInterfaceType)));
+
+ private static ClassDeclarationSyntax GenerateInterfaceInformation(ComInterfaceContext context)
+ {
+ const string vtableFieldName = "_vtable";
+ return InterfaceInformationTypeTemplate
+ .AddMembers(
+ // public static System.Guid Iid { get; } = new(<embeddedDataBlob>);
+ PropertyDeclaration(ParseTypeName(TypeNames.System_Guid), "Iid")
+ .AddModifiers(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword))
+ .AddAccessorListAccessors(
+ AccessorDeclaration(SyntaxKind.GetAccessorDeclaration).WithSemicolonToken(Token(SyntaxKind.SemicolonToken)))
+ .WithInitializer(
+ EqualsValueClause(
+ ImplicitObjectCreationExpression()
+ .AddArgumentListArguments(
+ Argument(CreateEmbeddedDataBlobCreationStatement(context.InterfaceId.ToByteArray())))))
+ .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
+ // private static void** _vtable;
+ FieldDeclaration(VariableDeclaration(VoidStarStarSyntax, SingletonSeparatedList(VariableDeclarator(vtableFieldName))))
+ .AddModifiers(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.StaticKeyword)),
+ // public static void* VirtualMethodTableManagedImplementation => _vtable != null ? _vtable : (_vtable = InterfaceImplementation.CreateManagedVirtualMethodTable());
+ PropertyDeclaration(PointerType(PredefinedType(Token(SyntaxKind.VoidKeyword))), "VirtualMethodTableManagedImplementation")
+ .AddModifiers(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword))
+ .WithExpressionBody(
+ ArrowExpressionClause(
+ ConditionalExpression(
+ BinaryExpression(SyntaxKind.EqualsExpression,
+ IdentifierName(vtableFieldName),
+ LiteralExpression(SyntaxKind.NullLiteralExpression)),
+ IdentifierName(vtableFieldName),
+ ParenthesizedExpression(
+ AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
+ IdentifierName(vtableFieldName),
+ InvocationExpression(
+ MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
+ IdentifierName("InterfaceImplementation"),
+ IdentifierName(CreateManagedVirtualFunctionTableMethodName))))))))
+ .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))
+ );
+
+ static ExpressionSyntax CreateEmbeddedDataBlobCreationStatement(ReadOnlySpan<byte> bytes)
+ {
+ var literals = new LiteralExpressionSyntax[bytes.Length];
- return containingSyntax.WrapMemberInContainingSyntaxWithUnsafeModifier(populateVtableMethod);
+ for (int i = 0; i < bytes.Length; i++)
+ {
+ literals[i] = LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(bytes[i]));
+ }
+
+ // new System.ReadOnlySpan<byte>(new[] { <byte literals> } )
+ return ObjectCreationExpression(
+ GenericName(TypeNames.System_ReadOnlySpan)
+ .AddTypeArgumentListArguments(PredefinedType(Token(SyntaxKind.ByteKeyword))))
+ .AddArgumentListArguments(
+ Argument(
+ ArrayCreationExpression(
+ ArrayType(PredefinedType(Token(SyntaxKind.ByteKeyword)), SingletonList(ArrayRankSpecifier())),
+ InitializerExpression(
+ SyntaxKind.ArrayInitializerExpression,
+ SeparatedList<ExpressionSyntax>(literals)))));
+ }
}
}
}
public const string TypeNotSupported = Prefix + "1051";
public const string ConfigurationNotSupported = Prefix + "1052";
public const string MethodNotDeclaredInAttributedInterface = Prefix + "1091";
+ public const string InvalidGeneratedComInterfaceAttributeUsage = Prefix + "1092";
}
private const string Category = "ComInterfaceGenerator";
isEnabledByDefault: true,
description: GetResourceString(nameof(SR.MethodNotDeclaredInAttributedInterfaceDescription)));
+ public static readonly DiagnosticDescriptor InvalidAttributedInterfaceMissingGuidAttribute =
+ new DiagnosticDescriptor(
+ Ids.InvalidGeneratedComInterfaceAttributeUsage,
+ GetResourceString(nameof(SR.InvalidGeneratedComInterfaceAttributeUsageTitle)),
+ GetResourceString(nameof(SR.InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute)),
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: GetResourceString(nameof(SR.InvalidGeneratedComInterfaceAttributeUsageDescription)));
private readonly List<Diagnostic> _diagnostics = new List<Diagnostic>();
public IEnumerable<Diagnostic> Diagnostics => _diagnostics;
+
/// <summary>
/// Report diagnostic for invalid configuration for string marshalling.
/// </summary>
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
+using System.Collections.Immutable;
namespace Microsoft.Interop
{
+ internal abstract record GeneratedMethodContextBase(ManagedTypeInfo OriginalDefiningType, SequenceEqualImmutableArray<Diagnostic> Diagnostics);
+
internal sealed record IncrementalMethodStubGenerationContext(
SignatureContext SignatureContext,
ContainingSyntaxContext ContainingSyntaxContext,
MarshallingGeneratorFactoryKey<(TargetFramework TargetFramework, Version TargetFrameworkVersion)> UnmanagedToManagedGeneratorFactory,
ManagedTypeInfo TypeKeyOwner,
SequenceEqualImmutableArray<Diagnostic> Diagnostics,
- TypeSyntax UnwrapperSyntax);
+ TypeSyntax UnwrapperSyntax) : GeneratedMethodContextBase(TypeKeyOwner, Diagnostics);
}
return builder.MoveToImmutable();
});
}
+
+ public static IncrementalValuesProvider<TNode> SelectNormalized<TNode>(this IncrementalValuesProvider<TNode> provider)
+ where TNode : SyntaxNode
+ {
+ return provider.Select((node, ct) => node.NormalizeWhitespace());
+ }
}
}
-<?xml version="1.0" encoding="utf-8"?>
-<root>
- <!--
- Microsoft ResX Schema
-
- Version 2.0
-
- The primary goals of this format is to allow a simple XML format
- that is mostly human readable. The generation and parsing of the
- various data types are done through the TypeConverter classes
- associated with the data types.
-
- Example:
-
- ... ado.net/XML headers & schema ...
- <resheader name="resmimetype">text/microsoft-resx</resheader>
- <resheader name="version">2.0</resheader>
- <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
- <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
- <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
- <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
- <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
- <value>[base64 mime encoded serialized .NET Framework object]</value>
- </data>
- <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
- <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
- <comment>This is a comment</comment>
- </data>
-
- There are any number of "resheader" rows that contain simple
- name/value pairs.
-
- Each data row contains a name, and value. The row also contains a
- type or mimetype. Type corresponds to a .NET class that support
- text/value conversion through the TypeConverter architecture.
- Classes that don't support this are serialized and stored with the
- mimetype set.
-
- The mimetype is used for serialized objects, and tells the
- ResXResourceReader how to depersist the object. This is currently not
- extensible. For a given mimetype the value must be set accordingly:
-
- Note - application/x-microsoft.net.object.binary.base64 is the format
- that the ResXResourceWriter will generate, however the reader can
- read any of the formats listed below.
-
- mimetype: application/x-microsoft.net.object.binary.base64
- value : The object must be serialized with
- : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
- : and then encoded with base64 encoding.
-
- mimetype: application/x-microsoft.net.object.soap.base64
- value : The object must be serialized with
- : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
- : and then encoded with base64 encoding.
-
- mimetype: application/x-microsoft.net.object.bytearray.base64
- value : The object must be serialized into a byte array
- : using a System.ComponentModel.TypeConverter
- : and then encoded with base64 encoding.
- -->
- <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
- <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
- <xsd:element name="root" msdata:IsDataSet="true">
- <xsd:complexType>
- <xsd:choice maxOccurs="unbounded">
- <xsd:element name="metadata">
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element name="value" type="xsd:string" minOccurs="0" />
- </xsd:sequence>
- <xsd:attribute name="name" use="required" type="xsd:string" />
- <xsd:attribute name="type" type="xsd:string" />
- <xsd:attribute name="mimetype" type="xsd:string" />
- <xsd:attribute ref="xml:space" />
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="assembly">
- <xsd:complexType>
- <xsd:attribute name="alias" type="xsd:string" />
- <xsd:attribute name="name" type="xsd:string" />
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="data">
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
- <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
- </xsd:sequence>
- <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
- <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
- <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
- <xsd:attribute ref="xml:space" />
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="resheader">
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
- </xsd:sequence>
- <xsd:attribute name="name" type="xsd:string" use="required" />
- </xsd:complexType>
- </xsd:element>
- </xsd:choice>
- </xsd:complexType>
- </xsd:element>
- </xsd:schema>
- <resheader name="resmimetype">
- <value>text/microsoft-resx</value>
- </resheader>
- <resheader name="version">
- <value>2.0</value>
- </resheader>
- <resheader name="reader">
- <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
- </resheader>
- <resheader name="writer">
- <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
- </resheader>
- <data name="ConfigurationNotSupportedDescription" xml:space="preserve">
- <value>Source-generated P/Invokes will ignore any configuration that is not supported.</value>
- </data>
- <data name="ConfigurationNotSupportedMessage" xml:space="preserve">
- <value>The '{0}' configuration is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead.</value>
- </data>
- <data name="ConfigurationNotSupportedMessageMarshallingInfo" xml:space="preserve">
- <value>The specified marshalling configuration is not supported by source-generated P/Invokes. {0}.</value>
- </data>
- <data name="ConfigurationNotSupportedMessageParameter" xml:space="preserve">
- <value>The specified '{0}' configuration for parameter '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead.</value>
- </data>
- <data name="ConfigurationNotSupportedMessageReturn" xml:space="preserve">
- <value>The specified '{0}' configuration for the return value of method '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead.</value>
- </data>
- <data name="ConfigurationNotSupportedMessageValue" xml:space="preserve">
- <value>The specified value '{0}' for '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead.</value>
- </data>
- <data name="ConfigurationNotSupportedTitle" xml:space="preserve">
- <value>Specified configuration is not supported by source-generated P/Invokes.</value>
- </data>
- <data name="InvalidStringMarshallingConfigurationDescription" xml:space="preserve">
- <value>The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid.</value>
- </data>
- <data name="InvalidStringMarshallingConfigurationMessage" xml:space="preserve">
- <value>The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' on method '{0}' is invalid. {1}</value>
- <comment>{1} is a message containing additional details about what is not valid</comment>
- </data>
- <data name="InvalidStringMarshallingConfigurationMissingCustomType" xml:space="preserve">
- <value>'StringMarshallingCustomType' must be specified when 'StringMarshalling' is set to 'StringMarshalling.Custom'.</value>
- </data>
- <data name="InvalidStringMarshallingConfigurationNotCustom" xml:space="preserve">
- <value>'StringMarshalling' should be set to 'StringMarshalling.Custom' when 'StringMarshallingCustomType' is specified.</value>
- </data>
- <data name="TypeNotSupportedDescription" xml:space="preserve">
- <value>For types that are not supported by source-generated P/Invokes, the resulting P/Invoke will rely on the underlying runtime to marshal the specified type.</value>
- </data>
- <data name="TypeNotSupportedMessageParameter" xml:space="preserve">
- <value>The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter '{1}'.</value>
- </data>
- <data name="TypeNotSupportedMessageParameterWithDetails" xml:space="preserve">
- <value>{0} The generated source will not handle marshalling of parameter '{1}'.</value>
- <comment>{0} is a message containing additional details about what is not supported
-{1} is the name of the parameter</comment>
- </data>
- <data name="TypeNotSupportedMessageReturn" xml:space="preserve">
- <value>The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of the return value of method '{1}'.</value>
- </data>
- <data name="TypeNotSupportedMessageReturnWithDetails" xml:space="preserve">
- <value>{0} The generated source will not handle marshalling of the return value of method '{1}'.</value>
- <comment>{0} is a message containing additional details about what is not supported
-{1} is the name of the method</comment>
- </data>
- <data name="TypeNotSupportedTitle" xml:space="preserve">
- <value>Specified type is not supported by source-generated P/Invokes</value>
- </data>
- <data name="InvalidAttributedMethodContainingTypeMissingModifiersMessage" xml:space="preserve">
- <value>Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'.</value>
- </data>
- <data name="InvalidAttributedMethodDescription" xml:space="preserve">
- <value>Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic.</value>
- </data>
- <data name="InvalidAttributedMethodSignatureMessage" xml:space="preserve">
- <value>Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'.</value>
- </data>
- <data name="InvalidVirtualMethodIndexAttributeUsage" xml:space="preserve">
- <value>Invalid 'VirtualMethodIndexAttribute' usage</value>
- </data>
- <data name="InvalidExceptionMarshallingConfigurationDescription" xml:space="preserve">
- <value>The configuration of 'ExceptionMarshalling' and 'ExceptionMarshallingCustomType' is invalid.</value>
- </data>
- <data name="InvalidExceptionMarshallingConfigurationMessage" xml:space="preserve">
- <value>The configuration of 'ExceptionMarshalling' and 'ExceptionMarshallingCustomType' on method '{0}' is invalid. {1}</value>
- <comment>{1} is a message containing additional details about what is not valid</comment>
- </data>
- <data name="InvalidExceptionMarshallingConfigurationMissingCustomType" xml:space="preserve">
- <value>'ExceptionMarshallingCustomType' must be specified when 'ExceptionMarshalling' is set to 'ExceptionMarshalling.Custom'.</value>
- </data>
- <data name="InvalidExceptionMarshallingConfigurationNotCustom" xml:space="preserve">
- <value>'ExceptionMarshalling' should be set to 'ExceptionMarshalling.Custom' when 'ExceptionMarshallingCustomType' is specified.</value>
- </data>
- <data name="InvalidExceptionMarshallingValue" xml:space="preserve">
- <value>The provided value is not a known flag of the 'ExceptionMarshalling' enum.</value>
- </data>
- <data name="InterfaceTypeNotSupportedTitle" xml:space="preserve">
- <value>'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type.</value>
- </data>
- <data name="InterfaceTypeNotSupportedMessage" xml:space="preserve">
- <value>Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'.</value>
- </data>
- <data name="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage" xml:space="preserve">
- <value>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </value>
- </data>
- <data name="MethodNotDeclaredInAttributedInterfaceDescription" xml:space="preserve">
- <value>All methods must be declared in the same partial definition of a 'GeneratedComInterface'-attributed interface type to ensure reliable calculation for virtual method table offsets.</value>
- </data>
- <data name="MethodNotDeclaredInAttributedInterfaceMessage" xml:space="preserve">
- <value>The method '{0}' is declared on a different partial definition of the interface '{1}' than the definition that has the 'GeneratedComInterface' attribute</value>
- </data>
- <data name="MethodNotDeclaredInAttributedInterfaceTitle" xml:space="preserve">
- <value>Method is declared in different partial declaration than the 'GeneratedComInterface' attribute.</value>
- </data>
-</root>
+<?xml version="1.0" encoding="utf-8"?>\r
+<root>\r
+ <!-- \r
+ Microsoft ResX Schema \r
+ \r
+ Version 2.0\r
+ \r
+ The primary goals of this format is to allow a simple XML format \r
+ that is mostly human readable. The generation and parsing of the \r
+ various data types are done through the TypeConverter classes \r
+ associated with the data types.\r
+ \r
+ Example:\r
+ \r
+ ... ado.net/XML headers & schema ...\r
+ <resheader name="resmimetype">text/microsoft-resx</resheader>\r
+ <resheader name="version">2.0</resheader>\r
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\r
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\r
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>\r
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>\r
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">\r
+ <value>[base64 mime encoded serialized .NET Framework object]</value>\r
+ </data>\r
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">\r
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\r
+ <comment>This is a comment</comment>\r
+ </data>\r
+ \r
+ There are any number of "resheader" rows that contain simple \r
+ name/value pairs.\r
+ \r
+ Each data row contains a name, and value. The row also contains a \r
+ type or mimetype. Type corresponds to a .NET class that support \r
+ text/value conversion through the TypeConverter architecture. \r
+ Classes that don't support this are serialized and stored with the \r
+ mimetype set.\r
+ \r
+ The mimetype is used for serialized objects, and tells the \r
+ ResXResourceReader how to depersist the object. This is currently not \r
+ extensible. For a given mimetype the value must be set accordingly:\r
+ \r
+ Note - application/x-microsoft.net.object.binary.base64 is the format \r
+ that the ResXResourceWriter will generate, however the reader can \r
+ read any of the formats listed below.\r
+ \r
+ mimetype: application/x-microsoft.net.object.binary.base64\r
+ value : The object must be serialized with \r
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\r
+ : and then encoded with base64 encoding.\r
+ \r
+ mimetype: application/x-microsoft.net.object.soap.base64\r
+ value : The object must be serialized with \r
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\r
+ : and then encoded with base64 encoding.\r
+\r
+ mimetype: application/x-microsoft.net.object.bytearray.base64\r
+ value : The object must be serialized into a byte array \r
+ : using a System.ComponentModel.TypeConverter\r
+ : and then encoded with base64 encoding.\r
+ -->\r
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">\r
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />\r
+ <xsd:element name="root" msdata:IsDataSet="true">\r
+ <xsd:complexType>\r
+ <xsd:choice maxOccurs="unbounded">\r
+ <xsd:element name="metadata">\r
+ <xsd:complexType>\r
+ <xsd:sequence>\r
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />\r
+ </xsd:sequence>\r
+ <xsd:attribute name="name" use="required" type="xsd:string" />\r
+ <xsd:attribute name="type" type="xsd:string" />\r
+ <xsd:attribute name="mimetype" type="xsd:string" />\r
+ <xsd:attribute ref="xml:space" />\r
+ </xsd:complexType>\r
+ </xsd:element>\r
+ <xsd:element name="assembly">\r
+ <xsd:complexType>\r
+ <xsd:attribute name="alias" type="xsd:string" />\r
+ <xsd:attribute name="name" type="xsd:string" />\r
+ </xsd:complexType>\r
+ </xsd:element>\r
+ <xsd:element name="data">\r
+ <xsd:complexType>\r
+ <xsd:sequence>\r
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />\r
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />\r
+ </xsd:sequence>\r
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />\r
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />\r
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />\r
+ <xsd:attribute ref="xml:space" />\r
+ </xsd:complexType>\r
+ </xsd:element>\r
+ <xsd:element name="resheader">\r
+ <xsd:complexType>\r
+ <xsd:sequence>\r
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />\r
+ </xsd:sequence>\r
+ <xsd:attribute name="name" type="xsd:string" use="required" />\r
+ </xsd:complexType>\r
+ </xsd:element>\r
+ </xsd:choice>\r
+ </xsd:complexType>\r
+ </xsd:element>\r
+ </xsd:schema>\r
+ <resheader name="resmimetype">\r
+ <value>text/microsoft-resx</value>\r
+ </resheader>\r
+ <resheader name="version">\r
+ <value>2.0</value>\r
+ </resheader>\r
+ <resheader name="reader">\r
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r
+ </resheader>\r
+ <resheader name="writer">\r
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r
+ </resheader>\r
+ <data name="ConfigurationNotSupportedDescription" xml:space="preserve">\r
+ <value>Source-generated P/Invokes will ignore any configuration that is not supported.</value>\r
+ </data>\r
+ <data name="ConfigurationNotSupportedMessage" xml:space="preserve">\r
+ <value>The '{0}' configuration is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead.</value>\r
+ </data>\r
+ <data name="ConfigurationNotSupportedMessageMarshallingInfo" xml:space="preserve">\r
+ <value>The specified marshalling configuration is not supported by source-generated P/Invokes. {0}.</value>\r
+ </data>\r
+ <data name="ConfigurationNotSupportedMessageParameter" xml:space="preserve">\r
+ <value>The specified '{0}' configuration for parameter '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead.</value>\r
+ </data>\r
+ <data name="ConfigurationNotSupportedMessageReturn" xml:space="preserve">\r
+ <value>The specified '{0}' configuration for the return value of method '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead.</value>\r
+ </data>\r
+ <data name="ConfigurationNotSupportedMessageValue" xml:space="preserve">\r
+ <value>The specified value '{0}' for '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead.</value>\r
+ </data>\r
+ <data name="ConfigurationNotSupportedTitle" xml:space="preserve">\r
+ <value>Specified configuration is not supported by source-generated P/Invokes.</value>\r
+ </data>\r
+ <data name="InvalidStringMarshallingConfigurationDescription" xml:space="preserve">\r
+ <value>The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid.</value>\r
+ </data>\r
+ <data name="InvalidStringMarshallingConfigurationMessage" xml:space="preserve">\r
+ <value>The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' on method '{0}' is invalid. {1}</value>\r
+ <comment>{1} is a message containing additional details about what is not valid</comment>\r
+ </data>\r
+ <data name="InvalidStringMarshallingConfigurationMissingCustomType" xml:space="preserve">\r
+ <value>'StringMarshallingCustomType' must be specified when 'StringMarshalling' is set to 'StringMarshalling.Custom'.</value>\r
+ </data>\r
+ <data name="InvalidStringMarshallingConfigurationNotCustom" xml:space="preserve">\r
+ <value>'StringMarshalling' should be set to 'StringMarshalling.Custom' when 'StringMarshallingCustomType' is specified.</value>\r
+ </data>\r
+ <data name="TypeNotSupportedDescription" xml:space="preserve">\r
+ <value>For types that are not supported by source-generated P/Invokes, the resulting P/Invoke will rely on the underlying runtime to marshal the specified type.</value>\r
+ </data>\r
+ <data name="TypeNotSupportedMessageParameter" xml:space="preserve">\r
+ <value>The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter '{1}'.</value>\r
+ </data>\r
+ <data name="TypeNotSupportedMessageParameterWithDetails" xml:space="preserve">\r
+ <value>{0} The generated source will not handle marshalling of parameter '{1}'.</value>\r
+ <comment>{0} is a message containing additional details about what is not supported\r
+{1} is the name of the parameter</comment>\r
+ </data>\r
+ <data name="TypeNotSupportedMessageReturn" xml:space="preserve">\r
+ <value>The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of the return value of method '{1}'.</value>\r
+ </data>\r
+ <data name="TypeNotSupportedMessageReturnWithDetails" xml:space="preserve">\r
+ <value>{0} The generated source will not handle marshalling of the return value of method '{1}'.</value>\r
+ <comment>{0} is a message containing additional details about what is not supported\r
+{1} is the name of the method</comment>\r
+ </data>\r
+ <data name="TypeNotSupportedTitle" xml:space="preserve">\r
+ <value>Specified type is not supported by source-generated P/Invokes</value>\r
+ </data>\r
+ <data name="InvalidAttributedMethodContainingTypeMissingModifiersMessage" xml:space="preserve">\r
+ <value>Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'.</value>\r
+ </data>\r
+ <data name="InvalidAttributedMethodDescription" xml:space="preserve">\r
+ <value>Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic.</value>\r
+ </data>\r
+ <data name="InvalidAttributedMethodSignatureMessage" xml:space="preserve">\r
+ <value>Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'.</value>\r
+ </data>\r
+ <data name="InvalidVirtualMethodIndexAttributeUsage" xml:space="preserve">\r
+ <value>Invalid 'VirtualMethodIndexAttribute' usage</value>\r
+ </data>\r
+ <data name="InvalidExceptionMarshallingConfigurationDescription" xml:space="preserve">\r
+ <value>The configuration of 'ExceptionMarshalling' and 'ExceptionMarshallingCustomType' is invalid.</value>\r
+ </data>\r
+ <data name="InvalidExceptionMarshallingConfigurationMessage" xml:space="preserve">\r
+ <value>The configuration of 'ExceptionMarshalling' and 'ExceptionMarshallingCustomType' on method '{0}' is invalid. {1}</value>\r
+ <comment>{1} is a message containing additional details about what is not valid</comment>\r
+ </data>\r
+ <data name="InvalidExceptionMarshallingConfigurationMissingCustomType" xml:space="preserve">\r
+ <value>'ExceptionMarshallingCustomType' must be specified when 'ExceptionMarshalling' is set to 'ExceptionMarshalling.Custom'.</value>\r
+ </data>\r
+ <data name="InvalidExceptionMarshallingConfigurationNotCustom" xml:space="preserve">\r
+ <value>'ExceptionMarshalling' should be set to 'ExceptionMarshalling.Custom' when 'ExceptionMarshallingCustomType' is specified.</value>\r
+ </data>\r
+ <data name="InvalidExceptionMarshallingValue" xml:space="preserve">\r
+ <value>The provided value is not a known flag of the 'ExceptionMarshalling' enum.</value>\r
+ </data>\r
+ <data name="InterfaceTypeNotSupportedTitle" xml:space="preserve">\r
+ <value>'GeneratedComInterfaceType' does not support the 'ComInterfaceType' value supplied to 'InterfaceTypeAttribute' on the same type.</value>\r
+ </data>\r
+ <data name="InterfaceTypeNotSupportedMessage" xml:space="preserve">\r
+ <value>Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'.</value>\r
+ </data>\r
+ <data name="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage" xml:space="preserve">\r
+ <value>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </value>\r
+ </data>\r
+ <data name="MethodNotDeclaredInAttributedInterfaceDescription" xml:space="preserve">\r
+ <value>All methods must be declared in the same partial definition of a 'GeneratedComInterface'-attributed interface type to ensure reliable calculation for virtual method table offsets.</value>\r
+ </data>\r
+ <data name="MethodNotDeclaredInAttributedInterfaceMessage" xml:space="preserve">\r
+ <value>The method '{0}' is declared on a different partial definition of the interface '{1}' than the definition that has the 'GeneratedComInterface' attribute</value>\r
+ </data>\r
+ <data name="MethodNotDeclaredInAttributedInterfaceTitle" xml:space="preserve">\r
+ <value>Method is declared in different partial declaration than the 'GeneratedComInterface' attribute.</value>\r
+ </data>\r
+ <data name="InvalidGeneratedComInterfaceAttributeUsageDescription" xml:space="preserve">\r
+ <value>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</value>\r
+ </data>\r
+ <data name="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute" xml:space="preserve">\r
+ <value>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</value>\r
+ </data>\r
+ <data name="InvalidGeneratedComInterfaceAttributeUsageTitle" xml:space="preserve">\r
+ <value>Invalid 'GeneratedComInterfaceAttribute' usage.</value>\r
+ </data>\r
+</root>\r
\ No newline at end of file
<target state="translated">Zadaná hodnota není známý příznak výčtu ExceptionMarsnuming.</target>
<note />
</trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageTitle">
+ <source>Invalid 'GeneratedComInterfaceAttribute' usage.</source>
+ <target state="new">Invalid 'GeneratedComInterfaceAttribute' usage.</target>
+ <note />
+ </trans-unit>
<trans-unit id="InvalidStringMarshallingConfigurationDescription">
<source>The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid.</source>
<target state="translated">Konfigurace StringMarshalling a StringMarshallingCustomType je neplatná.</target>
<target state="translated">Der angegebene Wert ist kein bekanntes Flag der „ExceptionMarshalling“-Enumeration.</target>
<note />
</trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageTitle">
+ <source>Invalid 'GeneratedComInterfaceAttribute' usage.</source>
+ <target state="new">Invalid 'GeneratedComInterfaceAttribute' usage.</target>
+ <note />
+ </trans-unit>
<trans-unit id="InvalidStringMarshallingConfigurationDescription">
<source>The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid.</source>
<target state="translated">Die Konfiguration von \"StringMarshalling\" und \"StringMarshallingCustomType\" ist ungültig.</target>
<target state="translated">El valor proporcionado no es una marca conocida de la enumeración “ExceptionMarshalling”.</target>
<note />
</trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageTitle">
+ <source>Invalid 'GeneratedComInterfaceAttribute' usage.</source>
+ <target state="new">Invalid 'GeneratedComInterfaceAttribute' usage.</target>
+ <note />
+ </trans-unit>
<trans-unit id="InvalidStringMarshallingConfigurationDescription">
<source>The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid.</source>
<target state="translated">La configuración de “StringMarshalling” y “StringMarshallingCustomType” no es válida.</target>
<target state="translated">La valeur fournie n’est pas un indicateur connu de l’énumération « ExceptionMarshalling ».</target>
<note />
</trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageTitle">
+ <source>Invalid 'GeneratedComInterfaceAttribute' usage.</source>
+ <target state="new">Invalid 'GeneratedComInterfaceAttribute' usage.</target>
+ <note />
+ </trans-unit>
<trans-unit id="InvalidStringMarshallingConfigurationDescription">
<source>The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid.</source>
<target state="translated">La configuration de « StringMarshalling » et de « StringMarshallingCustomType » n’est pas valide.</target>
<target state="translated">Il valore specificato non è un flag noto dell'enumerazione 'ExceptionMarshalling'.</target>
<note />
</trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageTitle">
+ <source>Invalid 'GeneratedComInterfaceAttribute' usage.</source>
+ <target state="new">Invalid 'GeneratedComInterfaceAttribute' usage.</target>
+ <note />
+ </trans-unit>
<trans-unit id="InvalidStringMarshallingConfigurationDescription">
<source>The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid.</source>
<target state="translated">La configurazione di 'StringMarshalling' e 'StringMarshallingCustomType' non è valida.</target>
<target state="translated">指定された値は、'ExceptionMarshalling' 列挙型の既知のフラグではありません。</target>
<note />
</trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageTitle">
+ <source>Invalid 'GeneratedComInterfaceAttribute' usage.</source>
+ <target state="new">Invalid 'GeneratedComInterfaceAttribute' usage.</target>
+ <note />
+ </trans-unit>
<trans-unit id="InvalidStringMarshallingConfigurationDescription">
<source>The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid.</source>
<target state="translated">'StringMarshalling' と 'StringMarshallingCustomType' の構成が無効です。</target>
<target state="translated">제공된 값은 'ExceptionMarshalling' 열거형의 알려진 플래그가 아닙니다.</target>
<note />
</trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageTitle">
+ <source>Invalid 'GeneratedComInterfaceAttribute' usage.</source>
+ <target state="new">Invalid 'GeneratedComInterfaceAttribute' usage.</target>
+ <note />
+ </trans-unit>
<trans-unit id="InvalidStringMarshallingConfigurationDescription">
<source>The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid.</source>
<target state="translated">'StringMarshalling' 및 'StringMarshallingCustomType'의 구성이 잘못되었습니다.</target>
<target state="translated">Podana wartość nie jest znaną flagą wyliczenia „'ExceptionMarshalling”.</target>
<note />
</trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageTitle">
+ <source>Invalid 'GeneratedComInterfaceAttribute' usage.</source>
+ <target state="new">Invalid 'GeneratedComInterfaceAttribute' usage.</target>
+ <note />
+ </trans-unit>
<trans-unit id="InvalidStringMarshallingConfigurationDescription">
<source>The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid.</source>
<target state="translated">Konfiguracja elementów „StringMarshalling” i „StringMarshallingCustomType” jest nieprawidłowa.</target>
<target state="translated">O valor fornecido não é um sinalizador conhecido da enumeração 'ExceptionMarshalling'.</target>
<note />
</trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageTitle">
+ <source>Invalid 'GeneratedComInterfaceAttribute' usage.</source>
+ <target state="new">Invalid 'GeneratedComInterfaceAttribute' usage.</target>
+ <note />
+ </trans-unit>
<trans-unit id="InvalidStringMarshallingConfigurationDescription">
<source>The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid.</source>
<target state="translated">A configuração de 'StringMarshalling' e 'StringMarshallingCustomType' é inválida.</target>
<target state="translated">Указанное значение не является известным флагом перечисления ExceptionMarshalling.</target>
<note />
</trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageTitle">
+ <source>Invalid 'GeneratedComInterfaceAttribute' usage.</source>
+ <target state="new">Invalid 'GeneratedComInterfaceAttribute' usage.</target>
+ <note />
+ </trans-unit>
<trans-unit id="InvalidStringMarshallingConfigurationDescription">
<source>The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid.</source>
<target state="translated">Конфигурация \"StringMarshalling\" и \"StringMarshallingCustomType\" недопустима.</target>
<target state="translated">Sağlanan değer bilinen bir 'ExceptionMarshalling' sabit listesi bayrağı değil.</target>
<note />
</trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageTitle">
+ <source>Invalid 'GeneratedComInterfaceAttribute' usage.</source>
+ <target state="new">Invalid 'GeneratedComInterfaceAttribute' usage.</target>
+ <note />
+ </trans-unit>
<trans-unit id="InvalidStringMarshallingConfigurationDescription">
<source>The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid.</source>
<target state="translated">'StringMarshalling' ve 'StringMarshallingCustomType' yapılandırması geçersiz.</target>
<target state="translated">提供的值不是 “ExceptionMarshalling” 枚举的已知标志。</target>
<note />
</trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageTitle">
+ <source>Invalid 'GeneratedComInterfaceAttribute' usage.</source>
+ <target state="new">Invalid 'GeneratedComInterfaceAttribute' usage.</target>
+ <note />
+ </trans-unit>
<trans-unit id="InvalidStringMarshallingConfigurationDescription">
<source>The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid.</source>
<target state="translated">“StringMarshalling” 和 “StringMarshallingCustomType” 的配置无效。</target>
<target state="translated">提供的值不是 'ExceptionMarshalling' 列舉的已知旗標。</target>
<note />
</trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageDescription">
+ <source>Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interfaces attributed with 'GeneratedComInterfaceAttribute' must be partial and must specify a GUID with 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageMissingGuidAttribute">
+ <source>Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</source>
+ <target state="new">Interface '{0}' is attributed with 'GeneratedComInterfaceAttribute' but is missing 'System.Runtime.InteropServices.GuidAttribute'.</target>
+ <note />
+ </trans-unit>
+ <trans-unit id="InvalidGeneratedComInterfaceAttributeUsageTitle">
+ <source>Invalid 'GeneratedComInterfaceAttribute' usage.</source>
+ <target state="new">Invalid 'GeneratedComInterfaceAttribute' usage.</target>
+ <note />
+ </trans-unit>
<trans-unit id="InvalidStringMarshallingConfigurationDescription">
<source>The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid.</source>
<target state="translated">'StringMarshalling' 和 'StringMarshallingCustomType' 的設定無效。</target>
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Text;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.CSharp;
+using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
+using Microsoft.CodeAnalysis;
+using System.Diagnostics;
+
+namespace Microsoft.Interop
+{
+ internal static class VirtualMethodPointerStubGenerator
+ {
+ public static (MethodDeclarationSyntax, ImmutableArray<Diagnostic>) GenerateManagedToNativeStub(
+ IncrementalMethodStubGenerationContext methodStub)
+ {
+ var diagnostics = new GeneratorDiagnostics();
+
+ // Generate stub code
+ var stubGenerator = new ManagedToNativeVTableMethodGenerator(
+ methodStub.ManagedToUnmanagedGeneratorFactory.Key.TargetFramework,
+ methodStub.ManagedToUnmanagedGeneratorFactory.Key.TargetFrameworkVersion,
+ methodStub.SignatureContext.ElementTypeInformation,
+ methodStub.VtableIndexData.SetLastError,
+ methodStub.VtableIndexData.ImplicitThisParameter,
+ (elementInfo, ex) =>
+ {
+ diagnostics.ReportMarshallingNotSupported(methodStub.DiagnosticLocation, elementInfo, ex.NotSupportedDetails);
+ },
+ methodStub.ManagedToUnmanagedGeneratorFactory.GeneratorFactory);
+
+ BlockSyntax code = stubGenerator.GenerateStubBody(
+ methodStub.VtableIndexData.Index,
+ methodStub.CallingConvention.Array,
+ methodStub.TypeKeyOwner.Syntax);
+
+ // The owner type will always be an interface type, so the syntax will always be a NameSyntax as it's the name of a named type
+ // with no additional decorators.
+ Debug.Assert(methodStub.TypeKeyOwner.Syntax is NameSyntax);
+
+ return (
+ PrintGeneratedSource(
+ methodStub.StubMethodSyntaxTemplate,
+ methodStub.SignatureContext,
+ code)
+ .WithExplicitInterfaceSpecifier(ExplicitInterfaceSpecifier((NameSyntax)methodStub.TypeKeyOwner.Syntax)),
+ methodStub.Diagnostics.Array.AddRange(diagnostics.Diagnostics));
+ }
+ private static MethodDeclarationSyntax PrintGeneratedSource(
+ ContainingSyntax stubMethodSyntax,
+ SignatureContext stub,
+ BlockSyntax stubCode)
+ {
+ // Create stub function
+ return MethodDeclaration(stub.StubReturnType, stubMethodSyntax.Identifier)
+ .AddAttributeLists(stub.AdditionalAttributes.ToArray())
+ .WithModifiers(stubMethodSyntax.Modifiers.StripTriviaFromTokens())
+ .WithParameterList(ParameterList(SeparatedList(stub.StubParameters)))
+ .WithBody(stubCode);
+ }
+
+ private const string ThisParameterIdentifier = "@this";
+
+ public static (MethodDeclarationSyntax, ImmutableArray<Diagnostic>) GenerateNativeToManagedStub(
+ IncrementalMethodStubGenerationContext methodStub)
+ {
+ var diagnostics = new GeneratorDiagnostics();
+ ImmutableArray<TypePositionInfo> elements = AddImplicitElementInfos(methodStub);
+
+ // Generate stub code
+ var stubGenerator = new UnmanagedToManagedStubGenerator(
+ methodStub.UnmanagedToManagedGeneratorFactory.Key.TargetFramework,
+ methodStub.UnmanagedToManagedGeneratorFactory.Key.TargetFrameworkVersion,
+ elements,
+ (elementInfo, ex) =>
+ {
+ diagnostics.ReportMarshallingNotSupported(methodStub.DiagnosticLocation, elementInfo, ex.NotSupportedDetails);
+ },
+ methodStub.UnmanagedToManagedGeneratorFactory.GeneratorFactory);
+
+ BlockSyntax code = stubGenerator.GenerateStubBody(
+ MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
+ IdentifierName(ThisParameterIdentifier),
+ IdentifierName(methodStub.StubMethodSyntaxTemplate.Identifier)));
+
+ (ParameterListSyntax unmanagedParameterList, TypeSyntax returnType, _) = stubGenerator.GenerateAbiMethodSignatureData();
+
+ AttributeSyntax unmanagedCallersOnlyAttribute = Attribute(
+ ParseName(TypeNames.UnmanagedCallersOnlyAttribute));
+
+ if (methodStub.CallingConvention.Array.Length != 0)
+ {
+ unmanagedCallersOnlyAttribute = unmanagedCallersOnlyAttribute.AddArgumentListArguments(
+ AttributeArgument(
+ ImplicitArrayCreationExpression(
+ InitializerExpression(SyntaxKind.CollectionInitializerExpression,
+ SeparatedList<ExpressionSyntax>(
+ methodStub.CallingConvention.Array.Select(callConv => TypeOfExpression(ParseName($"System.Runtime.CompilerServices.CallConv{callConv.Name.ValueText}")))))))
+ .WithNameEquals(NameEquals(IdentifierName("CallConvs"))));
+ }
+
+ MethodDeclarationSyntax unmanagedToManagedStub =
+ MethodDeclaration(returnType, $"ABI_{methodStub.StubMethodSyntaxTemplate.Identifier.Text}")
+ .WithModifiers(TokenList(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.StaticKeyword)))
+ .WithParameterList(unmanagedParameterList)
+ .AddAttributeLists(AttributeList(SingletonSeparatedList(unmanagedCallersOnlyAttribute)))
+ .WithBody(code);
+
+ return (
+ unmanagedToManagedStub,
+ methodStub.Diagnostics.Array.AddRange(diagnostics.Diagnostics));
+ }
+ private static ImmutableArray<TypePositionInfo> AddImplicitElementInfos(IncrementalMethodStubGenerationContext methodStub)
+ {
+ ImmutableArray<TypePositionInfo> originalElements = methodStub.SignatureContext.ElementTypeInformation;
+
+ var elements = ImmutableArray.CreateBuilder<TypePositionInfo>(originalElements.Length + 2);
+
+ elements.Add(new TypePositionInfo(methodStub.TypeKeyOwner, new NativeThisInfo(methodStub.UnwrapperSyntax))
+ {
+ InstanceIdentifier = ThisParameterIdentifier,
+ NativeIndex = 0,
+ });
+ foreach (TypePositionInfo element in originalElements)
+ {
+ elements.Add(element with
+ {
+ NativeIndex = TypePositionInfo.IncrementIndex(element.NativeIndex)
+ });
+ }
+
+ if (methodStub.ExceptionMarshallingInfo != NoMarshallingInfo.Instance)
+ {
+ elements.Add(
+ new TypePositionInfo(
+ new ReferenceTypeInfo($"global::{TypeNames.System_Exception}", TypeNames.System_Exception),
+ methodStub.ExceptionMarshallingInfo)
+ {
+ InstanceIdentifier = "__exception",
+ ManagedIndex = TypePositionInfo.ExceptionIndex,
+ NativeIndex = TypePositionInfo.ReturnIndex
+ });
+ }
+
+ return elements.ToImmutable();
+ }
+
+ public static BlockSyntax GenerateVirtualMethodTableSlotAssignments(IEnumerable<IncrementalMethodStubGenerationContext> vtableMethods, string vtableIdentifier)
+ {
+ List<StatementSyntax> statements = new();
+ foreach (var method in vtableMethods)
+ {
+ FunctionPointerTypeSyntax functionPointerType = GenerateUnmanagedFunctionPointerTypeForMethod(method);
+
+ // <vtableParameter>[<index>] = (void*)(<functionPointerType>)&ABI_<methodIdentifier>;
+ statements.Add(
+ ExpressionStatement(
+ AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
+ ElementAccessExpression(
+ IdentifierName(vtableIdentifier))
+ .AddArgumentListArguments(Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(method.VtableIndexData.Index)))),
+ CastExpression(PointerType(PredefinedType(Token(SyntaxKind.VoidKeyword))),
+ CastExpression(functionPointerType,
+ PrefixUnaryExpression(SyntaxKind.AddressOfExpression,
+ IdentifierName($"ABI_{method.StubMethodSyntaxTemplate.Identifier}")))))));
+ }
+
+ return Block(statements);
+ }
+
+ private static FunctionPointerTypeSyntax GenerateUnmanagedFunctionPointerTypeForMethod(IncrementalMethodStubGenerationContext method)
+ {
+ var stubGenerator = new UnmanagedToManagedStubGenerator(
+ method.UnmanagedToManagedGeneratorFactory.Key.TargetFramework,
+ method.UnmanagedToManagedGeneratorFactory.Key.TargetFrameworkVersion,
+ AddImplicitElementInfos(method),
+ // Swallow diagnostics here since the diagnostics will be reported by the unmanaged->managed stub generation
+ (elementInfo, ex) => { },
+ method.UnmanagedToManagedGeneratorFactory.GeneratorFactory);
+
+ List<FunctionPointerParameterSyntax> functionPointerParameters = new();
+ var (paramList, retType, _) = stubGenerator.GenerateAbiMethodSignatureData();
+ functionPointerParameters.AddRange(paramList.Parameters.Select(p => FunctionPointerParameter(p.Type)));
+ // We add the return type as the last "parameter" here as that's what the function pointer syntax requires.
+ functionPointerParameters.Add(FunctionPointerParameter(retType));
+
+ // delegate* unmanaged<...>
+ ImmutableArray<FunctionPointerUnmanagedCallingConventionSyntax> callConv = method.CallingConvention.Array;
+ FunctionPointerTypeSyntax functionPointerType = FunctionPointerType(
+ FunctionPointerCallingConvention(Token(SyntaxKind.UnmanagedKeyword), callConv.IsEmpty ? null : FunctionPointerUnmanagedCallingConventionList(SeparatedList(callConv))),
+ FunctionPointerParameterList(SeparatedList(functionPointerParameters)));
+ return functionPointerType;
+ }
+ }
+}
}
return callingConventions.ToImmutable();
}
-
- private static SyntaxTokenList StripTriviaFromModifiers(SyntaxTokenList tokenList)
- {
- SyntaxToken[] strippedTokens = new SyntaxToken[tokenList.Count];
- for (int i = 0; i < tokenList.Count; i++)
- {
- strippedTokens[i] = tokenList[i].WithoutTrivia();
- }
- return new SyntaxTokenList(strippedTokens);
- }
-
- private static MethodDeclarationSyntax PrintGeneratedSource(
- ContainingSyntax stubMethodSyntax,
- SignatureContext stub,
- BlockSyntax stubCode)
- {
- // Create stub function
- return MethodDeclaration(stub.StubReturnType, stubMethodSyntax.Identifier)
- .AddAttributeLists(stub.AdditionalAttributes.ToArray())
- .WithModifiers(StripTriviaFromModifiers(stubMethodSyntax.Modifiers))
- .WithParameterList(ParameterList(SeparatedList(stub.StubParameters)))
- .WithBody(stubCode);
- }
-
private static VirtualMethodIndexCompilationData? ProcessVirtualMethodIndexAttribute(AttributeData attrData)
{
// Found the attribute, but it has an error so report the error.
return NoMarshallingInfo.Instance;
}
- internal static (MemberDeclarationSyntax, ImmutableArray<Diagnostic>) GenerateManagedToNativeStub(
+ private static (MemberDeclarationSyntax, ImmutableArray<Diagnostic>) GenerateManagedToNativeStub(
IncrementalMethodStubGenerationContext methodStub)
{
- var diagnostics = new GeneratorDiagnostics();
-
- // Generate stub code
- var stubGenerator = new ManagedToNativeVTableMethodGenerator(
- methodStub.ManagedToUnmanagedGeneratorFactory.Key.TargetFramework,
- methodStub.ManagedToUnmanagedGeneratorFactory.Key.TargetFrameworkVersion,
- methodStub.SignatureContext.ElementTypeInformation,
- methodStub.VtableIndexData.SetLastError,
- methodStub.VtableIndexData.ImplicitThisParameter,
- (elementInfo, ex) =>
- {
- diagnostics.ReportMarshallingNotSupported(methodStub.DiagnosticLocation, elementInfo, ex.NotSupportedDetails);
- },
- methodStub.ManagedToUnmanagedGeneratorFactory.GeneratorFactory);
-
- BlockSyntax code = stubGenerator.GenerateStubBody(
- methodStub.VtableIndexData.Index,
- methodStub.CallingConvention.Array,
- methodStub.TypeKeyOwner.Syntax);
+ var (stub, diagnostics) = VirtualMethodPointerStubGenerator.GenerateManagedToNativeStub(methodStub);
return (
methodStub.ContainingSyntaxContext.AddContainingSyntax(
NativeTypeContainingSyntax)
.WrapMemberInContainingSyntaxWithUnsafeModifier(
- PrintGeneratedSource(
- methodStub.StubMethodSyntaxTemplate,
- methodStub.SignatureContext,
- code)
- .WithExplicitInterfaceSpecifier(ExplicitInterfaceSpecifier(IdentifierName(methodStub.ContainingSyntaxContext.ContainingSyntax[0].Identifier)))),
- methodStub.Diagnostics.Array.AddRange(diagnostics.Diagnostics));
+ stub),
+ methodStub.Diagnostics.Array.AddRange(diagnostics));
}
- private const string ThisParameterIdentifier = "@this";
-
- internal static (MemberDeclarationSyntax, ImmutableArray<Diagnostic>) GenerateNativeToManagedStub(
+ private static (MemberDeclarationSyntax, ImmutableArray<Diagnostic>) GenerateNativeToManagedStub(
IncrementalMethodStubGenerationContext methodStub)
{
- var diagnostics = new GeneratorDiagnostics();
- ImmutableArray<TypePositionInfo> elements = AddImplicitElementInfos(methodStub);
-
- // Generate stub code
- var stubGenerator = new UnmanagedToManagedStubGenerator(
- methodStub.UnmanagedToManagedGeneratorFactory.Key.TargetFramework,
- methodStub.UnmanagedToManagedGeneratorFactory.Key.TargetFrameworkVersion,
- elements,
- (elementInfo, ex) =>
- {
- diagnostics.ReportMarshallingNotSupported(methodStub.DiagnosticLocation, elementInfo, ex.NotSupportedDetails);
- },
- methodStub.UnmanagedToManagedGeneratorFactory.GeneratorFactory);
-
- BlockSyntax code = stubGenerator.GenerateStubBody(
- MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
- IdentifierName(ThisParameterIdentifier),
- IdentifierName(methodStub.StubMethodSyntaxTemplate.Identifier)));
-
- (ParameterListSyntax unmanagedParameterList, TypeSyntax returnType, _) = stubGenerator.GenerateAbiMethodSignatureData();
-
- AttributeSyntax unmanagedCallersOnlyAttribute = Attribute(
- ParseName(TypeNames.UnmanagedCallersOnlyAttribute));
-
- if (methodStub.CallingConvention.Array.Length != 0)
- {
- unmanagedCallersOnlyAttribute = unmanagedCallersOnlyAttribute.AddArgumentListArguments(
- AttributeArgument(
- ImplicitArrayCreationExpression(
- InitializerExpression(SyntaxKind.CollectionInitializerExpression,
- SeparatedList<ExpressionSyntax>(
- methodStub.CallingConvention.Array.Select(callConv => TypeOfExpression(ParseName($"System.Runtime.CompilerServices.CallConv{callConv.Name.ValueText}")))))))
- .WithNameEquals(NameEquals(IdentifierName("CallConvs"))));
- }
-
- MethodDeclarationSyntax unmanagedToManagedStub =
- MethodDeclaration(returnType, $"ABI_{methodStub.StubMethodSyntaxTemplate.Identifier.Text}")
- .WithModifiers(TokenList(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.StaticKeyword)))
- .WithParameterList(unmanagedParameterList)
- .AddAttributeLists(AttributeList(SingletonSeparatedList(unmanagedCallersOnlyAttribute)))
- .WithBody(code);
+ var (stub, diagnostics) = VirtualMethodPointerStubGenerator.GenerateNativeToManagedStub(methodStub);
return (
methodStub.ContainingSyntaxContext.AddContainingSyntax(
NativeTypeContainingSyntax)
.WrapMemberInContainingSyntaxWithUnsafeModifier(
- unmanagedToManagedStub),
- methodStub.Diagnostics.Array.AddRange(diagnostics.Diagnostics));
- }
-
- private static ImmutableArray<TypePositionInfo> AddImplicitElementInfos(IncrementalMethodStubGenerationContext methodStub)
- {
- ImmutableArray<TypePositionInfo> originalElements = methodStub.SignatureContext.ElementTypeInformation;
-
- var elements = ImmutableArray.CreateBuilder<TypePositionInfo>(originalElements.Length + 2);
-
- elements.Add(new TypePositionInfo(methodStub.TypeKeyOwner, new NativeThisInfo(methodStub.UnwrapperSyntax))
- {
- InstanceIdentifier = ThisParameterIdentifier,
- NativeIndex = 0,
- });
- foreach (TypePositionInfo element in originalElements)
- {
- elements.Add(element with
- {
- NativeIndex = TypePositionInfo.IncrementIndex(element.NativeIndex)
- });
- }
-
- if (methodStub.ExceptionMarshallingInfo != NoMarshallingInfo.Instance)
- {
- elements.Add(
- new TypePositionInfo(
- new ReferenceTypeInfo($"global::{TypeNames.System_Exception}", TypeNames.System_Exception),
- methodStub.ExceptionMarshallingInfo)
- {
- InstanceIdentifier = "__exception",
- ManagedIndex = TypePositionInfo.ExceptionIndex,
- NativeIndex = TypePositionInfo.ReturnIndex
- });
- }
-
- return elements.ToImmutable();
+ stub),
+ methodStub.Diagnostics.Array.AddRange(diagnostics));
}
private static Diagnostic? GetDiagnosticIfInvalidMethodForGeneration(MethodDeclarationSyntax methodSyntax, IMethodSymbol method)
private static MemberDeclarationSyntax GeneratePopulateVTableMethod(IGrouping<ContainingSyntaxContext, IncrementalMethodStubGenerationContext> vtableMethods)
{
- const string vtableParameter = "vtable";
ContainingSyntaxContext containingSyntax = vtableMethods.Key.AddContainingSyntax(NativeTypeContainingSyntax);
+
+ const string vtableParameter = "vtable";
MethodDeclarationSyntax populateVtableMethod = MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)),
"PopulateUnmanagedVirtualMethodTable")
- .WithModifiers(TokenList(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.StaticKeyword)))
+ .WithModifiers(TokenList(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.StaticKeyword), Token(SyntaxKind.UnsafeKeyword)))
.AddParameterListParameters(
Parameter(Identifier(vtableParameter))
.WithType(PointerType(PointerType(PredefinedType(Token(SyntaxKind.VoidKeyword))))));
- foreach (var method in vtableMethods)
- {
- FunctionPointerTypeSyntax functionPointerType = GenerateUnmanagedFunctionPointerTypeForMethod(method);
-
- // <vtableParameter>[<index>] = (void*)(<functionPointerType>)&ABI_<methodIdentifier>;
- populateVtableMethod = populateVtableMethod.AddBodyStatements(
- ExpressionStatement(
- AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
- ElementAccessExpression(
- IdentifierName(vtableParameter))
- .AddArgumentListArguments(Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(method.VtableIndexData.Index)))),
- CastExpression(PointerType(PredefinedType(Token(SyntaxKind.VoidKeyword))),
- CastExpression(functionPointerType,
- PrefixUnaryExpression(SyntaxKind.AddressOfExpression,
- IdentifierName($"ABI_{method.StubMethodSyntaxTemplate.Identifier}")))))));
- }
-
- return containingSyntax.WrapMemberInContainingSyntaxWithUnsafeModifier(populateVtableMethod);
- }
-
- internal static FunctionPointerTypeSyntax GenerateUnmanagedFunctionPointerTypeForMethod(IncrementalMethodStubGenerationContext method)
- {
- var stubGenerator = new UnmanagedToManagedStubGenerator(
- method.UnmanagedToManagedGeneratorFactory.Key.TargetFramework,
- method.UnmanagedToManagedGeneratorFactory.Key.TargetFrameworkVersion,
- AddImplicitElementInfos(method),
- // Swallow diagnostics here since the diagnostics will be reported by the unmanaged->managed stub generation
- (elementInfo, ex) => { },
- method.UnmanagedToManagedGeneratorFactory.GeneratorFactory);
-
- List<FunctionPointerParameterSyntax> functionPointerParameters = new();
- var (paramList, retType, _) = stubGenerator.GenerateAbiMethodSignatureData();
- functionPointerParameters.AddRange(paramList.Parameters.Select(p => FunctionPointerParameter(p.Type)));
- // We add the return type as the last "parameter" here as that's what the function pointer syntax requires.
- functionPointerParameters.Add(FunctionPointerParameter(retType));
-
- // delegate* unmanaged<...>
- ImmutableArray<FunctionPointerUnmanagedCallingConventionSyntax> callConv = method.CallingConvention.Array;
- FunctionPointerTypeSyntax functionPointerType = FunctionPointerType(
- FunctionPointerCallingConvention(Token(SyntaxKind.UnmanagedKeyword), callConv.IsEmpty ? null : FunctionPointerUnmanagedCallingConventionList(SeparatedList(callConv))),
- FunctionPointerParameterList(SeparatedList(functionPointerParameters)));
- return functionPointerType;
+ return containingSyntax.WrapMembersInContainingSyntaxWithUnsafeModifier(
+ populateVtableMethod.WithBody(VirtualMethodPointerStubGenerator.GenerateVirtualMethodTableSlotAssignments(vtableMethods, vtableParameter)));
}
}
}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Microsoft.CodeAnalysis;
+
+namespace Microsoft.Interop
+{
+ public record struct SyntaxEquivalentNode<T>(T Node)
+ where T : SyntaxNode
+ {
+ public bool Equals(SyntaxEquivalentNode<T> other)
+ {
+ return SyntaxEquivalentComparer.Instance.Equals(Node, other.Node);
+ }
+
+ public override int GetHashCode() => throw new UnreachableException();
+ }
+}
public const string System_Runtime_InteropServices_DynamicInterfaceCastableImplementationAttribute = "System.Runtime.InteropServices.DynamicInterfaceCastableImplementationAttribute";
+ public const string System_Guid = "System.Guid";
+
+ public const string System_Runtime_CompilerServices_RuntimeHelpers = "System.Runtime.CompilerServices.RuntimeHelpers";
+
public const string GeneratedComInterfaceAttribute = "System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute";
+
public const string InterfaceTypeAttribute = "System.Runtime.InteropServices.InterfaceTypeAttribute";
+
public const string ComInterfaceTypeAttribute = "System.Runtime.InteropServices.ComInterfaceType";
+
+ public const string System_Runtime_InteropServices_GuidAttribute = "System.Runtime.InteropServices.GuidAttribute";
+
+ public const string System_Runtime_InteropServices_ComWrappers = "System.Runtime.InteropServices.ComWrappers";
+
public const string System_Runtime_InteropServices_ComWrappers_ComInterfaceDispatch = "System.Runtime.InteropServices.ComWrappers.ComInterfaceDispatch";
+
+ public const string IIUnknownInterfaceType = "System.Runtime.InteropServices.Marshalling.IIUnknownInterfaceType";
+ public const string IUnknownDerivedAttribute = "System.Runtime.InteropServices.Marshalling.IUnknownDerivedAttribute";
+
public const string ComWrappersUnwrapper = "System.Runtime.InteropServices.Marshalling.ComWrappersUnwrapper";
public const string UnmanagedObjectUnwrapperAttribute = "System.Runtime.InteropServices.Marshalling.UnmanagedObjectUnwrapperAttribute`1";
[AttributeUsage(AttributeTargets.Interface)]
public class IUnknownDerivedAttribute<T, TImpl> : Attribute, IUnknownDerivedDetails
where T : IIUnknownInterfaceType
- where TImpl : T
{
public IUnknownDerivedAttribute()
{
INamedTypeSymbol generatedInterfaceImplementation = Assert.Single(userDefinedInterface.GetTypeMembers("Native"));
- IMethodSymbol methodImplementation = Assert.Single(generatedInterfaceImplementation.GetMembers($"{userDefinedInterfaceName}.{methodName}").OfType<IMethodSymbol>());
+ IMethodSymbol methodImplementation = Assert.Single(generatedInterfaceImplementation.GetMembers($"global::{userDefinedInterfaceName}.{methodName}").OfType<IMethodSymbol>());
SyntaxNode emittedImplementationSyntax = await methodImplementation.DeclaringSyntaxReferences[0].GetSyntaxAsync();
public static readonly string DisableRuntimeMarshalling = "[assembly:System.Runtime.CompilerServices.DisableRuntimeMarshalling]";
public static readonly string UsingSystemRuntimeInteropServicesMarshalling = "using System.Runtime.InteropServices.Marshalling;";
- public static string NativeInterfaceUsage() => @"
-// Try using the generated native interface
-sealed class NativeAPI : IUnmanagedVirtualMethodTableProvider, INativeAPI.Native
-{
- public VirtualMethodTableInfo GetVirtualMethodTableInfoForKey(System.Type type) => throw null;
-}
-";
public string SpecifiedMethodIndexNoExplicitParameters => $@"
using System.Runtime.InteropServices;
{{
{VirtualMethodIndex(0)}
void Method();
-}}" + NativeInterfaceUsage() + _attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+}}" + _attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
public string SpecifiedMethodIndexNoExplicitParametersNoImplicitThis => $@"
using System.Runtime.InteropServices;
{VirtualMethodIndex(0, ImplicitThisParameter: false)}
void Method();
-}}" + NativeInterfaceUsage() + _attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+}}" + _attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
public string SpecifiedMethodIndexNoExplicitParametersCallConvWithCallingConventions => $@"
using System.Runtime.CompilerServices;
[SuppressGCTransition]
{VirtualMethodIndex(4)}
void Method4();
-}}" + NativeInterfaceUsage() + _attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+}}" + _attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
public string BasicParametersAndModifiers(string typeName, string preDeclaration = "") => $@"
using System.Runtime.CompilerServices;
{{
{VirtualMethodIndex(0)}
{typeName} Method({typeName} value, in {typeName} inValue, ref {typeName} refValue, out {typeName} outValue);
-}}" + NativeInterfaceUsage() + _attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+}}" + _attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
public string BasicParametersAndModifiersManagedToUnmanaged(string typeName, string preDeclaration = "") => $@"
using System.Runtime.CompilerServices;
{{
{VirtualMethodIndex(0, Direction: MarshalDirection.ManagedToUnmanaged)}
{typeName} Method({typeName} value, in {typeName} inValue, ref {typeName} refValue, out {typeName} outValue);
-}}" + NativeInterfaceUsage() + _attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+}}" + _attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
public string BasicParametersAndModifiers<T>() => BasicParametersAndModifiers(typeof(T).FullName!);
public string BasicParametersAndModifiersNoRef(string typeName, string preDeclaration = "") => $@"
using System.Runtime.CompilerServices;
{{
{VirtualMethodIndex(0)}
{typeName} Method({typeName} value, in {typeName} inValue, out {typeName} outValue);
-}}" + NativeInterfaceUsage() + _attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+}}" + _attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
public string BasicParametersAndModifiersNoImplicitThis(string typeName) => $@"
using System.Runtime.CompilerServices;
{{
{VirtualMethodIndex(0, ImplicitThisParameter: false)}
{typeName} Method({typeName} value, in {typeName} inValue, ref {typeName} refValue, out {typeName} outValue);
-}}" + NativeInterfaceUsage() + _attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+}}" + _attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
public string BasicParametersAndModifiersNoImplicitThis<T>() => BasicParametersAndModifiersNoImplicitThis(typeof(T).FullName!);
public string MarshalUsingCollectionCountInfoParametersAndModifiers<T>() => MarshalUsingCollectionCountInfoParametersAndModifiers(typeof(T).ToString());
[MarshalUsing(CountElementName = ""pRefSize"")] ref {collectionType} pRef,
[MarshalUsing(CountElementName = ""pOutSize"")] out {collectionType} pOut,
out int pOutSize);
-}}" + NativeInterfaceUsage() + _attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+}}" + _attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
public string BasicReturnTypeComExceptionHandling(string typeName, string preDeclaration = "") => $@"
using System.Runtime.CompilerServices;
{{
{VirtualMethodIndex(0, ExceptionMarshalling : ExceptionMarshalling.Com)}
{typeName} Method();
-}}" + NativeInterfaceUsage() + _attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+}}" + _attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
public string BasicReturnTypeCustomExceptionHandling(string typeName, string customExceptionType, string preDeclaration = "") => $@"
using System.Runtime.CompilerServices;
{{
{VirtualMethodIndex(0, ExceptionMarshallingType : Type.GetType(customExceptionType))}
{typeName} Method();
-}}" + NativeInterfaceUsage() + _attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+}}" + _attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
public class ManagedToUnmanaged : IVirtualMethodIndexSignatureProvider
{
public bool ImplicitThisParameter => true;
- public string NativeInterfaceUsage() => CodeSnippets.NativeInterfaceUsage();
-
public ManagedToUnmanaged(IComInterfaceAttributeProvider attributeProvider)
{
AttributeProvider = attributeProvider;
public bool ImplicitThisParameter => false;
- public string NativeInterfaceUsage() => CodeSnippets.NativeInterfaceUsage();
-
public ManagedToUnmanagedNoImplicitThis(IComInterfaceAttributeProvider attributeProvider)
{
AttributeProvider = attributeProvider;
public bool ImplicitThisParameter => true;
- // Unmanaged-to-managed-only stubs don't provide implementations for the interface, so we don't want to try to use the generated nested interface
- // since it won't have managed implementations for the methods
- public string NativeInterfaceUsage() => string.Empty;
-
public UnmanagedToManaged(IComInterfaceAttributeProvider attributeProvider)
{
AttributeProvider = attributeProvider;
public bool ImplicitThisParameter => true;
- public string NativeInterfaceUsage() => CodeSnippets.NativeInterfaceUsage();
-
public Bidirectional(IComInterfaceAttributeProvider attributeProvider)
{
AttributeProvider = attributeProvider;
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.Interop.UnitTests;
+using Xunit;
+
+namespace ComInterfaceGenerator.Unit.Tests
+{
+ public class ComInterfaceGeneratorOutputShape
+ {
+ [Fact]
+ public async Task SingleComInterface()
+ {
+ string source = """
+ using System.Runtime.InteropServices;
+ using System.Runtime.InteropServices.Marshalling;
+
+ [GeneratedComInterface]
+ partial interface INativeAPI
+ {
+ void Method();
+ void Method2();
+ }
+ """;
+ Compilation comp = await TestUtils.CreateCompilation(source);
+ TestUtils.AssertPreSourceGeneratorCompilation(comp);
+
+ var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.ComInterfaceGenerator());
+ TestUtils.AssertPostSourceGeneratorCompilation(newComp);
+ // We'll create one syntax tree for the new interface.
+ Assert.Equal(comp.SyntaxTrees.Count() + 1, newComp.SyntaxTrees.Count());
+
+ VerifyShape(newComp, "INativeAPI");
+ }
+
+ [Fact]
+ public async Task MultipleComInterfaces()
+ {
+ string source = $$"""
+ using System.Runtime.InteropServices;
+ using System.Runtime.InteropServices.Marshalling;
+
+ [GeneratedComInterface]
+ partial interface I
+ {
+ void Method();
+ void Method2();
+ }
+ [GeneratedComInterface]
+ partial interface J
+ {
+ void Method();
+ void Method2();
+ }
+ """;
+ Compilation comp = await TestUtils.CreateCompilation(source);
+ TestUtils.AssertPreSourceGeneratorCompilation(comp);
+
+ var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.ComInterfaceGenerator());
+ TestUtils.AssertPostSourceGeneratorCompilation(newComp);
+ // We'll create one syntax tree per user-defined interface.
+ Assert.Equal(comp.SyntaxTrees.Count() + 2, newComp.SyntaxTrees.Count());
+
+ VerifyShape(newComp, "I");
+ VerifyShape(newComp, "J");
+ }
+
+ [Fact]
+ public async Task EmptyComInterface()
+ {
+ string source = $$"""
+ using System.Runtime.InteropServices;
+ using System.Runtime.InteropServices.Marshalling;
+
+ [GeneratedComInterface]
+ partial interface I
+ {
+ void Method();
+ void Method2();
+ }
+ [GeneratedComInterface]
+ partial interface Empty
+ {
+ }
+ [GeneratedComInterface]
+ partial interface J
+ {
+ void Method();
+ void Method2();
+ }
+ """;
+ Compilation comp = await TestUtils.CreateCompilation(source);
+ TestUtils.AssertPreSourceGeneratorCompilation(comp);
+
+ var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.ComInterfaceGenerator());
+ TestUtils.AssertPostSourceGeneratorCompilation(newComp);
+ // We'll create one syntax tree per user-defined interface.
+ Assert.Equal(comp.SyntaxTrees.Count() + 3, newComp.SyntaxTrees.Count());
+
+ VerifyShape(newComp, "I");
+ VerifyShape(newComp, "J");
+ }
+
+ private static void VerifyShape(Compilation comp, string userDefinedInterfaceMetadataName)
+ {
+ INamedTypeSymbol? userDefinedInterface = comp.Assembly.GetTypeByMetadataName(userDefinedInterfaceMetadataName);
+ Assert.NotNull(userDefinedInterface);
+
+ INamedTypeSymbol? iUnknownDerivedAttributeType = comp.GetTypeByMetadataName("System.Runtime.InteropServices.Marshalling.IUnknownDerivedAttribute`2");
+
+ Assert.NotNull(iUnknownDerivedAttributeType);
+
+ AttributeData iUnknownDerivedAttribute = Assert.Single(
+ userDefinedInterface.GetAttributes(),
+ attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass?.OriginalDefinition, iUnknownDerivedAttributeType));
+
+ Assert.Collection(Assert.IsAssignableFrom<INamedTypeSymbol>(iUnknownDerivedAttribute.AttributeClass).TypeArguments,
+ infoType =>
+ {
+ Assert.True(Assert.IsAssignableFrom<INamedTypeSymbol>(infoType).IsFileLocal);
+ },
+ implementationType =>
+ {
+ Assert.True(Assert.IsAssignableFrom<INamedTypeSymbol>(implementationType).IsFileLocal);
+ Assert.Contains(userDefinedInterface, implementationType.Interfaces, SymbolEqualityComparer.Default);
+ Assert.Contains(implementationType.GetAttributes(), attr => attr.AttributeClass?.ToDisplayString() == typeof(DynamicInterfaceCastableImplementationAttribute).FullName);
+ Assert.All(userDefinedInterface.GetMembers().OfType<IMethodSymbol>().Where(method => method.IsAbstract && !method.IsStatic),
+ method =>
+ {
+ Assert.NotNull(implementationType.FindImplementationForInterfaceMember(method));
+ });
+ });
+ }
+ }
+}
{
// Duplicate 'using'
"CS0105",
- // ComWrappersUnwrapper is inaccessible due to its protection level
- "CS0122",
// Variable assigned to but never read
"CS0219"
};
public string UnmanagedObjectUnwrapper(Type t) => "";
- public string GeneratedComInterface => "[global::System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute]";
+ public string GeneratedComInterface => @$"[global::System.Runtime.InteropServices.Marshalling.GeneratedComInterface, global::System.Runtime.InteropServices.Guid(""0A52B77C-E08B-4274-A1F4-1A2BF2C07E60"")]";
public string AdditionalUserRequiredInterfaces(string userDefinedInterfaceName) => "";
}
-}
\ No newline at end of file
+}
public static readonly string DisableRuntimeMarshalling = "[assembly:System.Runtime.CompilerServices.DisableRuntimeMarshalling]";
public static readonly string UsingSystemRuntimeInteropServicesMarshalling = "using System.Runtime.InteropServices.Marshalling;";
- string NativeInterfaceUsage();
-
string ICustomMarshallingSignatureTestProvider.BasicParametersAndModifiers(string typeName, string preDeclaration) => $@"
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
{{
{AttributeProvider.VirtualMethodIndex(0, ImplicitThisParameter: ImplicitThisParameter, Direction: Direction)}
{typeName} Method({typeName} value, in {typeName} inValue, ref {typeName} refValue, out {typeName} outValue);
-}}" + NativeInterfaceUsage() + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+}}" + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
string ICustomMarshallingSignatureTestProvider.BasicParametersAndModifiersNoRef(string typeName, string preDeclaration) => $@"
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
{{
{AttributeProvider.VirtualMethodIndex(0, ImplicitThisParameter: ImplicitThisParameter, Direction: Direction)}
{typeName} Method({typeName} value, in {typeName} inValue, out {typeName} outValue);
-}}" + NativeInterfaceUsage() + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+}}" + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
string ICustomMarshallingSignatureTestProvider.BasicParameterByValue(string typeName, string preDeclaration) => $@"
using System.Runtime.CompilerServices;
{{
{AttributeProvider.VirtualMethodIndex(0, ImplicitThisParameter: ImplicitThisParameter, Direction: Direction)}
void Method({typeName} value);
-}}" + NativeInterfaceUsage() + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+}}" + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
string ICustomMarshallingSignatureTestProvider.BasicParameterWithByRefModifier(string modifier, string typeName, string preDeclaration) => $@"
using System.Runtime.CompilerServices;
{{
{AttributeProvider.VirtualMethodIndex(0, ImplicitThisParameter: ImplicitThisParameter, Direction: Direction)}
void Method({modifier} {typeName} value);
-}}" + NativeInterfaceUsage() + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+}}" + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
string ICustomMarshallingSignatureTestProvider.BasicReturnType(string typeName, string preDeclaration) => $@"
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
{{
{AttributeProvider.VirtualMethodIndex(0, ImplicitThisParameter: ImplicitThisParameter, Direction: Direction)}
{typeName} Method();
-}}" + NativeInterfaceUsage() + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+}}" + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
string ICustomMarshallingSignatureTestProvider.MarshalUsingParametersAndModifiers(string typeName, string marshallerTypeName, string preDeclaration) => $@"
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[MarshalUsing(typeof({marshallerTypeName}))] in {typeName} pIn,
[MarshalUsing(typeof({marshallerTypeName}))] ref {typeName} pRef,
[MarshalUsing(typeof({marshallerTypeName}))] out {typeName} pOut);
-}}" + NativeInterfaceUsage() + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+}}" + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
string ICustomMarshallingSignatureTestProvider.MarshalUsingCollectionCountInfoParametersAndModifiers(string collectionType) => $@"
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[MarshalUsing(CountElementName = ""pRefSize"")] ref {collectionType} pRef,
[MarshalUsing(CountElementName = ""pOutSize"")] out {collectionType} pOut,
out int pOutSize);
-}}" + NativeInterfaceUsage() + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+}}" + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
string ICustomMarshallingSignatureTestProvider.MarshalUsingCollectionParametersAndModifiers(string collectionType, string marshallerType) => $@"
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[MarshalUsing(typeof({marshallerType}), CountElementName = ""pOutSize"")] out {collectionType} pOut,
out int pOutSize
);
-}}" + NativeInterfaceUsage() + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+}}" + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
string ICustomMarshallingSignatureTestProvider.MarshalUsingCollectionReturnValueLength(string collectionType, string marshallerType) => $@"
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
int Method(
[MarshalUsing(typeof({marshallerType}), CountElementName = MarshalUsingAttribute.ReturnsCountValue)] out {collectionType} pOut
);
-}}" + NativeInterfaceUsage() + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+}}" + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
string ICustomMarshallingSignatureTestProvider.MarshalUsingCollectionOutConstantLength(string collectionType, string predeclaration) => $@"
using System.Runtime.CompilerServices;
[MarshalUsing(ConstantElementCount = 10)] out {collectionType} pOut
);
}}
-" + NativeInterfaceUsage() + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+" + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
string ICustomMarshallingSignatureTestProvider.MarshalUsingCollectionReturnConstantLength(string collectionType, string predeclaration) => $@"
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[return:MarshalUsing(ConstantElementCount = 10)]
{collectionType} Method();
}}
-" + NativeInterfaceUsage() + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+" + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
string ICustomMarshallingSignatureTestProvider.CustomElementMarshalling(string collectionType, string elementMarshaller, string predeclaration) => $@"
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
out int pOutSize
);
}}
-" + NativeInterfaceUsage() + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
+" + AttributeProvider.AdditionalUserRequiredInterfaces("INativeAPI");
}
}
namespace ComInterfaceGenerator.Unit.Tests
{
- public class NativeInterfaceShape
+ public class VTableGeneratorOutputShape
{
[Fact]
public async Task NativeInterfaceNestedInUserInterface()
}
""";
Compilation comp = await TestUtils.CreateCompilation(source);
- // Allow the Native nested type name to be missing in the pre-source-generator compilation
TestUtils.AssertPreSourceGeneratorCompilation(comp);
var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.VtableIndexStubGenerator());
}
""";
Compilation comp = await TestUtils.CreateCompilation(source);
- // Allow the Native nested type name to be missing in the pre-source-generator compilation
TestUtils.AssertPreSourceGeneratorCompilation(comp);
var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.VtableIndexStubGenerator());
}
[Fact]
- public async Task NativeInterfaceHasDynamicInterfaceCastableImplementationAttribute()
+ public async Task NativeInterfaceImplementsUserInterfaceMethods()
{
string source = $$"""
using System.Runtime.InteropServices;
[VirtualMethodIndex(0)]
void Method();
}
+
+ // Ensure we can implement the native interface without defining any implementations.
+ class C : INativeAPI.Native {}
""";
Compilation comp = await TestUtils.CreateCompilation(source);
// Allow the Native nested type name to be missing in the pre-source-generator compilation
+ TestUtils.AssertPreSourceGeneratorCompilation(comp, "CS0426");
+
+ var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.VtableIndexStubGenerator());
+ TestUtils.AssertPostSourceGeneratorCompilation(newComp);
+ }
+
+ [Fact]
+ public async Task NativeInterfaceHasDynamicInterfaceCastableImplementationAttribute()
+ {
+ string source = $$"""
+ using System.Runtime.InteropServices;
+ using System.Runtime.InteropServices.Marshalling;
+
+ [UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+ partial interface INativeAPI : IUnmanagedInterfaceType
+ {
+ static unsafe void* IUnmanagedInterfaceType.VirtualMethodTableManagedImplementation => null;
+ [VirtualMethodIndex(0)]
+ void Method();
+ }
+ """;
+ Compilation comp = await TestUtils.CreateCompilation(source);
TestUtils.AssertPreSourceGeneratorCompilation(comp);
var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.VtableIndexStubGenerator());
}
""";
Compilation comp = await TestUtils.CreateCompilation(source);
- // Allow the Native nested type name to be missing in the pre-source-generator compilation
TestUtils.AssertPreSourceGeneratorCompilation(comp);
var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.VtableIndexStubGenerator());