CsWinRT
CsWinRT copied to clipboard
KeyNotFoundException thrown by SourceGenerator for a nested public struct in an internal class and only showing as a build warning
Summary I have a WinUI3 C++/WinRT (WindowsAppSDK) app "CppHost" with most of the XAML UI implemented in a separate C# DLL "CsUiLibrary". I also have a separate C#-based test app "CsUiTestHost" that loads the same DLL to test the different parts of the UI it implements that helps speed up some prototyping. I was trying to add some functionality in CsUiLibrary the that used p/invoke into some old Win32 APIs and everything was working great in the CsUiTestHost, but at one point I started integrating the new UI into the CppHost and started hitting issues like:
Microsoft.UI.Xaml.dll!00007FFF57B03106: 80040154 - Class not registered
Unhandled exception at 0x00007FFF57D95175 (Microsoft.ui.xaml.dll) in CppHost.exe: 0xC000027B: An application-internal exception has occurred (parameters: 0x000001FB60348740, 0x0000000000000004).
After hours of adding and removing various parts of the code I noticed there was this not-seen-before warning in the output of the CsUiLibrary that didn't scream at me or break the build that only showed with the new code, which helped narrow things down a bit since I could now keep undoing or re-adding bits of code checking for which parts cause the warning to show up or disappear:
1>CSC : warning CS8785: Generator 'SourceGenerator' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type 'KeyNotFoundException' with message 'The given key was not present in the dictionary.'.
It turns out the issue triggers when I define an internal class (I use a lot of internal classes to implement things in CsUiLibrary without cryptic/hidden projection errors, but some things I need to make public anyways because XAML C++/C# compilers likes it that way) and a nested public struct inside of it. Now, marking the nested struct as internal - fixes the problem and the problem only occurs if the struct is tagged with StructLayoutAttribute.
To Reproduce Create WinUI 3 C++ Desktop app and a C# WinUI 3 Desktop Class Library. Reference the C# library from the C++ host app and add something like a UserControl in the library to display the C++ host app and F5-test to make sure it works fine at this stage. Now add below class to the C# library:
namespace Foo.Interop
{
internal static class Bar
{
[StructLayout(LayoutKind.Sequential)]
public struct Xyz
{
public int Abc;
}
}
}
This builds fine, but should show the error-as-warning KeyNotFoundException I mentioned earlier in the library build output and when you run the C++ host app now app - you get the unhandled "Class not registered" exception that crashes the app.
Expected behavior This builds and runs fine in a C# host app, so the exception from SourceGenerator shouldn't occur. I suspect there's a good reason why the WinUI class library msbuild project template hides the error without blocking the build, but maybe it's not a good enough reason or there should be an easier way to help match the runtime exception with an original error. That's likely more a WinUI problem than CsWinRT even if these things typically go in pair.
Version Info C++ host lists these imports:
<Import Project="..\packages\Microsoft.WindowsAppSDK.1.5.240404000\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\packages\Microsoft.WindowsAppSDK.1.5.240404000\build\native\Microsoft.WindowsAppSDK.props')" />
<Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.240412.1\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.240412.1\build\native\Microsoft.Windows.CppWinRT.props')" />
<Import Project="..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.3233\build\Microsoft.Windows.SDK.BuildTools.props" Condition="Exists('..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.3233\build\Microsoft.Windows.SDK.BuildTools.props')" />
C# library lists these details:
<TargetFramework>net6.0-windows10.0.22621.0</TargetFramework>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
<UseWinUI>true</UseWinUI>
<CsWinRTComponent>true</CsWinRTComponent>
Additional context
See https://github.com/microsoft/CsWinRT/issues/1202