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 01/13] 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 02/13] 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 03/13] 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 04/13] 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 05/13] 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 06/13] 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 07/13] 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 }; } From 37de31faeb155de3b161df17ff5ccbc63d79888c Mon Sep 17 00:00:00 2001 From: Dongle <29563098+dongle-the-gadget@users.noreply.github.com> Date: Sat, 3 May 2025 15:42:50 +0700 Subject: [PATCH 08/13] Prevent exception when exception marshaller is invalid --- .../ComInterfaceGenerator.cs | 2 +- .../ComInterfaceGenerator/ComInterfaceInfo.cs | 7 +++++++ .../GeneratedComInterfaceAttributeData.cs | 8 ++----- .../GeneratorDiagnostics.cs | 11 ++++++++++ .../gen/Common/Resources/Strings.resx | 5 ++++- .../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 +++++ .../CompileFails.cs | 21 +++++++++++++++++++ 19 files changed, 111 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs index 9841c86e869a43..19093263e3f761 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs @@ -395,7 +395,7 @@ private static IncrementalMethodStubGenerationContext CalculateStubInformation(M { exceptionMarshallingInfo = CustomMarshallingInfoHelper.CreateNativeMarshallingInfoForNonSignatureElement( environment.Compilation.GetTypeByMetadataName(TypeNames.System_Exception), - generatedComInterfaceAttributeData.ExceptionToUnmanagedMarshaller, + (INamedTypeSymbol)generatedComInterfaceAttributeData.ExceptionToUnmanagedMarshaller, generatedComAttribute, environment.Compilation, generatorDiagnostics); diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceInfo.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceInfo.cs index 1aa502aec58a33..0e5219065c8ab5 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceInfo.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceInfo.cs @@ -305,6 +305,13 @@ private static bool ExceptionToUnmanagedMarshallerIsValid( return false; } } + else if (attrSymbolInfo.ExceptionToUnmanagedMarshaller is not null) + { + exceptionToUnmanagedMarshallerDiagnostic = DiagnosticInfo.Create( + GeneratorDiagnostics.InvalidExceptionToUnmanagedMarshallerType, + syntax.Identifier.GetLocation()); + return false; + } exceptionToUnmanagedMarshallerDiagnostic = null; return true; } diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs index 54e3a9f23976e4..a1ce98583006bf 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratedComInterfaceAttributeData.cs @@ -35,7 +35,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 ITypeSymbol? ExceptionToUnmanagedMarshaller { get; init; } public static bool TryGetGeneratedComInterfaceAttributeFromInterface(INamedTypeSymbol interfaceSymbol, [NotNullWhen(true)] out AttributeData? generatedComInterfaceAttribute) { @@ -73,13 +73,9 @@ public static GeneratedComInterfaceCompilationData GetDataFromAttribute(Attribut } if (args.TryGetValue(nameof(ExceptionToUnmanagedMarshaller), out TypedConstant exceptionToUnmanagedMarshaller)) { - if (exceptionToUnmanagedMarshaller.Value is not INamedTypeSymbol) - { - return null; - } generatedComInterfaceAttributeData = generatedComInterfaceAttributeData with { - ExceptionToUnmanagedMarshaller = (INamedTypeSymbol)exceptionToUnmanagedMarshaller.Value + ExceptionToUnmanagedMarshaller = (ITypeSymbol)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 e260ef98ec06df..bc67f140812286 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs @@ -141,6 +141,7 @@ public class Ids DiagnosticSeverity.Error, isEnabledByDefault: true); + /// public static readonly DiagnosticDescriptor ExceptionToUnmanagedMarshallerNotAccessibleByGeneratedCode = DiagnosticDescriptorHelper.Create( Ids.InvalidGeneratedComInterfaceAttributeUsage, @@ -161,6 +162,16 @@ public class Ids isEnabledByDefault: true, description: GetResourceString(nameof(SR.InvalidExceptionMarshallingConfigurationDescription))); + /// + public static readonly DiagnosticDescriptor InvalidExceptionToUnmanagedMarshallerType = + DiagnosticDescriptorHelper.Create( + Ids.InvalidGeneratedComInterfaceAttributeUsage, + GetResourceString(nameof(SR.InvalidGeneratedComInterfaceAttributeUsageTitle)), + GetResourceString(nameof(SR.InvalidExceptionToUnmanagedMarshallerType)), + Category, + DiagnosticSeverity.Error, + isEnabledByDefault: true); + /// public static readonly DiagnosticDescriptor ParameterTypeNotSupported = DiagnosticDescriptorHelper.Create( 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 83735f19bded22..5442d0fbc44186 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/Strings.resx +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/Strings.resx @@ -919,4 +919,7 @@ 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 + + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + + 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 baefd6dd66bd79..4b3586bb115263 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 @@ -617,6 +617,11 @@ Zadaná hodnota není známý příznak výčtu ExceptionMarsnuming. + + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + + Classes with 'GeneratedComClassAttribute' must implement one or more interfaces with 'GeneratedComInterfaceAttribute', be marked partial, and be non-generic. Třídy s třídou GeneratedComClassAttribute musí implementovat jedno nebo více rozhraní s „GeneratedComInterfaceAttribute“, být označeny jako částečné a musí být neobecné. 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 c14f2ce126bb82..3472b0d5396902 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 @@ -617,6 +617,11 @@ Der angegebene Wert ist kein bekanntes Flag der „ExceptionMarshalling“-Enumeration. + + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + + Classes with 'GeneratedComClassAttribute' must implement one or more interfaces with 'GeneratedComInterfaceAttribute', be marked partial, and be non-generic. Klassen mit "GeneratedComClassAttribute" müssen mindestens eine Schnittstelle mit "GeneratedComInterfaceAttribute" implementieren, als "Partiell" gekennzeichnet und nicht generisch sein. 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 52c7c6e7c2aa77..f5ab9623b53a28 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 @@ -617,6 +617,11 @@ El valor proporcionado no es una marca conocida de la enumeración “ExceptionMarshalling”. + + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + + Classes with 'GeneratedComClassAttribute' must implement one or more interfaces with 'GeneratedComInterfaceAttribute', be marked partial, and be non-generic. Las clases con "GeneratedComClassAttribute" deben implementar una o varias interfaces con "GeneratedComInterfaceAttribute", marcarse como parciales y no ser genéricas. 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 0a4ca5001abda2..cb1c0009efe375 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 @@ -617,6 +617,11 @@ La valeur fournie n’est pas un indicateur connu de l’énumération « ExceptionMarshalling ». + + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + + Classes with 'GeneratedComClassAttribute' must implement one or more interfaces with 'GeneratedComInterfaceAttribute', be marked partial, and be non-generic. Les classes avec 'GeneratedComClassAttribute' doivent implémenter une ou plusieurs interfaces avec 'GeneratedComInterfaceAttribute', être marquées comme partielles et non génériques. 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 e84ca09f0b32c5..98720b8537dcd9 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 @@ -617,6 +617,11 @@ Il valore specificato non è un flag noto dell'enumerazione 'ExceptionMarshalling'. + + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + + Classes with 'GeneratedComClassAttribute' must implement one or more interfaces with 'GeneratedComInterfaceAttribute', be marked partial, and be non-generic. Le classi con 'GeneratedComClassAttribute' devono implementare una o più interfacce con 'GeneratedComInterfaceAttribute', essere contrassegnate come parziali e non generiche. 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 4ef640080a7209..b7e353fe7ba299 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 @@ -617,6 +617,11 @@ 指定された値は、'ExceptionMarshalling' 列挙型の既知のフラグではありません。 + + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + + Classes with 'GeneratedComClassAttribute' must implement one or more interfaces with 'GeneratedComInterfaceAttribute', be marked partial, and be non-generic. 'GeneratedComClassAttribute' を持つクラスは、'GeneratedComInterfaceAttribute' を持つ 1 つ以上のインターフェイスを実装し、partial に設定し、非ジェネリックにする必要があります。 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 24405cdb59aac8..5329badd9a715a 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 @@ -617,6 +617,11 @@ 제공된 값은 'ExceptionMarshalling' 열거형의 알려진 플래그가 아닙니다. + + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + + Classes with 'GeneratedComClassAttribute' must implement one or more interfaces with 'GeneratedComInterfaceAttribute', be marked partial, and be non-generic. 'GeneratedComClassAttribute'가 있는 클래스는 'GeneratedComInterfaceAttribute'를 사용하여 인터페이스를 하나 이상 구현하고 'partial'로 표시되어야 하며 제네릭이 아니어야 합니다. 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 d253359ff888af..0863910d6cb317 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 @@ -617,6 +617,11 @@ Podana wartość nie jest znaną flagą wyliczenia „'ExceptionMarshalling”. + + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + + Classes with 'GeneratedComClassAttribute' must implement one or more interfaces with 'GeneratedComInterfaceAttribute', be marked partial, and be non-generic. Klasy z atrybutem „GeneratedComClassAttribute” muszą implementować co najmniej jeden interfejs z atrybutem „GeneratedComInterfaceAttribute”, być oznaczone jako częściowe i nie być ogólne. 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 ad2508b1e6fa8d..f68d5abae7d6b2 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 @@ -617,6 +617,11 @@ O valor fornecido não é um sinalizador conhecido da enumeração 'ExceptionMarshalling'. + + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + + Classes with 'GeneratedComClassAttribute' must implement one or more interfaces with 'GeneratedComInterfaceAttribute', be marked partial, and be non-generic. As classes com 'GeneratedComClassAttribute' devem implementar uma ou mais interfaces com 'GeneratedComInterfaceAttribute', ser marcadas como parciais e não genéricas. 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 790c09bac83a32..b1784abd31e822 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 @@ -617,6 +617,11 @@ Указанное значение не является известным флагом перечисления ExceptionMarshalling. + + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + + Classes with 'GeneratedComClassAttribute' must implement one or more interfaces with 'GeneratedComInterfaceAttribute', be marked partial, and be non-generic. Классы с "GeneratedComClassAttribute" должны реализовывать один или несколько интерфейсов с "GeneratedComInterfaceAttribute", помечаться как частичные и быть неуниверсальными. 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 b7a6c35d02677a..b2661c17dc5b2f 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 @@ -617,6 +617,11 @@ Sağlanan değer bilinen bir 'ExceptionMarshalling' sabit listesi bayrağı değil. + + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + + Classes with 'GeneratedComClassAttribute' must implement one or more interfaces with 'GeneratedComInterfaceAttribute', be marked partial, and be non-generic. 'GeneratedComClassAttribute' içeren sınıflar 'GeneratedComInterfaceAttribute' ile bir veya daha fazla arabirim uygulamalı, kısmi olarak işaretlenmeli ve genel olmayan olmalıdır. 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 7dd28559a7dccc..e8c4cee80ad412 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 @@ -617,6 +617,11 @@ 提供的值不是 “ExceptionMarshalling” 枚举的已知标志。 + + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + + Classes with 'GeneratedComClassAttribute' must implement one or more interfaces with 'GeneratedComInterfaceAttribute', be marked partial, and be non-generic. 具有“GeneratedComClassAttribute”的类必须执行一个或多个具有“GeneratedComInterfaceAttribute”的接口,并标记为部分和非泛型。 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 f422c201a2a497..732a272a6771be 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 @@ -617,6 +617,11 @@ 提供的值不是 'ExceptionMarshalling' 列舉的已知旗標。 + + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type. + + Classes with 'GeneratedComClassAttribute' must implement one or more interfaces with 'GeneratedComInterfaceAttribute', be marked partial, and be non-generic. 具有 'GeneratedComClassAttribute' 的類別必須實作一或多個具有 'GeneratedComInterfaceAttribute' 的介面、標示為部份且非泛型。 diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs index d7acb49fd7d819..a79cc33bf9ecde 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs @@ -866,5 +866,26 @@ public async Task ByRefInVariant_ReportsNotRecommendedDiagnostic() test.DisabledDiagnostics.Remove(GeneratorDiagnostics.Ids.NotRecommendedGeneratedComInterfaceUsage); await test.RunAsync(); } + + [Fact] + public async Task VerifyInvalidExceptionToUnmanagedMarshallerTypeDiagnostic() + { + string code = $$""" + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + public class Marshaller + { } + + [GeneratedComInterface(ExceptionToUnmanagedMarshaller = typeof(string[])] + [Guid("9D3FD745-3C90-4C10-B140-FAFB01E3541D")] + public partial interface {|#0:I|} + { + void Method(); + } + """; + + await VerifyComInterfaceGenerator.VerifySourceGeneratorAsync(code, new DiagnosticResult(GeneratorDiagnostics.InvalidExceptionToUnmanagedMarshallerType).WithLocation(0)); + } } } From f2cba7fb90d7637134c6d9579ed73889e0bccb21 Mon Sep 17 00:00:00 2001 From: Dongle <29563098+dongle-the-gadget@users.noreply.github.com> Date: Fri, 9 May 2025 23:09:38 +0700 Subject: [PATCH 09/13] Fix exception marshalling test. --- .../tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs index a79cc33bf9ecde..3e959e4d2ac744 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs @@ -873,11 +873,8 @@ public async Task VerifyInvalidExceptionToUnmanagedMarshallerTypeDiagnostic() string code = $$""" using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; - - public class Marshaller - { } - [GeneratedComInterface(ExceptionToUnmanagedMarshaller = typeof(string[])] + [GeneratedComInterface(ExceptionToUnmanagedMarshaller = typeof(string[]))] [Guid("9D3FD745-3C90-4C10-B140-FAFB01E3541D")] public partial interface {|#0:I|} { From 3839064bcf6a244598ba52f6c765c544d2649f77 Mon Sep 17 00:00:00 2001 From: Dongle <29563098+dongle-the-gadget@users.noreply.github.com> Date: Sat, 10 May 2025 01:09:35 +0700 Subject: [PATCH 10/13] Flip exception marshaller cases This is to match the common scenario. Co-authored-by: Aaron Robinson --- .../gen/ComInterfaceGenerator/ComInterfaceGenerator.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs index 19093263e3f761..45fc359bf6b5f0 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs @@ -391,7 +391,11 @@ private static IncrementalMethodStubGenerationContext CalculateStubInformation(M MarshallingInfo exceptionMarshallingInfo; - if (generatedComInterfaceAttributeData.ExceptionToUnmanagedMarshaller is not null) + if (generatedComInterfaceAttributeData.ExceptionToUnmanagedMarshaller is null) + { + exceptionMarshallingInfo = new ComExceptionMarshalling(); + } + else { exceptionMarshallingInfo = CustomMarshallingInfoHelper.CreateNativeMarshallingInfoForNonSignatureElement( environment.Compilation.GetTypeByMetadataName(TypeNames.System_Exception), @@ -400,10 +404,6 @@ private static IncrementalMethodStubGenerationContext CalculateStubInformation(M environment.Compilation, generatorDiagnostics); } - else - { - exceptionMarshallingInfo = new ComExceptionMarshalling(); - } return new IncrementalMethodStubGenerationContext( signatureContext, From 9d489674465c53fd8be4699e44612112e24d5acb Mon Sep 17 00:00:00 2001 From: Dongle <29563098+dongle-the-gadget@users.noreply.github.com> Date: Sat, 10 May 2025 01:30:03 +0700 Subject: [PATCH 11/13] Add custom exception marshaller test. --- .../ExceptionToUnmanagedMarshallerTests.cs | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/ExceptionToUnmanagedMarshallerTests.cs diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/ExceptionToUnmanagedMarshallerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/ExceptionToUnmanagedMarshallerTests.cs new file mode 100644 index 00000000000000..830f95367815e7 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/ExceptionToUnmanagedMarshallerTests.cs @@ -0,0 +1,50 @@ +// 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.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using Xunit; + +namespace ComInterfaceGenerator.Tests +{ + public unsafe partial class ExceptionToUnmanagedMarshallerTests + { + [CustomMarshaller(typeof(Exception), MarshalMode.UnmanagedToManagedOut, typeof(CustomExceptionAsHResultMarshaller))] + public static class CustomExceptionAsHResultMarshaller + { + public static int LastException { get; private set; } + + public static int ConvertToUnmanaged(Exception e) + { + return LastException = ExceptionAsHResultMarshaller.ConvertToUnmanaged(e); + } + } + + [GeneratedComInterface(ExceptionToUnmanagedMarshaller = typeof(CustomExceptionAsHResultMarshaller))] + [Guid("90F3657D-23B7-44C4-85DD-80BD1F5266E7")] + public partial interface ICustomExceptionMarshallerComInterface + { + void ThrowException(); + } + + [GeneratedComClass] + public partial class CustomExceptionMarshallerComClass : ICustomExceptionMarshallerComInterface + { + public void ThrowException() => throw new NotImplementedException(); + } + + [Fact] + public void TestCustomMarshaller() + { + CustomExceptionMarshallerComClass comObject = new(); + StrategyBasedComWrappers wrappers = new(); + nint nativeUnknown = wrappers.GetOrCreateComInterfaceForObject(comObject, CreateComInterfaceFlags.None); + Marshal.QueryInterface(nativeUnknown, typeof(ICustomExceptionMarshallerComInterface).GUID, out nint nativeInterface); + ((delegate* unmanaged[MemberFunction])(*(void***)nativeInterface)[3])(nativeUnknown); + Assert.Equal(unchecked((int)0x80004001), CustomExceptionAsHResultMarshaller.LastException); + Marshal.Release(nativeInterface); + Marshal.Release(nativeUnknown); + } + } +} From 3ce9c2a91c824a3eb6f1fd12b627c34f174452d5 Mon Sep 17 00:00:00 2001 From: Dongle <29563098+dongle-the-gadget@users.noreply.github.com> Date: Sat, 10 May 2025 11:38:59 +0700 Subject: [PATCH 12/13] Update exception marshaller to check for return value --- .../ExceptionToUnmanagedMarshallerTests.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/ExceptionToUnmanagedMarshallerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/ExceptionToUnmanagedMarshallerTests.cs index 830f95367815e7..23cf970ac3af99 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/ExceptionToUnmanagedMarshallerTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/ExceptionToUnmanagedMarshallerTests.cs @@ -35,14 +35,18 @@ public partial class CustomExceptionMarshallerComClass : ICustomExceptionMarshal } [Fact] - public void TestCustomMarshaller() + public void TestCustomExceptionMarshaller() { CustomExceptionMarshallerComClass comObject = new(); StrategyBasedComWrappers wrappers = new(); nint nativeUnknown = wrappers.GetOrCreateComInterfaceForObject(comObject, CreateComInterfaceFlags.None); Marshal.QueryInterface(nativeUnknown, typeof(ICustomExceptionMarshallerComInterface).GUID, out nint nativeInterface); - ((delegate* unmanaged[MemberFunction])(*(void***)nativeInterface)[3])(nativeUnknown); - Assert.Equal(unchecked((int)0x80004001), CustomExceptionAsHResultMarshaller.LastException); + + const int E_NOTIMPL = unchecked((int)0x80004001); + int resultCode = ((delegate* unmanaged[MemberFunction])(*(void***)nativeInterface)[3])(nativeUnknown); + Assert.Equal(E_NOTIMPL, resultCode); + Assert.Equal(E_NOTIMPL, CustomExceptionAsHResultMarshaller.LastException); + Marshal.Release(nativeInterface); Marshal.Release(nativeUnknown); } From ae0d0d844a4c7bd2a0f8754b17e844b619d8871c Mon Sep 17 00:00:00 2001 From: Dongle <29563098+dongle-the-gadget@users.noreply.github.com> Date: Wed, 14 May 2025 10:46:13 +0700 Subject: [PATCH 13/13] Create RCW in exception marshaller test. --- .../ExceptionToUnmanagedMarshallerTests.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/ExceptionToUnmanagedMarshallerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/ExceptionToUnmanagedMarshallerTests.cs index 23cf970ac3af99..c2032b2c875f8a 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/ExceptionToUnmanagedMarshallerTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/ExceptionToUnmanagedMarshallerTests.cs @@ -40,15 +40,13 @@ public void TestCustomExceptionMarshaller() CustomExceptionMarshallerComClass comObject = new(); StrategyBasedComWrappers wrappers = new(); nint nativeUnknown = wrappers.GetOrCreateComInterfaceForObject(comObject, CreateComInterfaceFlags.None); - Marshal.QueryInterface(nativeUnknown, typeof(ICustomExceptionMarshallerComInterface).GUID, out nint nativeInterface); + + ICustomExceptionMarshallerComInterface rcw = (ICustomExceptionMarshallerComInterface)wrappers.GetOrCreateObjectForComInstance(nativeUnknown, CreateObjectFlags.None); + Marshal.Release(nativeUnknown); const int E_NOTIMPL = unchecked((int)0x80004001); - int resultCode = ((delegate* unmanaged[MemberFunction])(*(void***)nativeInterface)[3])(nativeUnknown); - Assert.Equal(E_NOTIMPL, resultCode); + Assert.Throws(rcw.ThrowException); Assert.Equal(E_NOTIMPL, CustomExceptionAsHResultMarshaller.LastException); - - Marshal.Release(nativeInterface); - Marshal.Release(nativeUnknown); } } }