Skip to content
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

Stop preserving interfaces from MarshalInspectable<T> #1452

Merged
merged 5 commits into from
Jan 26, 2024
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
3 changes: 2 additions & 1 deletion src/WinRT.Runtime/ApiCompatBaseline.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ CannotRemoveAttribute : Attribute 'System.Diagnostics.CodeAnalysis.DynamicallyAc
CannotMakeMemberNonVirtual : Member 'public System.Int32 WinRT.IObjectReference.TryAs<T>(System.Guid, WinRT.ObjectReference<T>)' is non-virtual in the implementation but is virtual in the contract.
MembersMustExist : Member 'protected System.Boolean System.Boolean WinRT.IObjectReference.disposed' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'protected void WinRT.IObjectReference.Dispose(System.Boolean)' does not exist in the implementation but it does exist in the contract.
Total Issues: 15
CannotChangeAttribute : Attribute 'System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute' on 'ABI.System.Type.FromAbi(ABI.System.Type)' changed from '[UnconditionalSuppressMessageAttribute("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification="Any types which are trimmed are not used by managed user code and there is fallback logic to handle that.")]' in the contract to '[UnconditionalSuppressMessageAttribute("ReflectionAnalysis", "IL2057", Justification="Any types which are trimmed are not used by managed user code and there is fallback logic to handle that.")]' in the implementation.
Total Issues: 16
50 changes: 28 additions & 22 deletions src/WinRT.Runtime/ComWrappersSupport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -385,31 +385,37 @@ private static Func<IInspectable, object> CreateKeyValuePairFactory(Type type)
return createRcwFunc;
}

internal static Func<IntPtr, object> CreateDelegateFactory(Type type)
internal static Func<IntPtr, object> GetOrCreateDelegateFactory(Type type)
{
return DelegateFactoryCache.GetOrAdd(type, (type) =>
{
var createRcwFunc = (Func<IntPtr, object>)type.GetHelperType().GetMethod("CreateRcw", BindingFlags.Public | BindingFlags.Static).
CreateDelegate(typeof(Func<IntPtr, object>));
var iid = GuidGenerator.GetIID(type);
return DelegateFactoryCache.GetOrAdd(type, CreateDelegateFactory);
}

#if NET
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067",
Justification = "The type is a delegate type, so 'GuidGenerator.GetIID' doesn't need to access public fields from it (it uses the helper type).")]
#endif
private static Func<IntPtr, object> CreateDelegateFactory(Type type)
{
var createRcwFunc = (Func<IntPtr, object>)type.GetHelperType().GetMethod("CreateRcw", BindingFlags.Public | BindingFlags.Static).
CreateDelegate(typeof(Func<IntPtr, object>));
var iid = GuidGenerator.GetIID(type);

return (IntPtr externalComObject) =>
return (IntPtr externalComObject) =>
{
// The CreateRCW function for delegates expect the pointer to be the delegate interface in CsWinRT 1.5.
// But CreateObject is passed the IUnknown interface. This would typically be fine for delegates as delegates
// don't implement interfaces and implementations typically have both the IUnknown vtable and the delegate
// vtable point to the same vtable. But when the pointer is to a proxy, that can not be relied on.
Marshal.ThrowExceptionForHR(Marshal.QueryInterface(externalComObject, ref iid, out var ptr));
try
{
// The CreateRCW function for delegates expect the pointer to be the delegate interface in CsWinRT 1.5.
// But CreateObject is passed the IUnknown interface. This would typically be fine for delegates as delegates
// don't implement interfaces and implementations typically have both the IUnknown vtable and the delegate
// vtable point to the same vtable. But when the pointer is to a proxy, that can not be relied on.
Marshal.ThrowExceptionForHR(Marshal.QueryInterface(externalComObject, ref iid, out var ptr));
try
{
return createRcwFunc(ptr);
}
finally
{
Marshal.Release(ptr);
}
};
});
return createRcwFunc(ptr);
}
finally
{
Marshal.Release(ptr);
}
};
}

public static bool RegisterDelegateFactory(Type implementationType, Func<IntPtr, object> delegateFactory) => DelegateFactoryCache.TryAdd(implementationType, delegateFactory);
Expand Down
5 changes: 1 addition & 4 deletions src/WinRT.Runtime/ComWrappersSupport.net5.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,6 @@ internal static IntPtr CreateCCWForObjectForABI(object obj, Guid iid)
public static unsafe T FindObject<T>(IntPtr ptr)
where T : class => ComInterfaceDispatch.GetInstance<T>((ComInterfaceDispatch*)ptr);

private static T FindDelegate<T>(IntPtr thisPtr)
where T : class, System.Delegate => FindObject<T>(thisPtr);

public static IUnknownVftbl IUnknownVftbl => DefaultComWrappers.IUnknownVftbl;
public static IntPtr IUnknownVftblPtr => DefaultComWrappers.IUnknownVftblPtr;

Expand Down Expand Up @@ -537,7 +534,7 @@ private static object CreateObject(IntPtr externalComObject)
{
if (ComWrappersSupport.CreateRCWType != null && ComWrappersSupport.CreateRCWType.IsDelegate())
{
return ComWrappersSupport.CreateDelegateFactory(ComWrappersSupport.CreateRCWType)(externalComObject);
return ComWrappersSupport.GetOrCreateDelegateFactory(ComWrappersSupport.CreateRCWType)(externalComObject);
}
else if (Marshal.QueryInterface(externalComObject, ref inspectableIID, out ptr) == 0)
{
Expand Down
2 changes: 1 addition & 1 deletion src/WinRT.Runtime/ComWrappersSupport.netstandard2.0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ private static T CreateRcwForComObject<T>(IntPtr ptr, bool tryUseCache)
object runtimeWrapper = null;
if (typeof(T).IsDelegate())
{
runtimeWrapper = CreateDelegateFactory(typeof(T))(ptr);
runtimeWrapper = GetOrCreateDelegateFactory(typeof(T))(ptr);
}
else if (identity.TryAs<IInspectable.Vftbl>(out var inspectableRef) == 0)
{
Expand Down
25 changes: 15 additions & 10 deletions src/WinRT.Runtime/Marshalers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1499,14 +1499,16 @@ private static Func<T, IObjectReference> BindCreateMarshaler()
public
#endif
static class MarshalInspectable<
#if NET6_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
#elif NET
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
#if NET
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors)]
#endif
T>
{
public static IObjectReference CreateMarshaler<V>(
public static IObjectReference CreateMarshaler<
#if NET
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors)]
#endif
V>(
T o,
Guid iid,
bool unwrapObject = true)
Expand Down Expand Up @@ -1687,21 +1689,24 @@ public static ObjectReferenceValue CreateMarshaler2(object o, Guid delegateIID,
return ComWrappersSupport.CreateCCWForObjectForMarshaling(o, delegateIID);
}

#if NET
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2091",
Justification = "Preserving constructors is not necessary when creating RCWs for delegates, as they go through the factory methods in the helper types.")]
#endif
public static T FromAbi<T>(IntPtr nativeDelegate)
where T : Delegate
{
if (nativeDelegate == IntPtr.Zero)
{
return null;
}
else if (IUnknownVftbl.IsReferenceToManagedObject(nativeDelegate))

if (IUnknownVftbl.IsReferenceToManagedObject(nativeDelegate))
{
return ComWrappersSupport.FindObject<T>(nativeDelegate);
}
else
{
return ComWrappersSupport.CreateRcwForComObject<T>(nativeDelegate);
}

return ComWrappersSupport.CreateRcwForComObject<T>(nativeDelegate);
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,6 @@ MembersMustExist : Member 'public WinRT.ObjectReference<T> WinRT.ObjectReference
MembersMustExist : Member 'public WinRT.ObjectReference<T> WinRT.ObjectReference<T>.FromAbi(System.IntPtr, System.Guid)' does not exist in the reference but it does exist in the implementation.
MembersMustExist : Member 'public WinRT.ObjectReference<T> WinRT.ObjectReference<T>.FromAbi(System.IntPtr, T, System.Guid)' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'WinRT.ActivationFactory' does not exist in the reference but it does exist in the implementation.
Total Issues: 138
CannotChangeAttribute : Attribute 'System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute' on 'ABI.System.Type.FromAbi(ABI.System.Type)' changed from '[UnconditionalSuppressMessageAttribute("ReflectionAnalysis", "IL2057", Justification="Any types which are trimmed are not used by managed user code and there is fallback logic to handle that.")]' in the implementation to '[UnconditionalSuppressMessageAttribute("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification="Any types which are trimmed are not used by managed user code and there is fallback logic to handle that.")]' in the reference.
CannotRemoveAttribute : Attribute 'System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute' exists on 'WinRT.MarshalDelegate.FromAbi<T>(System.IntPtr)' in the implementation but not the reference.
Total Issues: 140
2 changes: 1 addition & 1 deletion src/WinRT.Runtime/Projections/Type.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public static Type GetAbi(Marshaler m)
}

#if NET
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2057",
Justification = "Any types which are trimmed are not used by managed user code and there is fallback logic to handle that.")]
#endif
public static global::System.Type FromAbi(Type value)
Expand Down
Loading