views:

311

answers:

4

I keep having this problem, solving it, and then when I implement new code it comes back again. It's driving me crazy!

What I finally found was that if you instantiate a Window of any kind, even if you never call Show() or ShowDialog(), when you close your application, it will not terminate. So now I make sure to call Close() when appropriate, and the problem hasn't ever come back with all of the Windows that I've created.

I've implemented more new features that don't create windows (as far as I can tell!), yet now my app will not terminate again. Hitting pause in the VS IDE is useless, I think, because the threads don't have any context so I can't figure out what code caused the hanging.

Normally, I would expect that a thread executing in the background that hasn't exited (and wasn't set as a Background thread) would cause this behavior, but I am not creating any threads at this point.

Can anyone recommend a good tool (free or license required) that will help me quickly resolve these sorts of stupid problems? For now, I'm going to go back, comment out a ton of the new code, and then uncomment line by line until the problem reappears. Brute force is how I typically end up fixing these sorts of things, and would really appreciate a tool to make my life easier. :)

A: 

While it may not help in your particular case, Process Explorer is an excellent tool for looking inside running processes and seeing how many threads etc. there are.

Richard J Foster
+2  A: 

You might get more information if you attached using both managed and unmanaged code. In Visual Studio 2008, you can change the mode in the Attach to Process form. Press the "Select..." button and specify debugging for both "Managed" and "Native".

(Before you do this, make sure your symbol path is setup. Go to Tools/Options, Debugging, Symbols. Enter http://msdl.microsoft.com/download/symbols in the list of symbol file locations. Cache the symbols locally in some directory.)

When you attach in both managed and unmanaged modes, you should get a larger call stack. I recommend right-clicking in the Call Stack debug window and choosing "Include Calls To/From Other Threads".

If your main thread shows System.Windows.Forms.Application.Run or ThreadContext.RunMessageLoop, then your UI thread's message pump is alive and still pumping messages. If, for some reason, it is transitioning to another thread, then it can't exit until it's done.

You can also see the full stack traces of the rest of the managed and unmanaged threads. You might want to look for a garbage collector thread and see what it's doing. Look for one that is has a stack with "GCHeap::FinalizerThreadStart" in it. That might be doing something.

There may also be a GID+ thread that's busy trying to do work.

Paul Williams
awesome, I'll try that out! thanks. Using my brute-force debugging "technique", I have determined that the freeze is occurring because of some calls to load plugins in my app. I didn't get around to isolating it to code within that function, but it's mostly Reflection code. The interesting thing is that I call the same function from elsewhere, and when that caller wasn't commented out, it didn't freeze. It didn't freeze until I implemented an interface that multiply inherits from three other interfaces.... any ideas? :)
Dave
+1  A: 

It sounds like you may be having other issues with background threads that the other answers are addressing but with regard to WPF Windows, have you tried changing the ShutdownMode of your App class? You can also try forcing the app to quit by calling Shutdown explicitly:

Application.Current.Shutdown();
John Bowen
I haven't tried the Shutdown mode (I didn't know about that!), but I'll give it a try. Thanks for the suggestion.
Dave
How do you actually set the Shutdown mode? I tried to do it but didn't know what constants to use. MSDN mentions OnMainWindowClosed, but I didn't know how to specify it. I might need to try calling Shutdown explicitly from Window_Unloaded.
Dave
ShutdownMode is a property on Application, so you can set it in App.xaml. The options are to exit when the Main window closes, exit after all windows are closed, or require an explicit call to Shutdown().
John Bowen
it turns out (I believe) that the hanging was caused by my plugin failing to load, and not handling the exception properly. It threw the exception in InitializeComponent, but rather than making the app crash, it simply silently failed. I didn't manually "toss out" the exception, because I stepped over the instantiation of the UC and the environment just popped up my main GUI without getting to the next line. This is something new to me in .NET that I never saw before in my VC++ days. I am going to revert to the previous code that froze, so I can try out your suggestion, though.
Dave
John, that did the trick! In general, I think I'll choose to not specify this property since it could mean that I've got a real problem, like the one I mentioned in my comment above. But I think it could also really come in handy some day, and it does seem to work! Very cool.
Dave
A: 

I don't mean to over-simplify things, but have you tried setting the owner of the dialog window to the MainWindow? This will force the dialog window to close when the MainWindow is closed. In other words, it would look like this:

dialog.Owner = Window.GetWindow(this);
// Or...
dialog.Owner = Application.Current.MainWindow;

This may not be an option for you, but I just wanted to throw it out there since your post didn't mention you didn't want to set the window's owner.

Brent
I might give that a shot, too, thanks! I should set the window owner anyway.
Dave