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)!; }