microsoft / CsWinRT

C# language projection for the Windows Runtime
MIT License
555 stars 107 forks source link

Marshalling `IEnumerable<T>` in modern UWP fails #1839

Open devsko opened 1 month ago

devsko commented 1 month ago

Describe the bug Calling WinRT with parameters of type IEnumerable<T> in modern UWP fails with various exceptions depending on T and parameter type.

To Reproduce

  1. Create a new .NET 9 UWP project
  2. Add <WindowsSDKPackageVersion>10.0.26100.54</WindowsSDKPackageVersion> and <AllowUnsafeBlocks>true</AllowUnsafeBlocks> to .csproj
  3. Add a Page_Loaded handler to MainPage with this code:

            new Geopath([new BasicGeoposition(0, 0, 0)]); // BasicGeoposition is a value type
            // System.InvalidCastException: Specified cast is not valid.
            //    at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32 errorCode)
            //    at WinRT.ComWrappersSupport.CreateCCWForObjectForABI(Object obj, Guid iid)
            //    at WinRT.ComWrappersSupport.CreateCCWForObjectForMarshaling(Object obj, Guid iid)
            //    at WinRT.MarshalInspectable`1.CreateMarshaler2(T o, Guid iid, Boolean unwrapObject)
            //    at WinRT.MarshalInterface`1.CreateMarshaler2(T value, Guid iid)
            //    at Windows.Devices.Geolocation.Geopath._IGeopathFactoryMethods.Create(IObjectReference _obj, IEnumerable`1 positions)
            //    at Windows.Devices.Geolocation.Geopath..ctor(IEnumerable`1 positions)
    
            new Geopath(new BasicGeoposition[] { new(0, 0, 0) });
            // System.NotSupportedException: Cannot provide IReferenceArray`1 support for element type 'Windows.Devices.Geolocation.BasicGeoposition'.
            //    at WinRT.ComWrappersSupport.ProvideIReferenceArray(Type arrayType)
            //    at WinRT.ComWrappersSupport.GetInterfaceTableEntries(Type type)
            //    at WinRT.DefaultComWrappers.<>c.<ComputeVtables>b__7_0(Type type)
            //    at System.Runtime.CompilerServices.ConditionalWeakTable`2.GetValueLocked(TKey key, CreateValueCallback createValueCallback)
            //    at System.Runtime.CompilerServices.ConditionalWeakTable`2.GetValue(TKey key, CreateValueCallback createValueCallback)
            //    at WinRT.DefaultComWrappers.ComputeVtables(Object obj, CreateComInterfaceFlags flags, Int32& count)
            //    at System.Runtime.InteropServices.ComWrappers.TryGetOrCreateComInterfaceForObjectInternal(ObjectHandleOnStack comWrappersImpl, Int64 wrapperId, ObjectHandleOnStack instance, CreateComInterfaceFlags flags, IntPtr& retValue)
            //    at System.Runtime.InteropServices.ComWrappers.TryGetOrCreateComInterfaceForObjectInternal(ComWrappers impl, Object instance, CreateComInterfaceFlags flags, IntPtr& retValue)
            //    at System.Runtime.InteropServices.ComWrappers.GetOrCreateComInterfaceForObject(Object instance, CreateComInterfaceFlags flags)
            //    at WinRT.ComWrappersSupport.CreateCCWForObjectForABI(Object obj, Guid iid)
            //    at WinRT.ComWrappersSupport.CreateCCWForObjectForMarshaling(Object obj, Guid iid)
            //    at WinRT.MarshalInspectable`1.CreateMarshaler2(T o, Guid iid, Boolean unwrapObject)
            //    at WinRT.MarshalInterface`1.CreateMarshaler2(T value, Guid iid)
            //    at Windows.Devices.Geolocation.Geopath._IGeopathFactoryMethods.Create(IObjectReference _obj, IEnumerable`1 positions)
            //    at Windows.Devices.Geolocation.Geopath..ctor(IEnumerable`1 positions)
    
            MapStyleSheet.Combine([MapStyleSheet.Aerial()]); // MapStyleSheet is a reference type
            // System.InvalidCastException: Specified cast is not valid.
            //    at WinRT.ComWrappersSupport.CreateCCWForObjectForABI(Object obj, Guid iid)
            //    at WinRT.ComWrappersSupport.CreateCCWForObjectForMarshaling(Object obj, Guid iid)
            //    at WinRT.MarshalInspectable`1.CreateMarshaler2(T o, Guid iid, Boolean unwrapObject)
            //    at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32 errorCode)
            //    at WinRT.MarshalInterface`1.CreateMarshaler2(T value, Guid iid)
            //    at ABI.Windows.UI.Xaml.Controls.Maps.IMapStyleSheetStaticsMethods.Combine(IObjectReference _obj, IEnumerable`1 styleSheets)
            //    at Windows.UI.Xaml.Controls.Maps.MapStyleSheet.Combine(IEnumerable`1 styleSheets)
    
            MapStyleSheet.Combine(new MapStyleSheet[] { MapStyleSheet.Aerial() }); 
            // works when AllowUnsafeBlocks=true, InvalidCastException otherwise

Expected behavior

No exceptions

Version Info

net9.0 rc2, Windows SDK 26100

Additional context

Creating a Geopath in WinUI3 works as expected. (MapStyleSheet is not available in WinUI3)

dongle-the-gadget commented 1 month ago

CsWinRT does not yet support collection expressions in AOT mode. As for the reference type array, it works with unsafe code because CsWinRT needs that to generate AOT shims.

The value-type-array error does look to be an oversight though. cc @manodasanW

manodasanW commented 1 month ago

We didn't initially support boxing arrays using IReferenceArray due to we couldn't make it work with non-blittable scenarios on AOT. But I am working on a change to enable it for blittable scenarios such as this one.

In the meantime, you should be able to use a list rather than an array or collection expression and it should work.

devsko commented 1 month ago

I tried new Geopath(new List<BasicGeoposition>() { new(0, 0, 0) }); which gives the exact same exception as the one with collection expression. On WinUI3 all of them work perfectly.

manodasanW commented 1 month ago

Can you confirm the version of the .NET 9 SDK you are using? And to confirm, do you have AllowUnsafeBlocks enabled?

devsko commented 1 month ago

It is 9.0.100-rc.2.24474.11 I uploaded the repro https://github.com/devsko/App10

Gaoyifei1011 commented 4 weeks ago

Image

https://github.com/microsoft/CsWinRT/issues/1846

Are the internal anomalous causes of the two issues consistent?

-------------------------------------

这俩个问题的内部异常原因是一致的吗?