Skip to content

Commit 700d724

Browse files
authored
Add feature switch to disable COM type descriptors (#100693)
Together with dotnet/winforms#11165, this removes some COM-related trim warnings in a winforms test app by disabling support for browsing COM objects via the TypeDescriptor APIs.
1 parent 16743ba commit 700d724

File tree

4 files changed

+42
-2
lines changed

4 files changed

+42
-2
lines changed

src/libraries/System.ComponentModel.TypeConverter/ref/System.ComponentModel.TypeConverter.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1410,9 +1410,17 @@ public sealed partial class TypeDescriptor
14101410
internal TypeDescriptor() { }
14111411
[System.Diagnostics.CodeAnalysis.DisallowNullAttribute]
14121412
[System.ObsoleteAttribute("TypeDescriptor.ComNativeDescriptorHandler has been deprecated. Use a type description provider to supply type information for COM types instead.")]
1413-
public static System.ComponentModel.IComNativeDescriptorHandler? ComNativeDescriptorHandler { get { throw null; } set { } }
1413+
public static System.ComponentModel.IComNativeDescriptorHandler? ComNativeDescriptorHandler {
1414+
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("COM type descriptors are not trim-compatible.")]
1415+
get { throw null; }
1416+
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("COM type descriptors are not trim-compatible.")]
1417+
set { }
1418+
}
14141419
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
1415-
public static System.Type ComObjectType { [return: System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] get { throw null; } }
1420+
public static System.Type ComObjectType {
1421+
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("COM type descriptors are not trim-compatible.")]
1422+
[return: System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] get { throw null; }
1423+
}
14161424
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
14171425
public static System.Type InterfaceType { [return: System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] get { throw null; } }
14181426
public static event System.ComponentModel.RefreshEventHandler? Refreshed { add { } remove { } }

src/libraries/System.ComponentModel.TypeConverter/src/ILLink/ILLink.Suppressions.LibraryBuild.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,12 @@
1515
<property name="Target">M:System.ComponentModel.Design.DesigntimeLicenseContextSerializer.DeserializeUsingBinaryFormatter(System.ComponentModel.Design.DesigntimeLicenseContextSerializer.StreamWrapper,System.String,System.ComponentModel.Design.RuntimeLicenseContext)</property>
1616
<property name="Justification">This warning is left in the product so developers get an ILLink warning when trimming an app with System.ComponentModel.TypeConverter.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization=true.</property>
1717
</attribute>
18+
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
19+
<argument>ILLink</argument>
20+
<argument>IL2026</argument>
21+
<property name="Scope">member</property>
22+
<property name="Target">M:System.ComponentModel.TypeDescriptor.NodeFor(System.Object,System.Boolean)</property>
23+
<property name="Justification">This warning is left in the product so developers get an ILLink warning when trimming an app with System.ComponentModel.TypeDescriptor.IsComObjectDescriptorSupported=true.</property>
24+
</attribute>
1825
</assembly>
1926
</linker>

src/libraries/System.ComponentModel.TypeConverter/src/Resources/Strings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@
172172
<data name="PropertyTabAttributeParamsBothNull" xml:space="preserve">
173173
<value>An array of tab type names or tab types must be specified</value>
174174
</data>
175+
<data name="ComObjectDescriptorsNotSupported" xml:space="preserve">
176+
<value>COM object type descriptor functionality has been disabled in the app configuration and is not supported.</value>
177+
</data>
175178
<data name="CultureInfoConverterDefaultCultureString" xml:space="preserve">
176179
<value>(Default)</value>
177180
</data>

src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ public sealed class TypeDescriptor
2222
internal const DynamicallyAccessedMemberTypes ReflectTypesDynamicallyAccessedMembers = DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields;
2323
internal const string DesignTimeAttributeTrimmed = "Design-time attributes are not preserved when trimming. Types referenced by attributes like EditorAttribute and DesignerAttribute may not be available after trimming.";
2424

25+
[FeatureSwitchDefinition("System.ComponentModel.TypeDescriptor.IsComObjectDescriptorSupported")]
26+
[FeatureGuard(typeof(RequiresUnreferencedCodeAttribute))]
27+
#pragma warning disable IL4000 // MSBuild logic will ensure that the switch is disabled in trimmed scenarios.
28+
internal static bool IsComObjectDescriptorSupported => AppContext.TryGetSwitch("System.ComponentModel.TypeDescriptor.IsComObjectDescriptorSupported", out bool isEnabled) ? isEnabled : true;
29+
#pragma warning restore IL4000
30+
2531
// Note: this is initialized at class load because we
2632
// lock on it for thread safety. It is used from nearly
2733
// every call to this class, so it will be created soon after
@@ -1556,11 +1562,19 @@ private static TypeDescriptionNode NodeFor(object instance, bool createDelegator
15561562

15571563
if (type.IsCOMObject)
15581564
{
1565+
if (!IsComObjectDescriptorSupported)
1566+
{
1567+
throw new NotSupportedException(SR.ComObjectDescriptorsNotSupported);
1568+
}
15591569
type = ComObjectType;
15601570
}
15611571
else if (OperatingSystem.IsWindows()
15621572
&& ComWrappers.TryGetComInstance(instance, out nint unknown))
15631573
{
1574+
if (!IsComObjectDescriptorSupported)
1575+
{
1576+
throw new NotSupportedException(SR.ComObjectDescriptorsNotSupported);
1577+
}
15641578
// ComObjectType uses the Windows Forms provided ComNativeDescriptor. It currently has hard Win32
15651579
// API dependencies. Even though ComWrappers work with other platforms, restricting to Windows until
15661580
// such time that the ComNativeDescriptor can handle basic COM types on other platforms.
@@ -2338,6 +2352,7 @@ public static void Refresh(Assembly assembly)
23382352
[EditorBrowsable(EditorBrowsableState.Advanced)]
23392353
public static Type ComObjectType
23402354
{
2355+
[RequiresUnreferencedCode("COM type descriptors are not trim-compatible.")]
23412356
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
23422357
get => typeof(TypeDescriptorComObject);
23432358
}
@@ -2385,6 +2400,7 @@ public static Type ComObjectType
23852400
[DisallowNull]
23862401
public static IComNativeDescriptorHandler? ComNativeDescriptorHandler
23872402
{
2403+
[RequiresUnreferencedCode("COM type descriptors are not trim-compatible.")]
23882404
get
23892405
{
23902406
TypeDescriptionNode? typeDescriptionNode = NodeFor(ComObjectType);
@@ -2397,6 +2413,7 @@ public static IComNativeDescriptorHandler? ComNativeDescriptorHandler
23972413
while (typeDescriptionNode != null && comNativeDescriptionProvider == null);
23982414
return comNativeDescriptionProvider?.Handler;
23992415
}
2416+
[RequiresUnreferencedCode("COM type descriptors are not trim-compatible.")]
24002417
set
24012418
{
24022419
TypeDescriptionNode? typeDescriptionNode = NodeFor(ComObjectType);
@@ -2850,6 +2867,11 @@ private sealed class ComNativeDescriptorProxy : TypeDescriptionProvider
28502867

28512868
public ComNativeDescriptorProxy()
28522869
{
2870+
if (!IsComObjectDescriptorSupported)
2871+
{
2872+
throw new NotSupportedException(SR.ComObjectDescriptorsNotSupported);
2873+
}
2874+
28532875
Type realComNativeDescriptor = Type.GetType("System.Windows.Forms.ComponentModel.Com2Interop.ComNativeDescriptor, System.Windows.Forms", throwOnError: true)!;
28542876
_comNativeDescriptor = (TypeDescriptionProvider)Activator.CreateInstance(realComNativeDescriptor)!;
28552877
}

0 commit comments

Comments
 (0)