A solution for Visual Studio XAML designer crashes in C++ Metro
Nico Vuyge
2012-08-08
40 days of Windows 8 Metro and WinRT development: Day 18.
Project status
In case you wondered what happened with day 3 to day 17, it turns out that being home 1 day a week for working on an internal project doesn't equal to having 8 hours of software development work done per week for that project. The first thing I noticed was that writing a blog with some useful and original information eats up a lot of time. So I quickly abandoned the idea to write a blog entry for every project day, and decided to only actually write something when I discovered some really interesting and original information (like today, keep reading on). In addition, I didn't realize how much of this precious time would be taken up by activities unrelated to software development. Thirdly, the app I'm writing does require a fair amount of (not sofware related) research, which turned out to also eat up a lot of the available time.
I did manage to get a fair amount of work done though. I was able to demo a prototype of my app a couple of weeks ago during an AppClinic with Microsoft Belgium. This triggered a number of changes which I am currently implementing.
Visual Studio 2012 XAML designer crashes.
The biggest technical problem until now is the instability of the Visual Studio XAML designer. For some unknown reason, the XAML designer is unable to display some of my controls. The XAML designer reports an error indicating that it is unable to create my control. Sometimes it just crashes. Now some of those errors could be traced down to my own code and I could fix them, but I was still left with a couple of situations where my controls couldn't be created at design-time.
How to debug the Visual Studio XAML designer.
So I started to debug the designer process in the hope of getting some clues of what was wrong. The process of debugging the designer brought back memories of debugging ActiveX control designer issues more than a decade ago. Since the XAML designer runs in a dedicated process in Visual Studio 2012, this is fairly easy without impacting the Visual Studio IDE. I can share a number of tips here:
-
XDesProc.exe: The XAML designer worker process is called 'XDesProc.exe' and runs under the same interactive account as the Visual Studio IDE. You should not have any problems attaching the Visual Studio debugger to this process.
-
XDesProc loads the assemblies you're developing in Visual Studio. Since C++ doesn't have the concept of an AppDomain like in C#, a rebuild triggers the creation of a new XDesProc process to host the new code. I haven't experimented with C# to verify if this is also the case with managed code, I would guess that XDesProc would unload the AppDomain instead of creating a new XDesProc process.
-
It is possible to have multipled XDesProc processes running. This appears to happen after rebuilds. A XAML designer window seems to be always linked to the same XDesProc process until the XAML designer window is reloaded. Since you can't know which XDesProc process services a particular XAML designer window, it is best to close all XAML designer windows before you attach the debugger to XDesProc. If that still leaves you with more than 1 XDesProc process, just kill all of the XDesProc processes. Visual Studio will create a new one automatically, and you should attach to that instance.
-
If you don't see an XDesProc, just click on App.XAML to trigger Visual Studio into the creation of an XDesProc process.
What is wrong with my dependency properties?
By debugging XDesProc, I found out that the Visual Studio designer throws the following kind of errors:
First-chance exception at 0x77397945 inMyApp.exe: Microsoft C++ exception:
Platform::COMException ^ at memory location 0x053FDA0C.
HRESULT:0x802B000A Unspecified error
WinRT information: The property 'Xxxx' was not found in type 'Yyy.Zzz'. [Line: 38 Position: 53]
The reported 'Line' and 'Position' always corresponds to the first character of a XAML binding expression in the XAML of a UserControl used on the control I was opening in the XAML designer for. So there was definitely something wrong with my DependencyProperties, but only in design mode. Everything worked perfectly at runtime. I spent hours and hours changing the names of my dependency properties, changing the moment and order of registration of DP's, without any consistent difference in behaviour. I found out that, when there are multiple of those exceptions, always the first Dependency Property name was reported even though a different dependency property was used in the binding expression on the indicated location, as if it was a variable that was initialized on the first occurance of the exception, and didn't get updated on the following exceptions. This definitely didn't help in keeping the amount of debugging hours low.
Since I couldn't pinpoint the root cause, I wanted to wait until the RTM becomes available before spending even more time on this problem. Maybe this was just some weird bug in the Release Preview designer. 2 days ago, after changing one of my UserControls to a templated control, practically everything started to fail in the XAML designer. I had to investigate this further. It turns out that most of the problems were solved by changing my dependency property registration. In the past, I had the following registration code:
Windows::UI::Xaml::Interop::TypeName dataType = { Y::typeid->FullName, Windows::UI::Xaml::Interop::TypeKind::Metadata };
Windows::UI::Xaml::Interop::TypeName ownerType = { T::typeid->FullName, Windows::UI::Xaml::Interop::TypeKind::Custom };
where Y and T are template parameters for the property type and the parent class type respectively (with a couple of variations for properties of base types).
By studing some of the C++ sample code (e.g. project Hilo on CodePlex), I found that 'Windows::UI::Xaml::Interop::TypeKind::Custom' is probably not the best way to register a C++ DP (although it works without problems at runtime). I changed it also to 'Windows::UI::Xaml::Interop::TypeKind::Metadata', and the designer started to show my controls again. It appears that there is even a TypeName constructor taking typeid as constructor argument, and this is what is used in the current C++ sample code I found. So I changed my code to:
Windows::UI::Xaml::Interop::TypeName dataType(Y::typeid);
Windows::UI::Xaml::Interop::TypeName ownerType(T::typeid);
I don't know how I got to use TypeKind::Custom. My code is rather old (a strange thing to say for code that will only work on a yet unavailable operating system). Some of it dates back to the Windows 8 Developer Preview, which didn't have much support for building Dependency Properties in C++. This particular code probably dates back to the first day the Windows 8 Consumer Preview became available, and I probably just used what seemed to work at that time.
Conclusion.
In addition to working much better, the XAML designer is now also much faster! I assume that using TypeKind::Metadata allows the XAML designer to use the .winmd metadata file, while using TypeKind::Custom requires the XAML designer to load the assembly, go through WinRT initalisation and create of the controls and viewmodels used in the designer. It would be logical that the .winmd code path is the most optimised because it is probably also used for managed code.
Next stop: Registration for Build 2012 in a couple of hours!