Skip to content

Commit 4dea84c

Browse files
jtschusterAaronRobinsonMSFTjkoritzinsky
authored
Add new proposed API to Ancillary.Interop (#81063)
Updates the VTableStubGenerator to use the latest version of the proposed API. Co-authored-by: Aaron Robinson <arobins@microsoft.com> Co-authored-by: Jeremy Koritzinsky <jkoritzinsky@gmail.com>
1 parent 6ede02b commit 4dea84c

File tree

53 files changed

+1069
-286
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1069
-286
lines changed

src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,8 @@ private static IncrementalMethodStubGenerationContext CalculateStubInformation(M
266266
ComInterfaceGeneratorHelpers.CreateGeneratorFactory(environment, MarshalDirection.ManagedToUnmanaged),
267267
ComInterfaceGeneratorHelpers.CreateGeneratorFactory(environment, MarshalDirection.UnmanagedToManaged),
268268
typeKeyOwner,
269-
new SequenceEqualImmutableArray<Diagnostic>(generatorDiagnostics.Diagnostics.ToImmutableArray()));
269+
new SequenceEqualImmutableArray<Diagnostic>(generatorDiagnostics.Diagnostics.ToImmutableArray()),
270+
ParseTypeName(TypeNames.ComWrappersUnwrapper));
270271
}
271272

272273
private static Diagnostic? GetDiagnosticIfInvalidTypeForGeneration(InterfaceDeclarationSyntax syntax, INamedTypeSymbol type)

src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ public class Ids
4545
isEnabledByDefault: true,
4646
description: GetResourceString(nameof(SR.InvalidAttributedMethodDescription)));
4747

48+
public static readonly DiagnosticDescriptor InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttribute =
49+
new DiagnosticDescriptor(
50+
Ids.InvalidLibraryImportAttributeUsage,
51+
GetResourceString(nameof(SR.InvalidVirtualMethodIndexAttributeUsage)),
52+
GetResourceString(nameof(SR.InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage)),
53+
Category,
54+
DiagnosticSeverity.Error,
55+
isEnabledByDefault: true,
56+
description: GetResourceString(nameof(SR.InvalidAttributedMethodDescription)));
57+
4858
public static readonly DiagnosticDescriptor InvalidStringMarshallingConfiguration =
4959
new DiagnosticDescriptor(
5060
Ids.InvalidLibraryImportAttributeUsage,

src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/IncrementalMethodStubGenerationContext.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@ internal sealed record IncrementalMethodStubGenerationContext(
1818
MarshallingGeneratorFactoryKey<(TargetFramework TargetFramework, Version TargetFrameworkVersion)> ManagedToUnmanagedGeneratorFactory,
1919
MarshallingGeneratorFactoryKey<(TargetFramework TargetFramework, Version TargetFrameworkVersion)> UnmanagedToManagedGeneratorFactory,
2020
ManagedTypeInfo TypeKeyOwner,
21-
SequenceEqualImmutableArray<Diagnostic> Diagnostics);
21+
SequenceEqualImmutableArray<Diagnostic> Diagnostics,
22+
TypeSyntax UnwrapperSyntax);
2223
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Microsoft.CodeAnalysis;
5+
using Microsoft.CodeAnalysis.CSharp;
6+
using Microsoft.CodeAnalysis.CSharp.Syntax;
7+
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
8+
9+
namespace Microsoft.Interop
10+
{
11+
internal static class InlinedTypes
12+
{
13+
/// <summary>
14+
/// Returns the ClassDeclarationSyntax for:
15+
/// <code>
16+
/// public sealed unsafe class ComWrappersUnwrapper : IUnmanagedObjectUnwrapper
17+
/// {
18+
/// public static object GetObjectForUnmanagedWrapper(void* ptr)
19+
/// {
20+
/// return ComWrappers.ComInterfaceDispatch.GetInstance<object>((ComWrappers.ComInterfaceDispatch*)ptr);
21+
/// }
22+
/// }
23+
/// </code>
24+
/// </summary>
25+
public static ClassDeclarationSyntax ComWrappersUnwrapper { get; } = GetComWrappersUnwrapper();
26+
27+
public static ClassDeclarationSyntax GetComWrappersUnwrapper()
28+
{
29+
return ClassDeclaration("ComWrappersUnwrapper")
30+
.AddModifiers(Token(SyntaxKind.SealedKeyword),
31+
Token(SyntaxKind.UnsafeKeyword),
32+
Token(SyntaxKind.StaticKeyword),
33+
Token(SyntaxKind.FileKeyword))
34+
.AddMembers(
35+
MethodDeclaration(
36+
PredefinedType(Token(SyntaxKind.ObjectKeyword)),
37+
Identifier("GetComObjectForUnmanagedWrapper"))
38+
.AddModifiers(Token(SyntaxKind.PublicKeyword),
39+
Token(SyntaxKind.StaticKeyword))
40+
.AddParameterListParameters(
41+
Parameter(Identifier("ptr"))
42+
.WithType(PointerType(PredefinedType(Token(SyntaxKind.VoidKeyword)))))
43+
.WithBody(body: Body()));
44+
45+
static BlockSyntax Body()
46+
{
47+
var invocation = InvocationExpression(
48+
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
49+
MemberAccessExpression(
50+
SyntaxKind.SimpleMemberAccessExpression,
51+
IdentifierName("ComWrappers"),
52+
IdentifierName("ComInterfaceDispatch")),
53+
GenericName(
54+
Identifier("GetInstance"),
55+
TypeArgumentList(
56+
SeparatedList<SyntaxNode>(
57+
new[] { PredefinedType(Token(SyntaxKind.ObjectKeyword)) })))))
58+
.AddArgumentListArguments(
59+
Argument(
60+
null,
61+
Token(SyntaxKind.None),
62+
CastExpression(
63+
PointerType(
64+
QualifiedName(
65+
IdentifierName("ComWrappers"),
66+
IdentifierName("ComInterfaceDispatch"))),
67+
IdentifierName("ptr"))));
68+
69+
return Block(ReturnStatement(invocation));
70+
}
71+
}
72+
73+
/// <summary>
74+
/// <code>
75+
/// file static class UnmanagedObjectUnwrapper
76+
/// {
77+
/// public static object GetObjectForUnmanagedWrapper<T>(void* ptr) where T : IUnmanagedObjectUnwrapper
78+
/// {
79+
/// return T.GetObjectForUnmanagedWrapper(ptr);
80+
/// }
81+
/// }
82+
/// </code>
83+
/// </summary>
84+
public static ClassDeclarationSyntax UnmanagedObjectUnwrapper { get; } = GetUnmanagedObjectUnwrapper();
85+
86+
private static ClassDeclarationSyntax GetUnmanagedObjectUnwrapper()
87+
{
88+
const string tUnwrapper = "TUnwrapper";
89+
return ClassDeclaration("UnmanagedObjectUnwrapper")
90+
.AddModifiers(Token(SyntaxKind.FileKeyword),
91+
Token(SyntaxKind.StaticKeyword))
92+
.AddMembers(
93+
MethodDeclaration(
94+
PredefinedType(Token(SyntaxKind.ObjectKeyword)),
95+
Identifier("GetObjectForUnmanagedWrapper"))
96+
.AddModifiers(Token(SyntaxKind.PublicKeyword),
97+
Token(SyntaxKind.StaticKeyword))
98+
.AddTypeParameterListParameters(
99+
TypeParameter(Identifier(tUnwrapper)))
100+
.AddParameterListParameters(
101+
Parameter(Identifier("ptr"))
102+
.WithType(PointerType(PredefinedType(Token(SyntaxKind.VoidKeyword)))))
103+
.AddConstraintClauses(TypeParameterConstraintClause(IdentifierName(tUnwrapper))
104+
.AddConstraints(TypeConstraint(ParseTypeName(TypeNames.IUnmanagedObjectUnwrapper))))
105+
.WithBody(body: Body()));
106+
107+
static BlockSyntax Body()
108+
{
109+
var invocation = InvocationExpression(
110+
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
111+
IdentifierName("T"),
112+
IdentifierName("GetObjectForUnmanagedWrapper")))
113+
.AddArgumentListArguments(
114+
Argument(
115+
null,
116+
Token(SyntaxKind.None),
117+
IdentifierName("ptr")));
118+
119+
return Block(ReturnStatement(invocation));
120+
}
121+
122+
}
123+
}
124+
}

src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ManagedToNativeVTableMethodGenerator.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public ManagedToNativeVTableMethodGenerator(
5555
if (implicitThis)
5656
{
5757
ImmutableArray<TypePositionInfo>.Builder newArgTypes = ImmutableArray.CreateBuilder<TypePositionInfo>(argTypes.Length + 1);
58-
newArgTypes.Add(new TypePositionInfo(SpecialTypeInfo.IntPtr, NoMarshallingInfo.Instance)
58+
newArgTypes.Add(new TypePositionInfo(new PointerTypeInfo("void*", "void*", false), NoMarshallingInfo.Instance)
5959
{
6060
InstanceIdentifier = NativeThisParameterIdentifier,
6161
NativeIndex = 0
@@ -101,7 +101,7 @@ public BlockSyntax GenerateStubBody(int index, ImmutableArray<FunctionPointerUnm
101101
{
102102
var setupStatements = new List<StatementSyntax>
103103
{
104-
// var (<thisParameter>, <virtualMethodTable>) = ((IUnmanagedVirtualMethodTableProvider)this).GetVirtualMethodTableInfoForKey<<containingTypeName>>();
104+
// var (<thisParameter>, <virtualMethodTable>) = ((IUnmanagedVirtualMethodTableProvider)this).GetVirtualMethodTableInfoForKey(typeof(<containingTypeName>));
105105
ExpressionStatement(
106106
AssignmentExpression(
107107
SyntaxKind.SimpleAssignmentExpression,
@@ -121,12 +121,9 @@ public BlockSyntax GenerateStubBody(int index, ImmutableArray<FunctionPointerUnm
121121
CastExpression(
122122
ParseTypeName(TypeNames.IUnmanagedVirtualMethodTableProvider),
123123
ThisExpression())),
124-
GenericName(
125-
Identifier("GetVirtualMethodTableInfoForKey"),
126-
TypeArgumentList(
127-
SingletonSeparatedList(containingTypeName)))))
124+
IdentifierName("GetVirtualMethodTableInfoForKey") ))
128125
.WithArgumentList(
129-
ArgumentList())))
126+
ArgumentList(SeparatedList(new[]{ Argument(TypeOfExpression(containingTypeName)) })))))
130127
};
131128

132129
GeneratedStatements statements = GeneratedStatements.Create(

src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Marshallers/NativeToManagedThisMarshallerFactory.cs

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,14 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Diagnostics;
67
using Microsoft.CodeAnalysis.CSharp;
78
using Microsoft.CodeAnalysis.CSharp.Syntax;
89
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
910

1011
namespace Microsoft.Interop
1112
{
12-
internal sealed record NativeThisInfo : MarshallingInfo
13-
{
14-
public static readonly NativeThisInfo Instance = new();
15-
}
13+
internal sealed record NativeThisInfo(TypeSyntax UnwrapperType) : MarshallingInfo;
1614

1715
internal sealed class NativeToManagedThisMarshallerFactory : IMarshallingGeneratorFactory
1816
{
@@ -30,27 +28,34 @@ private sealed class Marshaller : IMarshallingGenerator
3028
public ManagedTypeInfo AsNativeType(TypePositionInfo info) => new PointerTypeInfo("void*", "void*", false);
3129
public IEnumerable<StatementSyntax> Generate(TypePositionInfo info, StubCodeContext context)
3230
{
31+
Debug.Assert(info.MarshallingAttributeInfo is NativeThisInfo);
32+
TypeSyntax unwrapperType = ((NativeThisInfo)info.MarshallingAttributeInfo).UnwrapperType;
3333
if (context.CurrentStage != StubCodeContext.Stage.Unmarshal)
3434
{
3535
yield break;
3636
}
3737

3838
(string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info);
3939

40-
// <managed> = IUnmanagedVirtualMethodTableProvider.GetObjectForUnmanagedWrapper<<managedType>>(<native>);
40+
// <managed> = (<managedType>)UnmanagedObjectUnwrapper.GetObjectFormUnmanagedWrapper<TUnmanagedUnwrapper>(<native>);
4141
yield return ExpressionStatement(
42-
AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
43-
IdentifierName(managedIdentifier),
44-
InvocationExpression(
45-
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
46-
ParseTypeName(TypeNames.IUnmanagedVirtualMethodTableProvider),
47-
GenericName(Identifier("GetObjectForUnmanagedWrapper"),
48-
TypeArgumentList(
49-
SingletonSeparatedList(
50-
info.ManagedType.Syntax)))),
51-
ArgumentList(
52-
SingletonSeparatedList(
53-
Argument(IdentifierName(nativeIdentifier)))))));
42+
AssignmentExpression(
43+
SyntaxKind.SimpleAssignmentExpression,
44+
IdentifierName(managedIdentifier),
45+
CastExpression(
46+
info.ManagedType.Syntax,
47+
InvocationExpression(
48+
MemberAccessExpression(
49+
SyntaxKind.SimpleMemberAccessExpression,
50+
ParseTypeName(TypeNames.UnmanagedObjectUnwrapper),
51+
GenericName(Identifier("GetObjectForUnmanagedWrapper"))
52+
.WithTypeArgumentList(
53+
TypeArgumentList(
54+
SingletonSeparatedList(
55+
unwrapperType)))),
56+
ArgumentList(
57+
SingletonSeparatedList(
58+
Argument(IdentifierName(nativeIdentifier))))))));
5459
}
5560

5661
public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) => SignatureBehavior.NativeType;

src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/Strings.resx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@
207207
<data name="InterfaceTypeNotSupportedMessage" xml:space="preserve">
208208
<value>Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'.</value>
209209
</data>
210+
<data name="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage" xml:space="preserve">
211+
<value>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </value>
212+
</data>
210213
<data name="MethodNotDeclaredInAttributedInterfaceDescription" xml:space="preserve">
211214
<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>
212215
</data>
@@ -216,4 +219,4 @@
216219
<data name="MethodNotDeclaredInAttributedInterfaceTitle" xml:space="preserve">
217220
<value>Method is declared in different partial declaration than the 'GeneratedComInterface' attribute.</value>
218221
</data>
219-
</root>
222+
</root>

src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.cs.xlf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@
5252
<target state="translated">Metoda {0} je obsažena v typu {1}, který není označen jako „partial“. Generování zdrojů volání P/Invoke bude metodu {0} ignorovat.</target>
5353
<note />
5454
</trans-unit>
55+
<trans-unit id="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage">
56+
<source>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </source>
57+
<target state="new">Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </target>
58+
<note />
59+
</trans-unit>
5560
<trans-unit id="InvalidAttributedMethodDescription">
5661
<source>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.</source>
5762
<target state="translated">Metody označené atributem LibraryImportAttribute by měly být typu „static“, „partial“ a non-generic. Generování zdrojů volání P/Invoke bude ignorovat metody typu non-„static“, non-„partial“ a generic.</target>

src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.de.xlf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@
5252
<target state="translated">Die Methode \"{0}\" ist in einem Typ \"{1}\" enthalten, der nicht als \"partiell\" gekennzeichnet ist. Die P/Invoke-Quellgenerierung ignoriert die Methode \"{0}\".</target>
5353
<note />
5454
</trans-unit>
55+
<trans-unit id="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage">
56+
<source>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </source>
57+
<target state="new">Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </target>
58+
<note />
59+
</trans-unit>
5560
<trans-unit id="InvalidAttributedMethodDescription">
5661
<source>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.</source>
5762
<target state="translated">Methoden, die mit \"LibraryImportAttribute\" gekennzeichnet sind, sollten \"statisch\", \"partiell\" und nicht generisch sein. Die P/Invoke-Quellgenerierung ignoriert Methoden, die nicht \"statisch\", nicht \"partiell\" oder generisch sind.</target>

src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.es.xlf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@
5252
<target state="translated">El método “{0}” está contenido en un tipo “{1}” que no está marcado como “partial”. La generación de código fuente P/Invoke omitirá el método “{0}”.</target>
5353
<note />
5454
</trans-unit>
55+
<trans-unit id="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage">
56+
<source>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </source>
57+
<target state="new">Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </target>
58+
<note />
59+
</trans-unit>
5560
<trans-unit id="InvalidAttributedMethodDescription">
5661
<source>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.</source>
5762
<target state="translated">Los métodos marcados con “LibraryImportAttribute” deben ser “static”, “partial” y no genéricos. La generación de código fuente P/Invoke omitirá los métodos que no sean “static”, “partial” ni genéricos.</target>

0 commit comments

Comments
 (0)