Skip to content

Commit

Permalink
Add feature switch to disable COM type descriptors (dotnet#100693)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
sbomer authored and matouskozak committed Apr 30, 2024
1 parent 2dddda9 commit 839bc48
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 { } }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,12 @@
<property name="Target">M:System.ComponentModel.Design.DesigntimeLicenseContextSerializer.DeserializeUsingBinaryFormatter(System.ComponentModel.Design.DesigntimeLicenseContextSerializer.StreamWrapper,System.String,System.ComponentModel.Design.RuntimeLicenseContext)</property>
<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>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2026</argument>
<property name="Scope">member</property>
<property name="Target">M:System.ComponentModel.TypeDescriptor.NodeFor(System.Object,System.Boolean)</property>
<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>
</attribute>
</assembly>
</linker>
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@
<data name="PropertyTabAttributeParamsBothNull" xml:space="preserve">
<value>An array of tab type names or tab types must be specified</value>
</data>
<data name="ComObjectDescriptorsNotSupported" xml:space="preserve">
<value>COM object type descriptor functionality has been disabled in the app configuration and is not supported.</value>
</data>
<data name="CultureInfoConverterDefaultCultureString" xml:space="preserve">
<value>(Default)</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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)!;
}
Expand Down

0 comments on commit 839bc48

Please sign in to comment.