From 08f039edf9f83b7ff03b6bf293ad00168d356bb9 Mon Sep 17 00:00:00 2001 From: Dongle <29563098+dongle-the-gadget@users.noreply.github.com> Date: Sat, 19 Apr 2025 09:41:20 +0700 Subject: [PATCH 1/7] Add custom exception handler to COM Wrappers This is an initial iteration to add custom exception handlers to generated COM wrappers, through a new ExceptionToUnmanagedMarshaller property in GeneratedComWrappersAttribute Fix #109522 --- .../ComInterfaceGenerator.cs | 6 +-- .../ComInterfaceGenerator/ComInterfaceInfo.cs | 52 +++++++++++++++++-- .../GeneratedComInterfaceAttributeData.cs | 18 ++++++- .../GeneratorDiagnostics.cs | 9 ++++ .../VtableIndexStubGenerator.cs | 2 +- .../gen/Common/Resources/Strings.resx | 3 ++ .../gen/Common/Resources/xlf/Strings.cs.xlf | 5 ++ .../gen/Common/Resources/xlf/Strings.de.xlf | 5 ++ .../gen/Common/Resources/xlf/Strings.es.xlf | 5 ++ .../gen/Common/Resources/xlf/Strings.fr.xlf | 5 ++ .../gen/Common/Resources/xlf/Strings.it.xlf | 5 ++ .../gen/Common/Resources/xlf/Strings.ja.xlf | 5 ++ .../gen/Common/Resources/xlf/Strings.ko.xlf | 5 ++ .../gen/Common/Resources/xlf/Strings.pl.xlf | 5 ++ .../Common/Resources/xlf/Strings.pt-BR.xlf | 5 ++ .../gen/Common/Resources/xlf/Strings.ru.xlf | 5 ++ .../gen/Common/Resources/xlf/Strings.tr.xlf | 5 ++ .../Common/Resources/xlf/Strings.zh-Hans.xlf | 5 ++ .../Common/Resources/xlf/Strings.zh-Hant.xlf | 5 ++ .../BoundGenerators.cs | 4 +- .../MarshallingAttributeInfo.cs | 24 ++++++--- .../ref/System.Runtime.InteropServices.cs | 1 + .../GeneratedComInterfaceAttribute.cs | 8 +++ 23 files changed, 175 insertions(+), 17 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs index 79fb7e1982ba9f..3e0b35cd2d9b86 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs @@ -106,7 +106,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) return new ComMethodContext( data.Method, data.OwningInterface, - CalculateStubInformation(data.Method.MethodInfo.Syntax, symbolMap[data.Method.MethodInfo], data.Method.Index, env, data.OwningInterface.Info.Type, ct)); + CalculateStubInformation(data.Method.MethodInfo.Syntax, symbolMap[data.Method.MethodInfo], data.Method.Index, env, data.OwningInterface.Info.Type, data.OwningInterface.Info.ExceptionToUnmanagedMarshallerQualifiedName, ct)); }).WithTrackingName(StepNames.CalculateStubInformation); var interfaceAndMethodsContexts = comMethodContexts @@ -245,7 +245,7 @@ private static bool IsHResultLikeType(ManagedTypeInfo type) || typeName.Equals("hresult", StringComparison.OrdinalIgnoreCase); } - private static IncrementalMethodStubGenerationContext CalculateStubInformation(MethodDeclarationSyntax syntax, IMethodSymbol symbol, int index, StubEnvironment environment, ManagedTypeInfo owningInterface, CancellationToken ct) + private static IncrementalMethodStubGenerationContext CalculateStubInformation(MethodDeclarationSyntax syntax, IMethodSymbol symbol, int index, StubEnvironment environment, ManagedTypeInfo owningInterface, string? exceptionToUnmanagedMarshallerQualifiedName, CancellationToken ct) { ct.ThrowIfCancellationRequested(); INamedTypeSymbol? lcidConversionAttrType = environment.LcidConversionAttrType; @@ -396,7 +396,7 @@ private static IncrementalMethodStubGenerationContext CalculateStubInformation(M locations, callConv.ToSequenceEqualImmutableArray(SyntaxEquivalentComparer.Instance), virtualMethodIndexData, - new ComExceptionMarshalling(), + new ComExceptionMarshalling(exceptionToUnmanagedMarshallerQualifiedName), environment.EnvironmentFlags, owningInterface, declaringType, diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceInfo.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceInfo.cs index 9829c914cb11fa..bd2c38c74f1888 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceInfo.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceInfo.cs @@ -29,6 +29,7 @@ internal sealed record ComInterfaceInfo public ComInterfaceOptions Options { get; init; } public Location DiagnosticLocation { get; init; } public bool IsExternallyDefined { get; init; } + public string? ExceptionToUnmanagedMarshallerQualifiedName { get; init; } private ComInterfaceInfo( ManagedTypeInfo type, @@ -39,7 +40,8 @@ private ComInterfaceInfo( ContainingSyntax containingSyntax, Guid interfaceId, ComInterfaceOptions options, - Location diagnosticLocation) + Location diagnosticLocation, + string? exceptionToUnmanagedMarshallerFullyQualifiedName) { Type = type; ThisInterfaceKey = thisInterfaceKey; @@ -50,6 +52,7 @@ private ComInterfaceInfo( InterfaceId = interfaceId; Options = options; DiagnosticLocation = diagnosticLocation; + ExceptionToUnmanagedMarshallerQualifiedName = exceptionToUnmanagedMarshallerFullyQualifiedName; } public static DiagnosticOrInterfaceInfo From(INamedTypeSymbol symbol, InterfaceDeclarationSyntax syntax, StubEnvironment env, CancellationToken _) @@ -94,6 +97,9 @@ public static DiagnosticOrInterfaceInfo From(INamedTypeSymbol symbol, InterfaceD if (!OptionsAreValid(symbol, syntax, interfaceAttributeData, baseAttributeData, out DiagnosticInfo? optionsDiagnostic)) return DiagnosticOrInterfaceInfo.From(optionsDiagnostic); + if (!ExceptionToUnmanagedMarshallerIsValid(syntax, interfaceAttributeData, out string? exceptionToUnmanagedMarshallerFullyQualifiedName, out DiagnosticInfo? exceptionToUnmanagedMarshallerDiagnostic)) + return DiagnosticOrInterfaceInfo.From(exceptionToUnmanagedMarshallerDiagnostic); + InterfaceInfo info = ( new ComInterfaceInfo( ManagedTypeInfo.CreateTypeInfoForTypeSymbol(symbol), @@ -104,7 +110,8 @@ public static DiagnosticOrInterfaceInfo From(INamedTypeSymbol symbol, InterfaceD new ContainingSyntax(syntax.Modifiers, syntax.Kind(), syntax.Identifier, syntax.TypeParameterList), guid ?? Guid.Empty, interfaceAttributeData.Options, - syntax.Identifier.GetLocation()), + syntax.Identifier.GetLocation(), + exceptionToUnmanagedMarshallerFullyQualifiedName), symbol); // Now that we've validated all of our requirements, we will check for some non-blocking scenarios @@ -138,6 +145,11 @@ public static DiagnosticOrInterfaceInfo From(INamedTypeSymbol symbol, InterfaceD return DiagnosticOrInterfaceInfo.From(info); } + internal static readonly SymbolDisplayFormat QualifiedNameOnlyFormat = + new SymbolDisplayFormat( + globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces); + public static ImmutableArray CreateInterfaceInfoForBaseInterfacesInOtherCompilations( INamedTypeSymbol symbol) { @@ -153,6 +165,7 @@ public static ImmutableArray CreateInterfaceInfoForBaseInterfaces var thisSymbol = baseSymbol; TryGetBaseComInterface(thisSymbol, null, out baseSymbol, out _); var interfaceAttributeData = GeneratedComInterfaceCompilationData.GetAttributeDataFromInterfaceSymbol(thisSymbol); + string? exceptionToUnmanagedMarshallerQualifiedName = interfaceAttributeData.ExceptionToUnmanagedMarshaller?.ToDisplayString(QualifiedNameOnlyFormat); builder.Add(( new ComInterfaceInfo( ManagedTypeInfo.CreateTypeInfoForTypeSymbol(thisSymbol), @@ -163,7 +176,8 @@ public static ImmutableArray CreateInterfaceInfoForBaseInterfaces default, Guid.Empty, interfaceAttributeData.Options, - Location.None) + Location.None, + exceptionToUnmanagedMarshallerQualifiedName) { IsExternallyDefined = true }, @@ -285,6 +299,38 @@ private static bool OptionsAreValid( return true; } + private static bool ExceptionToUnmanagedMarshallerIsValid( + InterfaceDeclarationSyntax syntax, + GeneratedComInterfaceCompilationData attrSymbolInfo, + out string? exceptionToUnmanagedMarshallerFullyQualifiedName, + [NotNullWhen(false)] out DiagnosticInfo? exceptionToUnmanagedMarshallerDiagnostic) + { + GeneratedComInterfaceData attrInfo = GeneratedComInterfaceData.From(attrSymbolInfo); + if (attrSymbolInfo.ExceptionToUnmanagedMarshaller is INamedTypeSymbol exceptionToUnmanagedMarshallerType) + { + if (!exceptionToUnmanagedMarshallerType.IsAccessibleFromFileScopedClass(out var details)) + { + exceptionToUnmanagedMarshallerDiagnostic = DiagnosticInfo.Create( + GeneratorDiagnostics.ExceptionToUnmanagedMarshallerNotAccessibleByGeneratedCode, + syntax.Identifier.GetLocation(), + attrInfo.ExceptionToUnmanagedMarshaller.FullTypeName.Replace(TypeNames.GlobalAlias, ""), + details); + exceptionToUnmanagedMarshallerFullyQualifiedName = null; + return false; + } + else + { + exceptionToUnmanagedMarshallerFullyQualifiedName = exceptionToUnmanagedMarshallerType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + } + } + else + { + exceptionToUnmanagedMarshallerFullyQualifiedName = null; + } + exceptionToUnmanagedMarshallerDiagnostic = null; + return true; + } + /// /// Returns true if there is 0 or 1 base Com interfaces (i.e. the inheritance is valid), and returns false when there are 2 or more base Com interfaces and sets . /// diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs index b062e249759d07..a154a3a1b8a67a 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs @@ -15,6 +15,7 @@ namespace Microsoft.Interop internal sealed record GeneratedComInterfaceData : InteropAttributeData { public ComInterfaceOptions Options { get; init; } + public ManagedTypeInfo? ExceptionToUnmanagedMarshaller { get; init; } public static GeneratedComInterfaceData From(GeneratedComInterfaceCompilationData generatedComInterfaceAttr) => new GeneratedComInterfaceData() with { @@ -24,7 +25,10 @@ public static GeneratedComInterfaceData From(GeneratedComInterfaceCompilationDat StringMarshallingCustomType = generatedComInterfaceAttr.StringMarshallingCustomType is not null ? ManagedTypeInfo.CreateTypeInfoForTypeSymbol(generatedComInterfaceAttr.StringMarshallingCustomType) : null, - Options = generatedComInterfaceAttr.Options + Options = generatedComInterfaceAttr.Options, + ExceptionToUnmanagedMarshaller = generatedComInterfaceAttr.ExceptionToUnmanagedMarshaller is not null + ? ManagedTypeInfo.CreateTypeInfoForTypeSymbol(generatedComInterfaceAttr.ExceptionToUnmanagedMarshaller) + : null, }; } @@ -35,6 +39,7 @@ public static GeneratedComInterfaceData From(GeneratedComInterfaceCompilationDat internal sealed record GeneratedComInterfaceCompilationData : InteropAttributeCompilationData { public ComInterfaceOptions Options { get; init; } = ComInterfaceOptions.ManagedObjectWrapper | ComInterfaceOptions.ComObjectWrapper; + public INamedTypeSymbol? ExceptionToUnmanagedMarshaller { get; init; } public static bool TryGetGeneratedComInterfaceAttributeFromInterface(INamedTypeSymbol interfaceSymbol, [NotNullWhen(true)] out AttributeData? generatedComInterfaceAttribute) { @@ -70,6 +75,17 @@ public static GeneratedComInterfaceCompilationData GetDataFromAttribute(Attribut Options = (ComInterfaceOptions)options.Value }; } + if (args.TryGetValue(nameof(ExceptionToUnmanagedMarshaller), out TypedConstant exceptionToUnmanagedMarshaller)) + { + if (exceptionToUnmanagedMarshaller.Value is not INamedTypeSymbol) + { + return null; + } + generatedComInterfaceAttributeData = generatedComInterfaceAttributeData with + { + ExceptionToUnmanagedMarshaller = (INamedTypeSymbol)exceptionToUnmanagedMarshaller.Value + }; + } return generatedComInterfaceAttributeData; } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs index ca51e30346035a..e260ef98ec06df 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs @@ -141,6 +141,15 @@ public class Ids DiagnosticSeverity.Error, isEnabledByDefault: true); + public static readonly DiagnosticDescriptor ExceptionToUnmanagedMarshallerNotAccessibleByGeneratedCode = + DiagnosticDescriptorHelper.Create( + Ids.InvalidGeneratedComInterfaceAttributeUsage, + GetResourceString(nameof(SR.InvalidGeneratedComInterfaceAttributeUsageTitle)), + GetResourceString(nameof(SR.ExceptionToUnmanagedMarshallerNotAccessibleByGeneratedCode)), + Category, + DiagnosticSeverity.Error, + isEnabledByDefault: true); + /// public static readonly DiagnosticDescriptor InvalidExceptionMarshallingConfiguration = DiagnosticDescriptorHelper.Create( diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs index 9328c0e7d6e56e..394d1dfc139a14 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs @@ -343,7 +343,7 @@ private static MarshallingInfo CreateExceptionMarshallingInfo(AttributeData virt if (virtualMethodIndexData.ExceptionMarshalling == ExceptionMarshalling.Com) { - return new ComExceptionMarshalling(); + return new ComExceptionMarshalling(null); } if (virtualMethodIndexData.ExceptionMarshalling == ExceptionMarshalling.Custom) { diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/Strings.resx b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/Strings.resx index 7253540e16a0df..83735f19bded22 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/Strings.resx +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/Strings.resx @@ -916,4 +916,7 @@ Specifying 'GeneratedComInterfaceAttribute' on an interface that has a base interface defined in another assembly is not supported + + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf index ba1c9a3a785dba..baefd6dd66bd79 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf @@ -392,6 +392,11 @@ Zařazovací typ vstupního bodu {0} pro typ {1} musí být typ s nejméně jedním atributem System.Runtime.InteropServices.CustomMarshallerAttribute, který tento typ určuje jako spravovaný typ. + + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + + Marshalling info was specified for 'ElementIndirectionDepth' {0}, but marshalling info was only needed for {1} level(s) of indirection Informace o zařazování se určily pro ElementIndirectionDepth {0}, ale informace o zařazování byly potřebné pouze pro {1} úrovně indirekce. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf index b8b529c7c12b71..c14f2ce126bb82 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf @@ -392,6 +392,11 @@ Der Marshallertyp "{0}" des Eintrittspunkts für den Typ "{1}" muss ein Typ mit mindestens einem "System.Runtime.InteropServices.CustomMarshallerAttribute" sein, der diesen Typ als verwalteten Typ angibt + + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + + Marshalling info was specified for 'ElementIndirectionDepth' {0}, but marshalling info was only needed for {1} level(s) of indirection Marshallinginformationen wurden für \"ElementIndirectionDepth\" {0}angegeben. Marshallinginformationen wurden jedoch nur für {1} Dereferenzierungsebene(n) benötigt. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf index 89886b7f025883..52c7c6e7c2aa77 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf @@ -392,6 +392,11 @@ El tipo de serializador de punto de entrada "{0}" para el tipo "{1}" debe ser un tipo con al menos un "System.Runtime.InteropServices.CustomMarshallerAttribute" que especifique este tipo como el tipo administrado + + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + + Marshalling info was specified for 'ElementIndirectionDepth' {0}, but marshalling info was only needed for {1} level(s) of indirection Se especificó información de serialización para “ElementIndirectionDepth” {0}, pero la información de serialización solo era necesaria para {1} niveles de direccionamiento indirecto diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf index 34309a0a8dc920..0a4ca5001abda2 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf @@ -392,6 +392,11 @@ Le type de marshaleur de point d’entrée « {0} » pour le type « {1} » doit être un type avec au moins un type « System.Runtime.InteropServices.CustomMarspiaerAttribute » qui spécifie ce type comme type managé + + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + + Marshalling info was specified for 'ElementIndirectionDepth' {0}, but marshalling info was only needed for {1} level(s) of indirection Des informations de marshaling ont été spécifiées pour « ElementIndirectionDepth » {0}, mais les informations de marshaling étaient uniquement nécessaires pour {1} niveau(s) d’indirection diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf index 598b0874ab7f25..e84ca09f0b32c5 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf @@ -392,6 +392,11 @@ Il tipo di marshaller del punto di ingresso '{0}' per il tipo '{1}' deve essere un tipo con almeno un elemento 'System.Runtime.InteropServices.CustomMarshallerAttribute' che specifica questo tipo come tipo gestito + + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + + Marshalling info was specified for 'ElementIndirectionDepth' {0}, but marshalling info was only needed for {1} level(s) of indirection Sono state specificate informazioni di marshalling per l'elemento 'ElementIndirectionDepth' {0}, ma le informazioni di marshalling sono necessarie solo per {1} livello/i di riferimento indiretto diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf index e0c3c159f39952..4ef640080a7209 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf @@ -392,6 +392,11 @@ 型 '{1}' 向けのエントリ ポイント マーシャラー型 '{0}' は、この型をマネージド型として指定する 'System.Runtime.InteropServices.CustomMarshallerAttribute' を 1 つ以上持つ型である必要があります + + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + + Marshalling info was specified for 'ElementIndirectionDepth' {0}, but marshalling info was only needed for {1} level(s) of indirection 'ElementIndirectionDepth' {0} にマーシャリング情報が指定されましたが、マーシャリング情報は間接参照の {1} レベルにのみ必要です diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf index 3544bea85669bd..24405cdb59aac8 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf @@ -392,6 +392,11 @@ '{1}' 유형의 진입점 마샬러 유형 '{0}'은(는) 이 유형을 관리 유형으로 지정하는 'System.Runtime.InteropServices.CustomMarshallerAttribute'가 하나 이상 있는 유형이어야 합니다. + + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + + Marshalling info was specified for 'ElementIndirectionDepth' {0}, but marshalling info was only needed for {1} level(s) of indirection 마샬링 정보가 'ElementIndirectionDepth' {0}에 대해 지정되었지만 마샬링 정보는 간접 참조 수준 {1}에만 필요했습니다. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf index 30bc2cef8ae4de..d253359ff888af 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf @@ -392,6 +392,11 @@ Typ marshallera punktu wejścia „{0}” dla typu „{1}” musi być typem z co najmniej jednym atrybutem „System.Runtime.InteropServices.CustomMarshaellerAttribute”, który określa ten typ jako typ zarządzany + + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + + Marshalling info was specified for 'ElementIndirectionDepth' {0}, but marshalling info was only needed for {1} level(s) of indirection Informacje dotyczące skierowania zostały określone dla elementu „ElementIndirectionDepth” {0}, ale informacje dotyczące skierowania były potrzebne tylko dla poziomów pośrednich w liczbie {1} diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf index 3b825512d46ceb..ad2508b1e6fa8d 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf @@ -392,6 +392,11 @@ O tipo de empacotador de ponto de entrada '{0}' para o tipo '{1}' deve ser um tipo com pelo menos um 'System.Runtime.InteropServices.CustomMarshallerAttribute' que especifica esse tipo como o tipo gerenciado + + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + + Marshalling info was specified for 'ElementIndirectionDepth' {0}, but marshalling info was only needed for {1} level(s) of indirection As informações de marshalling foram especificadas para o {0} 'ElementIndirectionDepth', mas as informações de marshalling só eram necessárias para {1} nível(s) de indireção diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf index 27d7f597d2202c..790c09bac83a32 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf @@ -392,6 +392,11 @@ Тип маршалера точки входа "{0}" для типа "{1}" должен содержать хотя бы один атрибут "System.Runtime.InteropServices.CustomMarshallerAttribute", указывающий этот тип в качестве управляемого типа + + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + + Marshalling info was specified for 'ElementIndirectionDepth' {0}, but marshalling info was only needed for {1} level(s) of indirection Для \"ElementIndirectionDepth\" {0} указаны сведения маршализации, но они необходимы только для {1} уровней косвенного обращения diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf index 72813018d87503..b7a6c35d02677a 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf @@ -392,6 +392,11 @@ Tür '{1}' için giriş noktası hazırlayıcı türü '{0}', bu türü yönetilen tür olarak belirten en az bir 'System.Runtime.InteropServices.CustomMarshallerAttribute' türü olmalıdır + + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + + Marshalling info was specified for 'ElementIndirectionDepth' {0}, but marshalling info was only needed for {1} level(s) of indirection 'ElementIndirectionDepth' {0} için sıralama bilgileri belirtildi, ancak sıralama bilgileri yalnızca {1} yöneltme düzeyi için gerekli diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf index b9e21c430f3a76..7dd28559a7dccc 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf @@ -392,6 +392,11 @@ 适用于类型“{1}”的入口点封送处理程序类型“{0}”必须是至少具有一个指定此类型为托管类型的 “System.Runtime.InteropServices.CustomMarshallerAttribute”的类型 + + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + + Marshalling info was specified for 'ElementIndirectionDepth' {0}, but marshalling info was only needed for {1} level(s) of indirection 为 “ElementIndirectionDepth” {0} 指定了封送信息,但只有间接的 {1} 级别需要封送信息 diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf index feb774294e8ea0..f422c201a2a497 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf @@ -392,6 +392,11 @@ 類型 '{1}' 的進入點封送處理器類型 '{0}' 必須是具有至少一個 'System.Runtime.InteropServices.CustomMarshallerAttribute' 的類型,指定此類型為受控類型 + + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1} + + Marshalling info was specified for 'ElementIndirectionDepth' {0}, but marshalling info was only needed for {1} level(s) of indirection 已為 'ElementIndirectionDepth' {0}指定封送處理資訊,但只有 {1}層級 (間接) 需要封送處理資訊 diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/BoundGenerators.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/BoundGenerators.cs index c517a0c0353999..019241ce3c0140 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/BoundGenerators.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/BoundGenerators.cs @@ -84,7 +84,7 @@ public static BoundGenerators Create(ImmutableArray elementTyp overlappedMarshaller = nativeParamMarshallers.FirstOrDefault(e => e.TypeInfo.NativeIndex == managedExceptionInfo.NativeIndex); } - if (managedExceptionInfo.MarshallingAttributeInfo is ComExceptionMarshalling) + if (managedExceptionInfo.MarshallingAttributeInfo is ComExceptionMarshalling comExceptionMarshalling) { if (overlappedMarshaller is null) { @@ -94,7 +94,7 @@ public static BoundGenerators Create(ImmutableArray elementTyp { managedExceptionInfo = managedExceptionInfo with { - MarshallingAttributeInfo = ComExceptionMarshalling.CreateSpecificMarshallingInfo(overlappedMarshaller.NativeType) + MarshallingAttributeInfo = comExceptionMarshalling.CreateSpecificMarshallingInfo(overlappedMarshaller.NativeType) }; } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs index 6dcc8b97fcedb3..ff5bcf9e31e101 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs @@ -160,16 +160,26 @@ IEnumerable GetElementDependencies() /// public sealed record ComExceptionMarshalling : MarshallingInfo { - internal static MarshallingInfo CreateSpecificMarshallingInfo(ManagedTypeInfo unmanagedReturnType) + public ComExceptionMarshalling() : this((string?)null) + { } + + public ComExceptionMarshalling(string? exceptionToUnmanagedMarshallerQualifiedName) + { + _exceptionToUnmanagedMarshallerQualifiedName = exceptionToUnmanagedMarshallerQualifiedName; + } + + private readonly string? _exceptionToUnmanagedMarshallerQualifiedName; + + internal MarshallingInfo CreateSpecificMarshallingInfo(ManagedTypeInfo unmanagedReturnType) { return (unmanagedReturnType as SpecialTypeInfo)?.SpecialType switch { - SpecialType.System_Void => CreateWellKnownComExceptionMarshallingData(TypeNames.ExceptionAsVoidMarshaller, unmanagedReturnType), - SpecialType.System_Int32 => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionAsHResultMarshaller}", unmanagedReturnType), - SpecialType.System_UInt32 => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionAsHResultMarshaller}", unmanagedReturnType), - SpecialType.System_Single => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionAsNaNMarshaller}", unmanagedReturnType), - SpecialType.System_Double => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionAsNaNMarshaller}", unmanagedReturnType), - _ => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionAsDefaultMarshaller}<{MarshallerHelpers.GetCompatibleGenericTypeParameterSyntax(SyntaxFactory.ParseTypeName(unmanagedReturnType.FullTypeName))}>", unmanagedReturnType), + SpecialType.System_Void => CreateWellKnownComExceptionMarshallingData(_exceptionToUnmanagedMarshallerQualifiedName ?? TypeNames.ExceptionAsVoidMarshaller, unmanagedReturnType), + SpecialType.System_Int32 => CreateWellKnownComExceptionMarshallingData($"{_exceptionToUnmanagedMarshallerQualifiedName ?? TypeNames.ExceptionAsHResultMarshaller}", unmanagedReturnType), + SpecialType.System_UInt32 => CreateWellKnownComExceptionMarshallingData($"{_exceptionToUnmanagedMarshallerQualifiedName ?? TypeNames.ExceptionAsHResultMarshaller}", unmanagedReturnType), + SpecialType.System_Single => CreateWellKnownComExceptionMarshallingData($"{_exceptionToUnmanagedMarshallerQualifiedName ?? TypeNames.ExceptionAsNaNMarshaller}", unmanagedReturnType), + SpecialType.System_Double => CreateWellKnownComExceptionMarshallingData($"{_exceptionToUnmanagedMarshallerQualifiedName ?? TypeNames.ExceptionAsNaNMarshaller}", unmanagedReturnType), + _ => CreateWellKnownComExceptionMarshallingData($"{_exceptionToUnmanagedMarshallerQualifiedName ?? TypeNames.ExceptionAsDefaultMarshaller}<{MarshallerHelpers.GetCompatibleGenericTypeParameterSyntax(SyntaxFactory.ParseTypeName(unmanagedReturnType.FullTypeName))}>", unmanagedReturnType), }; static NativeMarshallingAttributeInfo CreateWellKnownComExceptionMarshallingData(string marshallerName, ManagedTypeInfo unmanagedType) diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index eb2130e4f80bc8..d262bcb20fa3ec 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -394,6 +394,7 @@ public GeneratedComInterfaceAttribute() { } public System.Runtime.InteropServices.Marshalling.ComInterfaceOptions Options { get { throw null; } set { } } public System.Runtime.InteropServices.StringMarshalling StringMarshalling { get { throw null; } set { } } public System.Type? StringMarshallingCustomType { get { throw null; } set { } } + public System.Type? ExceptionToUnmanagedMarshaller { get { throw null; } set { } } } [System.CLSCompliantAttribute(false)] public partial interface IComExposedClass diff --git a/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/GeneratedComInterfaceAttribute.cs b/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/GeneratedComInterfaceAttribute.cs index 60bc272d09284d..917af533139a8d 100644 --- a/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/GeneratedComInterfaceAttribute.cs +++ b/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/GeneratedComInterfaceAttribute.cs @@ -38,5 +38,13 @@ public class GeneratedComInterfaceAttribute : Attribute /// or must be set to . /// public Type? StringMarshallingCustomType { get; set; } + + /// + /// Gets or sets the used to control how exceptions are marshalled for all methods on the interface. + /// + /// + /// If this field is not specified, is used to marshal exceptions. + /// + public Type? ExceptionToUnmanagedMarshaller { get; set; } } } From 1a6614854d2b79074a2f49511d78eed644f2e531 Mon Sep 17 00:00:00 2001 From: Dongle <29563098+dongle-the-gadget@users.noreply.github.com> Date: Sat, 19 Apr 2025 10:33:31 +0700 Subject: [PATCH 2/7] Copy VTable Index exception logic over Resolves an issue with previous implementation, highlighted by Jeremy. The previous implementation is overcomplicated and hooks into the default exception logic, which is not ideal. This commit copies the existing custom exception marshalling logic from the VTable stub generator. --- .../ComInterfaceGenerator.cs | 22 ++++++-- .../ComInterfaceGenerator/ComInterfaceInfo.cs | 29 ++--------- .../VtableIndexStubGenerator.cs | 2 +- .../BoundGenerators.cs | 2 +- .../ISymbolExtensions.cs | 52 +++++++++++++++++++ .../MarshallingAttributeInfo.cs | 24 +++------ 6 files changed, 84 insertions(+), 47 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs index 3e0b35cd2d9b86..9841c86e869a43 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs @@ -106,7 +106,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) return new ComMethodContext( data.Method, data.OwningInterface, - CalculateStubInformation(data.Method.MethodInfo.Syntax, symbolMap[data.Method.MethodInfo], data.Method.Index, env, data.OwningInterface.Info.Type, data.OwningInterface.Info.ExceptionToUnmanagedMarshallerQualifiedName, ct)); + CalculateStubInformation(data.Method.MethodInfo.Syntax, symbolMap[data.Method.MethodInfo], data.Method.Index, env, data.OwningInterface.Info.Type, ct)); }).WithTrackingName(StepNames.CalculateStubInformation); var interfaceAndMethodsContexts = comMethodContexts @@ -245,7 +245,7 @@ private static bool IsHResultLikeType(ManagedTypeInfo type) || typeName.Equals("hresult", StringComparison.OrdinalIgnoreCase); } - private static IncrementalMethodStubGenerationContext CalculateStubInformation(MethodDeclarationSyntax syntax, IMethodSymbol symbol, int index, StubEnvironment environment, ManagedTypeInfo owningInterface, string? exceptionToUnmanagedMarshallerQualifiedName, CancellationToken ct) + private static IncrementalMethodStubGenerationContext CalculateStubInformation(MethodDeclarationSyntax syntax, IMethodSymbol symbol, int index, StubEnvironment environment, ManagedTypeInfo owningInterface, CancellationToken ct) { ct.ThrowIfCancellationRequested(); INamedTypeSymbol? lcidConversionAttrType = environment.LcidConversionAttrType; @@ -389,6 +389,22 @@ private static IncrementalMethodStubGenerationContext CalculateStubInformation(M var virtualMethodIndexData = new VirtualMethodIndexData(index, ImplicitThisParameter: true, direction, true, ExceptionMarshalling.Com); + MarshallingInfo exceptionMarshallingInfo; + + if (generatedComInterfaceAttributeData.ExceptionToUnmanagedMarshaller is not null) + { + exceptionMarshallingInfo = CustomMarshallingInfoHelper.CreateNativeMarshallingInfoForNonSignatureElement( + environment.Compilation.GetTypeByMetadataName(TypeNames.System_Exception), + generatedComInterfaceAttributeData.ExceptionToUnmanagedMarshaller, + generatedComAttribute, + environment.Compilation, + generatorDiagnostics); + } + else + { + exceptionMarshallingInfo = new ComExceptionMarshalling(); + } + return new IncrementalMethodStubGenerationContext( signatureContext, containingSyntaxContext, @@ -396,7 +412,7 @@ private static IncrementalMethodStubGenerationContext CalculateStubInformation(M locations, callConv.ToSequenceEqualImmutableArray(SyntaxEquivalentComparer.Instance), virtualMethodIndexData, - new ComExceptionMarshalling(exceptionToUnmanagedMarshallerQualifiedName), + exceptionMarshallingInfo, environment.EnvironmentFlags, owningInterface, declaringType, diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceInfo.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceInfo.cs index bd2c38c74f1888..dce9d1435c533e 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceInfo.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceInfo.cs @@ -29,7 +29,6 @@ internal sealed record ComInterfaceInfo public ComInterfaceOptions Options { get; init; } public Location DiagnosticLocation { get; init; } public bool IsExternallyDefined { get; init; } - public string? ExceptionToUnmanagedMarshallerQualifiedName { get; init; } private ComInterfaceInfo( ManagedTypeInfo type, @@ -40,8 +39,7 @@ private ComInterfaceInfo( ContainingSyntax containingSyntax, Guid interfaceId, ComInterfaceOptions options, - Location diagnosticLocation, - string? exceptionToUnmanagedMarshallerFullyQualifiedName) + Location diagnosticLocation) { Type = type; ThisInterfaceKey = thisInterfaceKey; @@ -52,7 +50,6 @@ private ComInterfaceInfo( InterfaceId = interfaceId; Options = options; DiagnosticLocation = diagnosticLocation; - ExceptionToUnmanagedMarshallerQualifiedName = exceptionToUnmanagedMarshallerFullyQualifiedName; } public static DiagnosticOrInterfaceInfo From(INamedTypeSymbol symbol, InterfaceDeclarationSyntax syntax, StubEnvironment env, CancellationToken _) @@ -97,7 +94,7 @@ public static DiagnosticOrInterfaceInfo From(INamedTypeSymbol symbol, InterfaceD if (!OptionsAreValid(symbol, syntax, interfaceAttributeData, baseAttributeData, out DiagnosticInfo? optionsDiagnostic)) return DiagnosticOrInterfaceInfo.From(optionsDiagnostic); - if (!ExceptionToUnmanagedMarshallerIsValid(syntax, interfaceAttributeData, out string? exceptionToUnmanagedMarshallerFullyQualifiedName, out DiagnosticInfo? exceptionToUnmanagedMarshallerDiagnostic)) + if (!ExceptionToUnmanagedMarshallerIsValid(syntax, interfaceAttributeData, out DiagnosticInfo? exceptionToUnmanagedMarshallerDiagnostic)) return DiagnosticOrInterfaceInfo.From(exceptionToUnmanagedMarshallerDiagnostic); InterfaceInfo info = ( @@ -110,8 +107,7 @@ public static DiagnosticOrInterfaceInfo From(INamedTypeSymbol symbol, InterfaceD new ContainingSyntax(syntax.Modifiers, syntax.Kind(), syntax.Identifier, syntax.TypeParameterList), guid ?? Guid.Empty, interfaceAttributeData.Options, - syntax.Identifier.GetLocation(), - exceptionToUnmanagedMarshallerFullyQualifiedName), + syntax.Identifier.GetLocation()), symbol); // Now that we've validated all of our requirements, we will check for some non-blocking scenarios @@ -145,11 +141,6 @@ public static DiagnosticOrInterfaceInfo From(INamedTypeSymbol symbol, InterfaceD return DiagnosticOrInterfaceInfo.From(info); } - internal static readonly SymbolDisplayFormat QualifiedNameOnlyFormat = - new SymbolDisplayFormat( - globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted, - typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces); - public static ImmutableArray CreateInterfaceInfoForBaseInterfacesInOtherCompilations( INamedTypeSymbol symbol) { @@ -165,7 +156,6 @@ public static ImmutableArray CreateInterfaceInfoForBaseInterfaces var thisSymbol = baseSymbol; TryGetBaseComInterface(thisSymbol, null, out baseSymbol, out _); var interfaceAttributeData = GeneratedComInterfaceCompilationData.GetAttributeDataFromInterfaceSymbol(thisSymbol); - string? exceptionToUnmanagedMarshallerQualifiedName = interfaceAttributeData.ExceptionToUnmanagedMarshaller?.ToDisplayString(QualifiedNameOnlyFormat); builder.Add(( new ComInterfaceInfo( ManagedTypeInfo.CreateTypeInfoForTypeSymbol(thisSymbol), @@ -176,8 +166,7 @@ public static ImmutableArray CreateInterfaceInfoForBaseInterfaces default, Guid.Empty, interfaceAttributeData.Options, - Location.None, - exceptionToUnmanagedMarshallerQualifiedName) + Location.None) { IsExternallyDefined = true }, @@ -302,7 +291,6 @@ private static bool OptionsAreValid( private static bool ExceptionToUnmanagedMarshallerIsValid( InterfaceDeclarationSyntax syntax, GeneratedComInterfaceCompilationData attrSymbolInfo, - out string? exceptionToUnmanagedMarshallerFullyQualifiedName, [NotNullWhen(false)] out DiagnosticInfo? exceptionToUnmanagedMarshallerDiagnostic) { GeneratedComInterfaceData attrInfo = GeneratedComInterfaceData.From(attrSymbolInfo); @@ -315,17 +303,8 @@ private static bool ExceptionToUnmanagedMarshallerIsValid( syntax.Identifier.GetLocation(), attrInfo.ExceptionToUnmanagedMarshaller.FullTypeName.Replace(TypeNames.GlobalAlias, ""), details); - exceptionToUnmanagedMarshallerFullyQualifiedName = null; return false; } - else - { - exceptionToUnmanagedMarshallerFullyQualifiedName = exceptionToUnmanagedMarshallerType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); - } - } - else - { - exceptionToUnmanagedMarshallerFullyQualifiedName = null; } exceptionToUnmanagedMarshallerDiagnostic = null; return true; diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs index 394d1dfc139a14..9328c0e7d6e56e 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs @@ -343,7 +343,7 @@ private static MarshallingInfo CreateExceptionMarshallingInfo(AttributeData virt if (virtualMethodIndexData.ExceptionMarshalling == ExceptionMarshalling.Com) { - return new ComExceptionMarshalling(null); + return new ComExceptionMarshalling(); } if (virtualMethodIndexData.ExceptionMarshalling == ExceptionMarshalling.Custom) { diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/BoundGenerators.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/BoundGenerators.cs index 019241ce3c0140..5b4f18cbc4cfe8 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/BoundGenerators.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/BoundGenerators.cs @@ -94,7 +94,7 @@ public static BoundGenerators Create(ImmutableArray elementTyp { managedExceptionInfo = managedExceptionInfo with { - MarshallingAttributeInfo = comExceptionMarshalling.CreateSpecificMarshallingInfo(overlappedMarshaller.NativeType) + MarshallingAttributeInfo = ComExceptionMarshalling.CreateSpecificMarshallingInfo(overlappedMarshaller.NativeType) }; } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ISymbolExtensions.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ISymbolExtensions.cs index c8fc383f4d501a..1b57e42c08a735 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ISymbolExtensions.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ISymbolExtensions.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Text; using Microsoft.CodeAnalysis; namespace Microsoft.Interop @@ -32,5 +33,56 @@ public static bool IsAccessibleFromFileScopedClass(this INamedTypeSymbol symbol, details = null; return true; } + + /// + /// Gets the fully qualified metadata name for a given symbol. + /// + /// The input instance. + public static string GetFullyQualifiedMetadataName(this ITypeSymbol symbol) + { + StringBuilder builder = new(); + + static void BuildFrom(ISymbol? symbol, StringBuilder builder) + { + switch (symbol) + { + // Namespaces that are nested also append a leading '.' + case INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: false }: + BuildFrom(symbol.ContainingNamespace, builder); + builder.Append('.'); + builder.Append(symbol.MetadataName); + break; + + // Other namespaces (ie. the one right before global) skip the leading '.' + case INamespaceSymbol { IsGlobalNamespace: false }: + builder.Append(symbol.MetadataName); + break; + + // Types with no namespace just have their metadata name directly written + case ITypeSymbol { ContainingSymbol: INamespaceSymbol { IsGlobalNamespace: true } }: + builder.Append(symbol.MetadataName); + break; + + // Types with a containing non-global namespace also append a leading '.' + case ITypeSymbol { ContainingSymbol: INamespaceSymbol namespaceSymbol }: + BuildFrom(namespaceSymbol, builder); + builder.Append('.'); + builder.Append(symbol.MetadataName); + break; + + // Nested types append a leading '+' + case ITypeSymbol { ContainingSymbol: ITypeSymbol typeSymbol }: + BuildFrom(typeSymbol, builder); + builder.Append('+'); + builder.Append(symbol.MetadataName); + break; + default: + break; + } + } + + BuildFrom(symbol, builder); + return builder.ToString(); + } } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs index ff5bcf9e31e101..6dcc8b97fcedb3 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshallingAttributeInfo.cs @@ -160,26 +160,16 @@ IEnumerable GetElementDependencies() /// public sealed record ComExceptionMarshalling : MarshallingInfo { - public ComExceptionMarshalling() : this((string?)null) - { } - - public ComExceptionMarshalling(string? exceptionToUnmanagedMarshallerQualifiedName) - { - _exceptionToUnmanagedMarshallerQualifiedName = exceptionToUnmanagedMarshallerQualifiedName; - } - - private readonly string? _exceptionToUnmanagedMarshallerQualifiedName; - - internal MarshallingInfo CreateSpecificMarshallingInfo(ManagedTypeInfo unmanagedReturnType) + internal static MarshallingInfo CreateSpecificMarshallingInfo(ManagedTypeInfo unmanagedReturnType) { return (unmanagedReturnType as SpecialTypeInfo)?.SpecialType switch { - SpecialType.System_Void => CreateWellKnownComExceptionMarshallingData(_exceptionToUnmanagedMarshallerQualifiedName ?? TypeNames.ExceptionAsVoidMarshaller, unmanagedReturnType), - SpecialType.System_Int32 => CreateWellKnownComExceptionMarshallingData($"{_exceptionToUnmanagedMarshallerQualifiedName ?? TypeNames.ExceptionAsHResultMarshaller}", unmanagedReturnType), - SpecialType.System_UInt32 => CreateWellKnownComExceptionMarshallingData($"{_exceptionToUnmanagedMarshallerQualifiedName ?? TypeNames.ExceptionAsHResultMarshaller}", unmanagedReturnType), - SpecialType.System_Single => CreateWellKnownComExceptionMarshallingData($"{_exceptionToUnmanagedMarshallerQualifiedName ?? TypeNames.ExceptionAsNaNMarshaller}", unmanagedReturnType), - SpecialType.System_Double => CreateWellKnownComExceptionMarshallingData($"{_exceptionToUnmanagedMarshallerQualifiedName ?? TypeNames.ExceptionAsNaNMarshaller}", unmanagedReturnType), - _ => CreateWellKnownComExceptionMarshallingData($"{_exceptionToUnmanagedMarshallerQualifiedName ?? TypeNames.ExceptionAsDefaultMarshaller}<{MarshallerHelpers.GetCompatibleGenericTypeParameterSyntax(SyntaxFactory.ParseTypeName(unmanagedReturnType.FullTypeName))}>", unmanagedReturnType), + SpecialType.System_Void => CreateWellKnownComExceptionMarshallingData(TypeNames.ExceptionAsVoidMarshaller, unmanagedReturnType), + SpecialType.System_Int32 => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionAsHResultMarshaller}", unmanagedReturnType), + SpecialType.System_UInt32 => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionAsHResultMarshaller}", unmanagedReturnType), + SpecialType.System_Single => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionAsNaNMarshaller}", unmanagedReturnType), + SpecialType.System_Double => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionAsNaNMarshaller}", unmanagedReturnType), + _ => CreateWellKnownComExceptionMarshallingData($"{TypeNames.ExceptionAsDefaultMarshaller}<{MarshallerHelpers.GetCompatibleGenericTypeParameterSyntax(SyntaxFactory.ParseTypeName(unmanagedReturnType.FullTypeName))}>", unmanagedReturnType), }; static NativeMarshallingAttributeInfo CreateWellKnownComExceptionMarshallingData(string marshallerName, ManagedTypeInfo unmanagedType) From d5cef7ec204aca52eb6760c69c9323d713c6f5b1 Mon Sep 17 00:00:00 2001 From: Dongle <29563098+dongle-the-gadget@users.noreply.github.com> Date: Sat, 19 Apr 2025 10:49:35 +0700 Subject: [PATCH 3/7] Remove redundant marshaller in interface data --- .../gen/ComInterfaceGenerator/ComInterfaceInfo.cs | 3 +-- .../GeneratedComInterfaceAttributeData.cs | 4 ---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceInfo.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceInfo.cs index dce9d1435c533e..1aa502aec58a33 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceInfo.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceInfo.cs @@ -293,7 +293,6 @@ private static bool ExceptionToUnmanagedMarshallerIsValid( GeneratedComInterfaceCompilationData attrSymbolInfo, [NotNullWhen(false)] out DiagnosticInfo? exceptionToUnmanagedMarshallerDiagnostic) { - GeneratedComInterfaceData attrInfo = GeneratedComInterfaceData.From(attrSymbolInfo); if (attrSymbolInfo.ExceptionToUnmanagedMarshaller is INamedTypeSymbol exceptionToUnmanagedMarshallerType) { if (!exceptionToUnmanagedMarshallerType.IsAccessibleFromFileScopedClass(out var details)) @@ -301,7 +300,7 @@ private static bool ExceptionToUnmanagedMarshallerIsValid( exceptionToUnmanagedMarshallerDiagnostic = DiagnosticInfo.Create( GeneratorDiagnostics.ExceptionToUnmanagedMarshallerNotAccessibleByGeneratedCode, syntax.Identifier.GetLocation(), - attrInfo.ExceptionToUnmanagedMarshaller.FullTypeName.Replace(TypeNames.GlobalAlias, ""), + exceptionToUnmanagedMarshallerType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat).Replace(TypeNames.GlobalAlias, ""), details); return false; } diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs index a154a3a1b8a67a..54e3a9f23976e4 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs @@ -15,7 +15,6 @@ namespace Microsoft.Interop internal sealed record GeneratedComInterfaceData : InteropAttributeData { public ComInterfaceOptions Options { get; init; } - public ManagedTypeInfo? ExceptionToUnmanagedMarshaller { get; init; } public static GeneratedComInterfaceData From(GeneratedComInterfaceCompilationData generatedComInterfaceAttr) => new GeneratedComInterfaceData() with { @@ -26,9 +25,6 @@ public static GeneratedComInterfaceData From(GeneratedComInterfaceCompilationDat ? ManagedTypeInfo.CreateTypeInfoForTypeSymbol(generatedComInterfaceAttr.StringMarshallingCustomType) : null, Options = generatedComInterfaceAttr.Options, - ExceptionToUnmanagedMarshaller = generatedComInterfaceAttr.ExceptionToUnmanagedMarshaller is not null - ? ManagedTypeInfo.CreateTypeInfoForTypeSymbol(generatedComInterfaceAttr.ExceptionToUnmanagedMarshaller) - : null, }; } From 5319da663e388ecceb0f9fd892c0f1b05e40148e Mon Sep 17 00:00:00 2001 From: Dongle <29563098+dongle-the-gadget@users.noreply.github.com> Date: Sat, 19 Apr 2025 10:50:41 +0700 Subject: [PATCH 4/7] Remove redundant metadata name logic --- .../ISymbolExtensions.cs | 51 ------------------- 1 file changed, 51 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ISymbolExtensions.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ISymbolExtensions.cs index 1b57e42c08a735..8ae1e23bf78b3c 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ISymbolExtensions.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ISymbolExtensions.cs @@ -33,56 +33,5 @@ public static bool IsAccessibleFromFileScopedClass(this INamedTypeSymbol symbol, details = null; return true; } - - /// - /// Gets the fully qualified metadata name for a given symbol. - /// - /// The input instance. - public static string GetFullyQualifiedMetadataName(this ITypeSymbol symbol) - { - StringBuilder builder = new(); - - static void BuildFrom(ISymbol? symbol, StringBuilder builder) - { - switch (symbol) - { - // Namespaces that are nested also append a leading '.' - case INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: false }: - BuildFrom(symbol.ContainingNamespace, builder); - builder.Append('.'); - builder.Append(symbol.MetadataName); - break; - - // Other namespaces (ie. the one right before global) skip the leading '.' - case INamespaceSymbol { IsGlobalNamespace: false }: - builder.Append(symbol.MetadataName); - break; - - // Types with no namespace just have their metadata name directly written - case ITypeSymbol { ContainingSymbol: INamespaceSymbol { IsGlobalNamespace: true } }: - builder.Append(symbol.MetadataName); - break; - - // Types with a containing non-global namespace also append a leading '.' - case ITypeSymbol { ContainingSymbol: INamespaceSymbol namespaceSymbol }: - BuildFrom(namespaceSymbol, builder); - builder.Append('.'); - builder.Append(symbol.MetadataName); - break; - - // Nested types append a leading '+' - case ITypeSymbol { ContainingSymbol: ITypeSymbol typeSymbol }: - BuildFrom(typeSymbol, builder); - builder.Append('+'); - builder.Append(symbol.MetadataName); - break; - default: - break; - } - } - - BuildFrom(symbol, builder); - return builder.ToString(); - } } } From e86c58ffb572b48018331aecfaa4354d8ab47a0a Mon Sep 17 00:00:00 2001 From: Dongle <29563098+dongle-the-gadget@users.noreply.github.com> Date: Sat, 19 Apr 2025 11:25:26 +0700 Subject: [PATCH 5/7] Remove leftover System.Text namespace Co-authored-by: Jeremy Koritzinsky --- .../gen/Microsoft.Interop.SourceGeneration/ISymbolExtensions.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ISymbolExtensions.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ISymbolExtensions.cs index 8ae1e23bf78b3c..c8fc383f4d501a 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ISymbolExtensions.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ISymbolExtensions.cs @@ -3,7 +3,6 @@ using System; using System.Diagnostics.CodeAnalysis; -using System.Text; using Microsoft.CodeAnalysis; namespace Microsoft.Interop From cf6a5bf914054751ba3d49325b1f5d2c762ea32e Mon Sep 17 00:00:00 2001 From: Dongle <29563098+dongle-the-gadget@users.noreply.github.com> Date: Sat, 19 Apr 2025 11:25:42 +0700 Subject: [PATCH 6/7] Remove leftover null pattern matching Co-authored-by: Jeremy Koritzinsky --- .../gen/Microsoft.Interop.SourceGeneration/BoundGenerators.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/BoundGenerators.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/BoundGenerators.cs index 5b4f18cbc4cfe8..c517a0c0353999 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/BoundGenerators.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/BoundGenerators.cs @@ -84,7 +84,7 @@ public static BoundGenerators Create(ImmutableArray elementTyp overlappedMarshaller = nativeParamMarshallers.FirstOrDefault(e => e.TypeInfo.NativeIndex == managedExceptionInfo.NativeIndex); } - if (managedExceptionInfo.MarshallingAttributeInfo is ComExceptionMarshalling comExceptionMarshalling) + if (managedExceptionInfo.MarshallingAttributeInfo is ComExceptionMarshalling) { if (overlappedMarshaller is null) { From d9804bb86baaba46b12bfd68463a672a15739945 Mon Sep 17 00:00:00 2001 From: Dongle <29563098+dongle-the-gadget@users.noreply.github.com> Date: Sun, 20 Apr 2025 14:06:16 +0700 Subject: [PATCH 7/7] Remove extra colon Co-authored-by: Aaron Robinson --- .../ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs index 54e3a9f23976e4..69ae9bcefd3b04 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs @@ -24,7 +24,7 @@ public static GeneratedComInterfaceData From(GeneratedComInterfaceCompilationDat StringMarshallingCustomType = generatedComInterfaceAttr.StringMarshallingCustomType is not null ? ManagedTypeInfo.CreateTypeInfoForTypeSymbol(generatedComInterfaceAttr.StringMarshallingCustomType) : null, - Options = generatedComInterfaceAttr.Options, + Options = generatedComInterfaceAttr.Options }; }