WindowsAppSDK: Natvis for C++/WinRT doesn't work
Describe the bug
Natvis for C++/WinRT doesn’t work because the *.winmd files aren’t deployed alonside the process *.exe. This affects both SDK and user authored types.
Steps to reproduce the bug
- Create a solution from
Blank App, Packaged (WinUI 3 in Desktop)
template. - Set a breakpoint in
App::OnLaunched()
- Debug and pause at breakpoint.
- Try to inspect the
LaunchActivatedEventArgs
argument.
Expected behavior
The debug visualizer shows object properties based on metadata.
Screenshots
Notice the output message. To enable natvis diagnostics see documentation.
NuGet package version
1.1.3
Packaging type
Packaged (MSIX)
Windows version
Windows 11 version 21H2 (22000)
IDE
Visual Studio 2022
Additional context
A workaround is to manually copy the *.winmd files from Microsoft.WindowsAppSDK
to the executable folder.
About this issue
- Original URL
- State: open
- Created 2 years ago
- Reactions: 4
- Comments: 15 (8 by maintainers)
Update! I got a few free days and was able to get basic generics visualization up and running in a branch: https://github.com/microsoft/cppwinrt/tree/feature/generic_natvis
This required synthesizing parsing generic type names, synthesizing type signatures for those generic types, plumbing in these more fully-fledged type signatures (over the existing
coded_index<TypeDefOrRef>
design), generating a C+±friendly type name for these properties. But I’ve successfully tested it with an instance ofIKeyValuePair<int, IKeyValuePair<string, int>>
.There’s still some work to be done:
IIterator<T>
to mergeCurrent
/HasCurrent
into a single pseudo-property so we can prevent errors from callingCurrent
whenHasCurrent
isfalse
.Current
or display a placeholder “empty” string.IIterable<T>
to callFirst
as a pseudo-property (it’s a method, not a property, but it takes no params and returns a single value, just like a property), iterate the collection, and somehow display the results as children of the container.Current
/HasCurrent
trick above, the traversal is probably not much harder. But I want some advice on how to collect all of that up and somehow get the results back to the debugger, tell it how many children it has, etc. @Scottj1s who worked on the original visualizer would be hugely valuable for that effort, which is presumably where we’d hit the biggest customer value. Also sending a heads-up to @kennykerr in case he’s got any contacts that could help me light up this last bit.@Scottj1s @DefaultRyan
What strikes me as really odd about this statement is that WinUI and I assume large parts of the Windows App SDK is written in C++/WinRT, isn’t it? If Microsoft internally writes that stuff in C++/WinRT, how would the lack of ability to inspect collections in the debugger not be a daily PITA for you guys?
It’s just that I’m really having a hard time understanding why we customers need to point out the obvious need for this if you guys have more C++/WinRT code to debug than everybody else. I might be wrong here and Microsoft’s code base was authored in C++/CX. At least that would explain the hesitance of releasing it as open source.
@ackh You’re correct, we don’t want to load up the AppX folder with debugging support files like pdbs and winmds, which aren’t required at runtime. In my experiments, I don’t see any Windows App SDK winmd files being copied to the parent of the AppX folder, so I don’t think we can rely on that. Fortunately, while the diagnostics don’t indicate it, the %TEMP% folder is also searched as a cache location. So, a short-term workaround is to add a custom target that copies all the Windows App SDK metadata to the %TEMP% folder. I’ve confirmed this works with the LaunchActivatedEventArgs repro, and it doesn’t impact the AppX folder.
directory.build.targets:
Enabling diagnostics shows that nativs only searches within the
AppX
of a packaged app for customwinmd
files but not within the folder where the customwinmd
files are actually created, i.e. one folder higher.This does not make sense because, as far as I understand it, the
winmd
files should not be packaged and shipped as part of the app. They are required at compile time, not at runtime and thus should not be shipped for the same reasons thatpdb
files aren’t shipped. From that perspective, adding a post build step to copywinmd
files into theAppX
folder isn’t a solution.Therefore, it is save to say that the debugging experience for custom types is broken. Why this does not receive more attention is beyond me. Especially because it seems to be fixable by just changing the search paths for
winmd
files.@DefaultRyan I’m actually excited about what you did here! Having support for generics would be really helpful when debugging. Now I’m actively hoping that this makes it into a C++/WinRT release eventually.
@Scottj1s good callout there. C# has indexed properties, while the WinRT type system does not.
Thinking about how to solve this in the general case, my first instinct would be to add a custom attribute to some types to tell diagnostic and debug tooling to treat certain methods as quasi-“indexed properties”. Lacking that, one could special case the commonly-used types we know about:
Windows.Foundation.Collections.*
andWindows.UI.Xaml.Interop.IBindableVector
(and friends).The vector-like collections shouldn’t be too hard - Size is already a property, and we could iterate over the collection from 0 to Size-1. Map-like collections don’t provide a getter for the set of keys, so I think we’d have to use its
IIterable
to obtain anIIterator
and simply iterate over the collection. That should be fine, given that the semantics of IMap are fairly well understood. I’m not sure we’d want to provide generalized support forIIterable
because their iterators could potentially behave like a C++input_iterator
and have side effects from reading/advancing (like only being able to read a value once).@torleifat Unfortunately, debug visualization does not support generics (collections). The work to implement this is quite involved, so I can’t give any estimate if/when it will be done.