Skip to content

Add custom exception handlers to generated COM wrappers #114828

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
May 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -389,14 +389,30 @@ private static IncrementalMethodStubGenerationContext CalculateStubInformation(M

var virtualMethodIndexData = new VirtualMethodIndexData(index, ImplicitThisParameter: true, direction, true, ExceptionMarshalling.Com);

MarshallingInfo exceptionMarshallingInfo;

if (generatedComInterfaceAttributeData.ExceptionToUnmanagedMarshaller is null)
{
exceptionMarshallingInfo = new ComExceptionMarshalling();
}
else
{
exceptionMarshallingInfo = CustomMarshallingInfoHelper.CreateNativeMarshallingInfoForNonSignatureElement(
environment.Compilation.GetTypeByMetadataName(TypeNames.System_Exception),
(INamedTypeSymbol)generatedComInterfaceAttributeData.ExceptionToUnmanagedMarshaller,
generatedComAttribute,
environment.Compilation,
generatorDiagnostics);
}

return new IncrementalMethodStubGenerationContext(
signatureContext,
containingSyntaxContext,
methodSyntaxTemplate,
locations,
callConv.ToSequenceEqualImmutableArray(SyntaxEquivalentComparer.Instance),
virtualMethodIndexData,
new ComExceptionMarshalling(),
exceptionMarshallingInfo,
environment.EnvironmentFlags,
owningInterface,
declaringType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,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 DiagnosticInfo? exceptionToUnmanagedMarshallerDiagnostic))
return DiagnosticOrInterfaceInfo.From(exceptionToUnmanagedMarshallerDiagnostic);

InterfaceInfo info = (
new ComInterfaceInfo(
ManagedTypeInfo.CreateTypeInfoForTypeSymbol(symbol),
Expand Down Expand Up @@ -285,6 +288,34 @@ private static bool OptionsAreValid(
return true;
}

private static bool ExceptionToUnmanagedMarshallerIsValid(
InterfaceDeclarationSyntax syntax,
GeneratedComInterfaceCompilationData attrSymbolInfo,
[NotNullWhen(false)] out DiagnosticInfo? exceptionToUnmanagedMarshallerDiagnostic)
{
if (attrSymbolInfo.ExceptionToUnmanagedMarshaller is INamedTypeSymbol exceptionToUnmanagedMarshallerType)
{
if (!exceptionToUnmanagedMarshallerType.IsAccessibleFromFileScopedClass(out var details))
{
exceptionToUnmanagedMarshallerDiagnostic = DiagnosticInfo.Create(
GeneratorDiagnostics.ExceptionToUnmanagedMarshallerNotAccessibleByGeneratedCode,
syntax.Identifier.GetLocation(),
exceptionToUnmanagedMarshallerType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat).Replace(TypeNames.GlobalAlias, ""),
details);
return false;
}
}
else if (attrSymbolInfo.ExceptionToUnmanagedMarshaller is not null)
{
exceptionToUnmanagedMarshallerDiagnostic = DiagnosticInfo.Create(
GeneratorDiagnostics.InvalidExceptionToUnmanagedMarshallerType,
syntax.Identifier.GetLocation());
return false;
}
exceptionToUnmanagedMarshallerDiagnostic = null;
return true;
}

/// <summary>
/// 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 <paramref name="diagnostic"/>.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public static GeneratedComInterfaceData From(GeneratedComInterfaceCompilationDat
internal sealed record GeneratedComInterfaceCompilationData : InteropAttributeCompilationData
{
public ComInterfaceOptions Options { get; init; } = ComInterfaceOptions.ManagedObjectWrapper | ComInterfaceOptions.ComObjectWrapper;
public ITypeSymbol? ExceptionToUnmanagedMarshaller { get; init; }

public static bool TryGetGeneratedComInterfaceAttributeFromInterface(INamedTypeSymbol interfaceSymbol, [NotNullWhen(true)] out AttributeData? generatedComInterfaceAttribute)
{
Expand Down Expand Up @@ -70,6 +71,13 @@ public static GeneratedComInterfaceCompilationData GetDataFromAttribute(Attribut
Options = (ComInterfaceOptions)options.Value
};
}
if (args.TryGetValue(nameof(ExceptionToUnmanagedMarshaller), out TypedConstant exceptionToUnmanagedMarshaller))
{
generatedComInterfaceAttributeData = generatedComInterfaceAttributeData with
{
ExceptionToUnmanagedMarshaller = (ITypeSymbol)exceptionToUnmanagedMarshaller.Value
};
}
return generatedComInterfaceAttributeData;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,16 @@ public class Ids
DiagnosticSeverity.Error,
isEnabledByDefault: true);

/// <inheritdoc cref="SR.ExceptionToUnmanagedMarshallerNotAccessibleByGeneratedCode"/>
public static readonly DiagnosticDescriptor ExceptionToUnmanagedMarshallerNotAccessibleByGeneratedCode =
DiagnosticDescriptorHelper.Create(
Ids.InvalidGeneratedComInterfaceAttributeUsage,
GetResourceString(nameof(SR.InvalidGeneratedComInterfaceAttributeUsageTitle)),
GetResourceString(nameof(SR.ExceptionToUnmanagedMarshallerNotAccessibleByGeneratedCode)),
Category,
DiagnosticSeverity.Error,
isEnabledByDefault: true);

/// <inheritdoc cref="SR.InvalidExceptionMarshallingConfigurationMessage"/>
public static readonly DiagnosticDescriptor InvalidExceptionMarshallingConfiguration =
DiagnosticDescriptorHelper.Create(
Expand All @@ -152,6 +162,16 @@ public class Ids
isEnabledByDefault: true,
description: GetResourceString(nameof(SR.InvalidExceptionMarshallingConfigurationDescription)));

/// <inheritdoc cref="SR.InvalidExceptionToUnmanagedMarshallerType"/>
public static readonly DiagnosticDescriptor InvalidExceptionToUnmanagedMarshallerType =
DiagnosticDescriptorHelper.Create(
Ids.InvalidGeneratedComInterfaceAttributeUsage,
GetResourceString(nameof(SR.InvalidGeneratedComInterfaceAttributeUsageTitle)),
GetResourceString(nameof(SR.InvalidExceptionToUnmanagedMarshallerType)),
Category,
DiagnosticSeverity.Error,
isEnabledByDefault: true);

/// <inheritdoc cref="SR.TypeNotSupportedMessageParameterCom"/>
public static readonly DiagnosticDescriptor ParameterTypeNotSupported =
DiagnosticDescriptorHelper.Create(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -916,7 +916,13 @@
<data name="BaseInterfaceDefinedInOtherAssemblyTitle" xml:space="preserve">
<value>Specifying 'GeneratedComInterfaceAttribute' on an interface that has a base interface defined in another assembly is not supported</value>
</data>
<data name="ExceptionToUnmanagedMarshallerNotAccessibleByGeneratedCode" xml:space="preserve">
<value>The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1}</value>
</data>
<data name="InvalidExceptionToUnmanagedMarshallerType" xml:space="preserve">
<value>The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type.</value>
</data>
<data name="GenericDelegatesNotSupported" xml:space="preserve">
<value>Marshalling a generic delegate is not supported. Consider using a function pointer instead.</value>
</data>
</root>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,11 @@
<target state="translated">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.</target>
<note />
</trans-unit>
<trans-unit id="ExceptionToUnmanagedMarshallerNotAccessibleByGeneratedCode">
<source>The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1}</source>
<target state="new">The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1}</target>
<note />
</trans-unit>
<trans-unit id="ExtraneousMarshallingInfo">
<source>Marshalling info was specified for 'ElementIndirectionDepth' {0}, but marshalling info was only needed for {1} level(s) of indirection</source>
<target state="translated">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.</target>
Expand Down Expand Up @@ -617,6 +622,11 @@
<target state="translated">Zadaná hodnota není známý příznak výčtu ExceptionMarsnuming.</target>
<note />
</trans-unit>
<trans-unit id="InvalidExceptionToUnmanagedMarshallerType">
<source>The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type.</source>
<target state="new">The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type.</target>
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComClassAttributeUsageDescription">
<source>Classes with 'GeneratedComClassAttribute' must implement one or more interfaces with 'GeneratedComInterfaceAttribute', be marked partial, and be non-generic.</source>
<target state="translated">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é.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,11 @@
<target state="translated">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</target>
<note />
</trans-unit>
<trans-unit id="ExceptionToUnmanagedMarshallerNotAccessibleByGeneratedCode">
<source>The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1}</source>
<target state="new">The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1}</target>
<note />
</trans-unit>
<trans-unit id="ExtraneousMarshallingInfo">
<source>Marshalling info was specified for 'ElementIndirectionDepth' {0}, but marshalling info was only needed for {1} level(s) of indirection</source>
<target state="translated">Marshallinginformationen wurden für \"ElementIndirectionDepth\" {0}angegeben. Marshallinginformationen wurden jedoch nur für {1} Dereferenzierungsebene(n) benötigt.</target>
Expand Down Expand Up @@ -617,6 +622,11 @@
<target state="translated">Der angegebene Wert ist kein bekanntes Flag der „ExceptionMarshalling“-Enumeration.</target>
<note />
</trans-unit>
<trans-unit id="InvalidExceptionToUnmanagedMarshallerType">
<source>The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type.</source>
<target state="new">The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type.</target>
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComClassAttributeUsageDescription">
<source>Classes with 'GeneratedComClassAttribute' must implement one or more interfaces with 'GeneratedComInterfaceAttribute', be marked partial, and be non-generic.</source>
<target state="translated">Klassen mit "GeneratedComClassAttribute" müssen mindestens eine Schnittstelle mit "GeneratedComInterfaceAttribute" implementieren, als "Partiell" gekennzeichnet und nicht generisch sein.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,11 @@
<target state="translated">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</target>
<note />
</trans-unit>
<trans-unit id="ExceptionToUnmanagedMarshallerNotAccessibleByGeneratedCode">
<source>The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1}</source>
<target state="new">The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1}</target>
<note />
</trans-unit>
<trans-unit id="ExtraneousMarshallingInfo">
<source>Marshalling info was specified for 'ElementIndirectionDepth' {0}, but marshalling info was only needed for {1} level(s) of indirection</source>
<target state="translated">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</target>
Expand Down Expand Up @@ -617,6 +622,11 @@
<target state="translated">El valor proporcionado no es una marca conocida de la enumeración “ExceptionMarshalling”.</target>
<note />
</trans-unit>
<trans-unit id="InvalidExceptionToUnmanagedMarshallerType">
<source>The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type.</source>
<target state="new">The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type.</target>
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComClassAttributeUsageDescription">
<source>Classes with 'GeneratedComClassAttribute' must implement one or more interfaces with 'GeneratedComInterfaceAttribute', be marked partial, and be non-generic.</source>
<target state="translated">Las clases con "GeneratedComClassAttribute" deben implementar una o varias interfaces con "GeneratedComInterfaceAttribute", marcarse como parciales y no ser genéricas.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,11 @@
<target state="translated">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é</target>
<note />
</trans-unit>
<trans-unit id="ExceptionToUnmanagedMarshallerNotAccessibleByGeneratedCode">
<source>The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1}</source>
<target state="new">The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1}</target>
<note />
</trans-unit>
<trans-unit id="ExtraneousMarshallingInfo">
<source>Marshalling info was specified for 'ElementIndirectionDepth' {0}, but marshalling info was only needed for {1} level(s) of indirection</source>
<target state="translated">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</target>
Expand Down Expand Up @@ -617,6 +622,11 @@
<target state="translated">La valeur fournie n’est pas un indicateur connu de l’énumération « ExceptionMarshalling ».</target>
<note />
</trans-unit>
<trans-unit id="InvalidExceptionToUnmanagedMarshallerType">
<source>The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type.</source>
<target state="new">The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type.</target>
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComClassAttributeUsageDescription">
<source>Classes with 'GeneratedComClassAttribute' must implement one or more interfaces with 'GeneratedComInterfaceAttribute', be marked partial, and be non-generic.</source>
<target state="translated">Les classes avec 'GeneratedComClassAttribute' doivent implémenter une ou plusieurs interfaces avec 'GeneratedComInterfaceAttribute', être marquées comme partielles et non génériques.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,11 @@
<target state="translated">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</target>
<note />
</trans-unit>
<trans-unit id="ExceptionToUnmanagedMarshallerNotAccessibleByGeneratedCode">
<source>The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1}</source>
<target state="new">The type '{0}' specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not accessible by generated code. The type must have at least 'internal' accessibility. {1}</target>
<note />
</trans-unit>
<trans-unit id="ExtraneousMarshallingInfo">
<source>Marshalling info was specified for 'ElementIndirectionDepth' {0}, but marshalling info was only needed for {1} level(s) of indirection</source>
<target state="translated">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</target>
Expand Down Expand Up @@ -617,6 +622,11 @@
<target state="translated">Il valore specificato non è un flag noto dell'enumerazione 'ExceptionMarshalling'.</target>
<note />
</trans-unit>
<trans-unit id="InvalidExceptionToUnmanagedMarshallerType">
<source>The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type.</source>
<target state="new">The type specified as 'GeneratedComInterfaceAttribute.ExceptionToUnmanagedMarshaller' is not a valid marshaller type.</target>
<note />
</trans-unit>
<trans-unit id="InvalidGeneratedComClassAttributeUsageDescription">
<source>Classes with 'GeneratedComClassAttribute' must implement one or more interfaces with 'GeneratedComInterfaceAttribute', be marked partial, and be non-generic.</source>
<target state="translated">Le classi con 'GeneratedComClassAttribute' devono implementare una o più interfacce con 'GeneratedComInterfaceAttribute', essere contrassegnate come parziali e non generiche.</target>
Expand Down
Loading
Loading