diff --git a/src/libraries/System.ComponentModel.TypeConverter/ref/System.ComponentModel.TypeConverter.cs b/src/libraries/System.ComponentModel.TypeConverter/ref/System.ComponentModel.TypeConverter.cs
index 59c3284a7fabf0..fb53eb78bfc8af 100644
--- a/src/libraries/System.ComponentModel.TypeConverter/ref/System.ComponentModel.TypeConverter.cs
+++ b/src/libraries/System.ComponentModel.TypeConverter/ref/System.ComponentModel.TypeConverter.cs
@@ -1410,9 +1410,17 @@ public sealed partial class TypeDescriptor
internal TypeDescriptor() { }
[System.Diagnostics.CodeAnalysis.DisallowNullAttribute]
[System.ObsoleteAttribute("TypeDescriptor.ComNativeDescriptorHandler has been deprecated. Use a type description provider to supply type information for COM types instead.")]
- public static System.ComponentModel.IComNativeDescriptorHandler? ComNativeDescriptorHandler { get { throw null; } set { } }
+ public static System.ComponentModel.IComNativeDescriptorHandler? ComNativeDescriptorHandler {
+ [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("COM type descriptors are not trim-compatible.")]
+ get { throw null; }
+ [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("COM type descriptors are not trim-compatible.")]
+ set { }
+ }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
- public static System.Type ComObjectType { [return: System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] get { throw null; } }
+ public static System.Type ComObjectType {
+ [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("COM type descriptors are not trim-compatible.")]
+ [return: System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] get { throw null; }
+ }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
public static System.Type InterfaceType { [return: System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] get { throw null; } }
public static event System.ComponentModel.RefreshEventHandler? Refreshed { add { } remove { } }
diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/ILLink/ILLink.Suppressions.LibraryBuild.xml b/src/libraries/System.ComponentModel.TypeConverter/src/ILLink/ILLink.Suppressions.LibraryBuild.xml
index 00f9036918d63d..aac20beb79bab5 100644
--- a/src/libraries/System.ComponentModel.TypeConverter/src/ILLink/ILLink.Suppressions.LibraryBuild.xml
+++ b/src/libraries/System.ComponentModel.TypeConverter/src/ILLink/ILLink.Suppressions.LibraryBuild.xml
@@ -15,5 +15,12 @@
M:System.ComponentModel.Design.DesigntimeLicenseContextSerializer.DeserializeUsingBinaryFormatter(System.ComponentModel.Design.DesigntimeLicenseContextSerializer.StreamWrapper,System.String,System.ComponentModel.Design.RuntimeLicenseContext)
This warning is left in the product so developers get an ILLink warning when trimming an app with System.ComponentModel.TypeConverter.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization=true.
+
+ ILLink
+ IL2026
+ member
+ M:System.ComponentModel.TypeDescriptor.NodeFor(System.Object,System.Boolean)
+ This warning is left in the product so developers get an ILLink warning when trimming an app with System.ComponentModel.TypeDescriptor.IsComObjectDescriptorSupported=true.
+
diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/Resources/Strings.resx b/src/libraries/System.ComponentModel.TypeConverter/src/Resources/Strings.resx
index b8a10ffbcd5f1b..adb104f266893c 100644
--- a/src/libraries/System.ComponentModel.TypeConverter/src/Resources/Strings.resx
+++ b/src/libraries/System.ComponentModel.TypeConverter/src/Resources/Strings.resx
@@ -172,6 +172,9 @@
An array of tab type names or tab types must be specified
+
+ COM object type descriptor functionality has been disabled in the app configuration and is not supported.
+
(Default)
diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs
index 0e5bba3b7486e4..cfe4517188bb9a 100644
--- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs
+++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs
@@ -22,6 +22,12 @@ public sealed class TypeDescriptor
internal const DynamicallyAccessedMemberTypes ReflectTypesDynamicallyAccessedMembers = DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields;
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.";
+ [FeatureSwitchDefinition("System.ComponentModel.TypeDescriptor.IsComObjectDescriptorSupported")]
+ [FeatureGuard(typeof(RequiresUnreferencedCodeAttribute))]
+#pragma warning disable IL4000 // MSBuild logic will ensure that the switch is disabled in trimmed scenarios.
+ internal static bool IsComObjectDescriptorSupported => AppContext.TryGetSwitch("System.ComponentModel.TypeDescriptor.IsComObjectDescriptorSupported", out bool isEnabled) ? isEnabled : true;
+#pragma warning restore IL4000
+
// Note: this is initialized at class load because we
// lock on it for thread safety. It is used from nearly
// every call to this class, so it will be created soon after
@@ -1556,11 +1562,19 @@ private static TypeDescriptionNode NodeFor(object instance, bool createDelegator
if (type.IsCOMObject)
{
+ if (!IsComObjectDescriptorSupported)
+ {
+ throw new NotSupportedException(SR.ComObjectDescriptorsNotSupported);
+ }
type = ComObjectType;
}
else if (OperatingSystem.IsWindows()
&& ComWrappers.TryGetComInstance(instance, out nint unknown))
{
+ if (!IsComObjectDescriptorSupported)
+ {
+ throw new NotSupportedException(SR.ComObjectDescriptorsNotSupported);
+ }
// ComObjectType uses the Windows Forms provided ComNativeDescriptor. It currently has hard Win32
// API dependencies. Even though ComWrappers work with other platforms, restricting to Windows until
// such time that the ComNativeDescriptor can handle basic COM types on other platforms.
@@ -2338,6 +2352,7 @@ public static void Refresh(Assembly assembly)
[EditorBrowsable(EditorBrowsableState.Advanced)]
public static Type ComObjectType
{
+ [RequiresUnreferencedCode("COM type descriptors are not trim-compatible.")]
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
get => typeof(TypeDescriptorComObject);
}
@@ -2385,6 +2400,7 @@ public static Type ComObjectType
[DisallowNull]
public static IComNativeDescriptorHandler? ComNativeDescriptorHandler
{
+ [RequiresUnreferencedCode("COM type descriptors are not trim-compatible.")]
get
{
TypeDescriptionNode? typeDescriptionNode = NodeFor(ComObjectType);
@@ -2397,6 +2413,7 @@ public static IComNativeDescriptorHandler? ComNativeDescriptorHandler
while (typeDescriptionNode != null && comNativeDescriptionProvider == null);
return comNativeDescriptionProvider?.Handler;
}
+ [RequiresUnreferencedCode("COM type descriptors are not trim-compatible.")]
set
{
TypeDescriptionNode? typeDescriptionNode = NodeFor(ComObjectType);
@@ -2850,6 +2867,11 @@ private sealed class ComNativeDescriptorProxy : TypeDescriptionProvider
public ComNativeDescriptorProxy()
{
+ if (!IsComObjectDescriptorSupported)
+ {
+ throw new NotSupportedException(SR.ComObjectDescriptorsNotSupported);
+ }
+
Type realComNativeDescriptor = Type.GetType("System.Windows.Forms.ComponentModel.Com2Interop.ComNativeDescriptor, System.Windows.Forms", throwOnError: true)!;
_comNativeDescriptor = (TypeDescriptionProvider)Activator.CreateInstance(realComNativeDescriptor)!;
}