Friday, September 16, 2005

Wrestling with the WindowsFormsParkingWindow

One of my colleagues showed me something interesting this week. He was using VisualStudio.NET and DevPartner Memory Analysis and ran into a problem when he followed this series of steps:

He would run his managed application under Memory Analysis and generate a session file. He would then 'Show Complete Details' on methods that allocated the most leaked memory. He would then begin looking at a particular method by selecting an interesting node in our call graph and selecting 'View leaked object allocated by this method' from the context menu. At this point, the session file would update to show him the data for that method, but Visual Studio.NET would then be completely unresponsive!

After some investigation, we discovered that this wasn't exactly the case. If you had more than one window open in VS.NET (like a source file), you could Ctrl+Tab to give one of the other editor tabs focus and VS.NET was responsive again. However, switching back to our session file caused VS.NET to ignore all keyboard and mouse input.

Firing up Spy++, we found a window named WindowsFormsParkingWindow which was hosting our Call Graph control. Since I wasn't familiar with this (and knew it wasn't one of ours), I returned to my desk to begin what I thought was going to be a long afternoon with Google.

Much to my surprise, the first result returned was a blog post entitled WindowsFormsParkingWindow, aka The devil. It described that when you remove a control from a form or pane, it doesn't really get removed, but rather placed onto an invisible window called WindowsFormsParkingWindow, where it stays until you put it back onto the form/pane.

This was the exact situation we were facing. Our Memory Analysis session file window is split horizontally into two panes. The bottom pane consists of a Windows Forms TabControl containing one of two sets of tabs depending on what type of data needs to be displayed. When we needed to switch the tab control to display the other set of tabs, we would call TabControl.TabPages.Clear(), and then add the other set of tabs to the pane. What was happening in the case described above was that the CallGraph tab had focus, since we brought up the context menu. We then removed the control while it still had focus. Because we removed the control while it still had focus, and it was still living on the WindowsFormsParkingWindow, all events fired would stop right there, explaining why VS.NET became completely unresponsive when our session file was the active window.

If this information wasn't helpful enough, the post ended off with a quick two-step solution to the problem:

  1. Remove focus from the control you are going to remove by setting it to the parent's form (I ended up having to set focus on one of our other user controls instead, which worked just as well).
  2. Remove the intended user control by using .RemoveAt( indexOfControl ).

I would like to thank the author of this post, since his concise explanation saved me a lot of time.

You may think this story is over at this point, but there's a twist: the problem described above only occurred on a French-language version of Visual Studio.NET. We were unable to get the problem to reproduce on the English version of Visual Studio.NET. Have you ever ran into this problem?

Update: Although WindowsFormsParkingWindow, aka The devil continues to be the top Google result for 'WindowsFormsParkingWindow', the blog is no longer active. I hope I captured enough of that post's detail to be useful to everyone else.

No comments: