CsWinRT icon indicating copy to clipboard operation
CsWinRT copied to clipboard

When publishing AOT, C#/WinRT throws System.NotSupportedException: 'Cannot retrieve a helper type for generic public type 'Windows.Foundation.IAsyncOperation`1[System.Boolean]'.'

Open smourier opened this issue 1 year ago • 7 comments
trafficstars

Description

I'm developing a WinUI3 application. When not publishing AOT, it works, but when adding <PublishAot>true</PublishAot>, it throws

System.NotSupportedException: 'Cannot retrieve a helper type for generic public type 'Windows.Foundation.IAsyncOperation`1[System.Boolean]'.'

Full stack trace:

[Exception] WinRT.Runtime.dll!WinRT.TypeExtensions.FindHelperType(System.Type type, bool throwIfNotAotSupported)	Unknown
[Exception] WinRT.Runtime.dll!WinRT.IWinRTObject.IsInterfaceImplementedFallback(System.RuntimeTypeHandle interfaceType, bool throwIfNotImplemented)	Unknown
[Exception] WinRT.Runtime.dll!WinRT.IWinRTObject.System.Runtime.InteropServices.IDynamicInterfaceCastable.IsInterfaceImplemented(System.RuntimeTypeHandle interfaceType, bool throwIfNotImplemented)	Unknown
Microsoft.Windows.SDK.NET.dll!Windows.Graphics.Printing.PrintManagerInterop.ShowPrintUIForWindowAsync(nint appWindow)	Unknown
WinUIApp.dll!WinUIApp.MainWindow.myButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e) Line 19	C#
Microsoft.WinUI.dll!WinRT._EventSource_global__Microsoft_UI_Xaml_RoutedEventHandler.EventState.GetEventInvoke.AnonymousMethod__1_0(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)	Unknown
Microsoft.WinUI.dll!ABI.Microsoft.UI.Xaml.RoutedEventHandler.Do_Abi_Invoke(nint thisPtr, nint sender, nint e)	Unknown
[Native to Managed Transition]	
[Managed to Native Transition]	
Microsoft.WinUI.dll!ABI.Microsoft.UI.Xaml.IApplicationStaticsMethods.Start(WinRT.IObjectReference _obj, Microsoft.UI.Xaml.ApplicationInitializationCallback callback)	Unknown
Microsoft.WinUI.dll!Microsoft.UI.Xaml.Application.Start(Microsoft.UI.Xaml.ApplicationInitializationCallback callback)	Unknown
WinUIApp.dll!WinUIApp.Program.Main(string[] args) Line 26	C#

Steps To Reproduce

To reproduce just create a WinUI3 blank project with latest Visual Studio 17.12.0, and modify the MainWindow.xaml.cs like this:

using System;
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Windows.Graphics.Printing;

namespace WinUIApp;

public sealed partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private async void myButton_Click(object sender, RoutedEventArgs e)
    {
        var printMananager = PrintManagerInterop.GetForWindow(Win32Interop.GetWindowFromWindowId(AppWindow.Id));
        printMananager.PrintTaskRequested += (s, e) => { };
        await PrintManagerInterop.ShowPrintUIForWindowAsync(Win32Interop.GetWindowFromWindowId(AppWindow.Id));
    }
}

With standard settings, just run and it will fail on ShowPrintUIForWindowAsync with a COM exception but that's expected.

Now change the project settings to add PublishAot, and Rebuild (you must rebuild, a simple build is usually not enough here), here is mine:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net9.0-windows10.0.19041.0</TargetFramework>
    <TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
    <RootNamespace>WinUIApp</RootNamespace>
    <ApplicationManifest>app.manifest</ApplicationManifest>
    <Platforms>x86;x64;ARM64</Platforms>
    <RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
    <PublishProfile>win-$(Platform).pubxml</PublishProfile>
    <UseWinUI>true</UseWinUI>
    <EnableMsixTooling>true</EnableMsixTooling>
    <Nullable>enable</Nullable>
    <PublishAot>true</PublishAot>
    <WindowsSdkPackageVersion>10.0.26100.57</WindowsSdkPackageVersion>
  </PropertyGroup>

  <ItemGroup>
    <Content Include="Assets\SplashScreen.scale-200.png" />
    <Content Include="Assets\LockScreenLogo.scale-200.png" />
    <Content Include="Assets\Square150x150Logo.scale-200.png" />
    <Content Include="Assets\Square44x44Logo.scale-200.png" />
    <Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
    <Content Include="Assets\StoreLogo.png" />
    <Content Include="Assets\Wide310x150Logo.scale-200.png" />
  </ItemGroup>

  <ItemGroup>
    <Manifest Include="$(ApplicationManifest)" />
  </ItemGroup>

  <ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
    <ProjectCapability Include="Msix" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.1742" />
    <PackageReference Include="Microsoft.WindowsAppSDK" Version="1.6.240923002" />
    <PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
  </ItemGroup>

  <PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
    <HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
  </PropertyGroup>

  <!-- Publish Properties -->
  <PropertyGroup>
    <PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
    <PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
    <PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed>
    <PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
  </PropertyGroup>
</Project>

I've tried .NET 8 and 9, I've also tested with an explicit latest C#/WinRT and WindowsSdkPackageVersion references but it's the same.

Expected Behavior

It should not fail with a System.NotSupportedException.

Version Info

Visual Studio 17.12.0 C#/WinRT 2.2.0 .NET 9.0.0 or .NET 8.0.11

Additional Context

I don't know of any workaround, but it would be welcome.

smourier avatar Nov 15 '24 13:11 smourier

In the meantime, the signature of this could be changed to return an IAsyncOperation<bool>, which should work with AOT mode: https://github.com/microsoft/CsWinRT/blob/d6b7e97386b54ec94dcd489bcd09bbeb75e9dbfa/src/cswinrt/WinRT.Interop.idl#L82

However, I don't think a more general solution to CsWinRT's existing usage pattern (casting from WinRT.IInspectable to a generic WinRT interface using IDynamicInterfaceCastable) would be possible without new projections).

dongle-the-gadget avatar Nov 17 '24 10:11 dongle-the-gadget

Thanks,

Not sure if I'm supposed to do anything from here

smourier avatar Nov 21 '24 18:11 smourier

Does MarshalInterface<IAsyncOperation<bool>>.FromAbi(MarshalInspectable<object>.FromManaged(printManager)); work?

dongle-the-gadget avatar Nov 21 '24 23:11 dongle-the-gadget

Does MarshalInterface<IAsyncOperation<bool>>.FromAbi(MarshalInspectable<object>.FromManaged(printManager)); work?

but the problem is on PrintManagerInterop.ShowPrintUIForWindowAsync not on printManager?

smourier avatar Nov 22 '24 07:11 smourier

Is there any news on this?

smourier avatar Apr 14 '25 16:04 smourier

Considering the focus is on CsWinRT 3.0, I'm not sure what's the priority on this. However, @Sergio0694, do you think we can accept breaking the definition in IDL, considering that consumers are generally only going to use IAsyncOperation anyways?

dongle-the-gadget avatar Apr 14 '25 16:04 dongle-the-gadget

I think we should be able to address this by calling the InitRcwHelper in our ComInteropHelpers implementation. We might also be able to share the generated one for the Windows SDK projection.

The change in the IDL might work too, but technically it relies on implementation that one of the parameters was RIID and that it should have done the QI to that interface.

manodasanW avatar Apr 15 '25 06:04 manodasanW