debugging C# .NET after app closed

J

Jeroen

Hi,

I'm still struggling with a hard-to-reproduce scenario in my app where
we get an InvalidOperationException when closing the application. The
reason I'm posting about this again is because I'd love to hear some
suggestions on the following.

I've confirmed that the exception occurs *after* my app has finally
closed. If I set a breakpoint at the final '}' of my main method, then
go to the disassembly, and step through until *past* the final
statement (in my case "000004ef ret", whatever that may mean), only
*then* I receive the InvalidOperationException, in a VStudio debugger
screen that doesn't point to any particular user code...

My question then is: how do I debug this kind of problem??

I started to look into this using WinDbg, but that's not very user
friendly IMHO.

PS. This problem is caused by the WebBrowser control: if I exclude all
those controls in my app for a sec I won't get the exception. See also
my post here:
http://groups.google.nl/group/micro...lidOperationException+jeroen#8d8051941dd4e2c4

Any tips on how to debug this are very welcome.

Regards,
Jeroen
 
I

Ignacio Machin \( .NET/ C# MVP \)

Hi,


Do you know at least where you are getting the error at?
Use Application.ThreadException and AppDomain.UnHandleException and dump it
in a file (remember to check Exception.InnerException)
 
J

Jeroen

Do you know at least where you are getting the error at?

I wish, it just gives me a generic exception popup. I'm not sure how I
should _use_ 'ThreadException' or 'UnHandleException', could you
elaborate on that a bit?

Here's what I get from the exception screen:

/***********************************************/
/****** 'Copy exception to clipboard' ******/
System.InvalidOperationException was unhandled
Message="Invoke or BeginInvoke cannot be called on a control until
the window handle has been created."
Source="System.Windows.Forms"
StackTrace:
at System.Windows.Forms.Control.MarshaledInvoke(Control caller,
Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.BeginInvoke(Delegate method,
Object[] args)
at
System.Windows.Forms.WindowsFormsSynchronizationContext.Post(SendOrPostCallback
d, Object state)
at System.Windows.Forms.AxHost.ConnectionPointCookie.Finalize()

/***********************************************/

/***********************************************/
/*************** 'View detail' ****************/
// InnerException = null
// The rest seems to me just generic information
// on what the 'exception' type is.
 
J

Jeroen

PS. The problem is more easily reproduced if I start the executable
directly (either in bin/debug or bin/release) than when running from
VStudio. In case of the latter I need to 'touch' much more of the
application to get the error after closing.
 
W

Willy Denoyette [MVP]

Jeroen said:
PS. The problem is more easily reproduced if I start the executable
directly (either in bin/debug or bin/release) than when running from
VStudio. In case of the latter I need to 'touch' much more of the
application to get the error after closing.


What version of the Framework are you running this on?
Are you accessing the WebBrowser control from other threads than the Main
UI thread?
Also, did you host the WB control on a Form that runs on the Main UI thread?
I'm asking this because "someone" is trying to access the Control, from a
thread other than the main UI thread, after the Form has been destroyed and
it's handle invalidated.
I'm supposing this is the finalizer thread which should be OK, but I want to
be sure.

Willy.
 
J

Jeroen

Hi,

(Different timezones I think, sorry for the delayed reply.)
What version of the Framework are you running this on?

..NET 2 / studio 2005. The app was built originally in .NET 1.1 /
studio 2003, we upgraded to .NET 2 a while ago.

Are you accessing the WebBrowser control from other threads than the Main
UI thread?

No, not that I know of (any convenient way to check if I'm wrong?).

Also, did you host the WB control on a Form that runs on the Main UI thread?
I'm asking this because "someone" is trying to access the Control, from a
thread other than the main UI thread, after the Form has been destroyed and
it's handle invalidated.
I'm supposing this is the finalizer thread which should be OK, but I want to
be sure.

Yes, the form is created on the main UI thread - or at least I think
so. It is indirectly activated through the System.Activator namespace,
which might cause problems?


Thanks again for all the help and responses (this one's beginning to
drive me insane...).

By the way, next to solving the problem (of course prio #1) I'm also
still curious if there's a convenient way to debug this exception,
i.e. see what actually triggers it.

Regards,
Jeroen
 
W

Willy Denoyette [MVP]

Jeroen said:
Hi,

(Different timezones I think, sorry for the delayed reply.)


.NET 2 / studio 2005. The app was built originally in .NET 1.1 /
studio 2003, we upgraded to .NET 2 a while ago.



No, not that I know of (any convenient way to check if I'm wrong?).



Yes, the form is created on the main UI thread - or at least I think
so. It is indirectly activated through the System.Activator namespace,
which might cause problems?

Does it mean that you are creating the WB control using System.Activator?
Question is why?
Are you using the WB control from the Tools box?
Thanks again for all the help and responses (this one's beginning to
drive me insane...).

By the way, next to solving the problem (of course prio #1) I'm also
still curious if there's a convenient way to debug this exception,
i.e. see what actually triggers it.

Like I've said before, I'm pretty sure that this issue is related to the
finalizer who tries to clean-up the WB COM instance at CLR shutdown time.
For this, the finalizer thread needs to marshal the call from the finalizer
thread to the UI thread, but finds the Form destroyed and it's handle set to
null, bummer.

From this point on, the CLR does not allow any managed code to run in the
process, so, it's nearly impossible to debug this from within VS, you'll
have to use a native only debugger like Windbg.

Willy.
 
J

Jeroen

(Different timezones I think, sorry for the delayed reply.)

Guess not :D?


Does it mean that you are creating the WB control using System.Activator?
Question is why?
Are you using the WB control from the Tools box?

Yes. It's docked to fill on my own user control. Long story short, my
app chooses user controls at runtime (based on user input), that's why
we use System.Activator.

Like I've said before, I'm pretty sure that this issue is related to the
finalizer who tries to clean-up the WB COM instance at CLR shutdown time.
For this, the finalizer thread needs to marshal the call from the finalizer
thread to the UI thread, but finds the Form destroyed and it's handle set to
null, bummer.

Ok, yes, I'm grasping this now. I guess my best option is then to
manually dispose all leftover WB controls when my application shuts
down, so the CLR doesn't have to anymore.

From this point on, the CLR does not allow any managed code to run in the
process, so, it's nearly impossible to debug this from within VS, you'll
have to use a native only debugger like Windbg.

Okay, thanks. I was a bit afraid it would come to that, given that
concerning usability comparing Windbg to VStudio is like comparing
TurboC-1.0 to C# 2 :D.


Thanks for all the insights and tips Willy.

If I find a solution to this I will post it...

-Jeroen
 
W

Willy Denoyette [MVP]

Jeroen said:
Guess not :D?




Yes. It's docked to fill on my own user control. Long story short, my
app chooses user controls at runtime (based on user input), that's why
we use System.Activator.

I see, I guess you can't produce a small repro?
Like I've said before, I'm pretty sure that this issue is related to the
finalizer who tries to clean-up the WB COM instance at CLR shutdown time.
For this, the finalizer thread needs to marshal the call from the
finalizer
thread to the UI thread, but finds the Form destroyed and it's handle set
to
null, bummer.

Ok, yes, I'm grasping this now. I guess my best option is then to
manually dispose all leftover WB controls when my application shuts
down, so the CLR doesn't have to anymore.
Well, there is a lot of clean-up you can do in your Form "OnClosing" event
handler, especially you should dispose of the WB control, so that the
finalizer doesn't have to do at process shutdown time.
Okay, thanks. I was a bit afraid it would come to that, given that
concerning usability comparing Windbg to VStudio is like comparing
TurboC-1.0 to C# 2 :D.

Well all depends what you are used to, I'm using Windbg since years and find
it difficult to use the VS debugger, pretty interface that's true, but
sometimes I'm asking "where's the meat?" to finally find out that it's not
there ;-).
Thanks for all the insights and tips Willy.

If I find a solution to this I will post it...

Good luck.

Willy.
 
J

Jeroen

Sorry to bump an old thread, but it seems I have fixed my notorious
problem. After what I went through :) I want to help out anyone who
searches the web with the same problem ends up in this particular
thread. Here goes:

I added a class WebBrowserTracker with two methods:

AddInstantiatedBrowser(browser)
DisposeInstantiatedBrowserControls()

In each UserControl or other class where I have a webbrowser
instantiated I call the first method, which keeps track of all
webbrowser controls. At the end of my Main method I call the latter
method, which looks like this:

public static void DisposeInstantiatedBrowserControls()
{
foreach (System.Windows.Forms.WebBrowser control in
instantiatedBrowserObjects)
if (control != null &&
control.Disposing != true)
control.Dispose();
}

It ain't pretty, and I still don't fully understand why/how the some
WebBrowser controls do stuff after my app closes, but hey: this fixed
my problem (or so it seems, time will tell more).

Regards,
Jeroen
 
J

Jeroen

PS. Willy, thanks for your explanations and tips, that led me to
solving this!

-Jeroen
 
W

Willy Denoyette [MVP]

Jeroen said:
Sorry to bump an old thread, but it seems I have fixed my notorious
problem. After what I went through :) I want to help out anyone who
searches the web with the same problem ends up in this particular
thread. Here goes:

I added a class WebBrowserTracker with two methods:

AddInstantiatedBrowser(browser)
DisposeInstantiatedBrowserControls()

In each UserControl or other class where I have a webbrowser
instantiated I call the first method, which keeps track of all
webbrowser controls. At the end of my Main method I call the latter
method, which looks like this:

public static void DisposeInstantiatedBrowserControls()
{
foreach (System.Windows.Forms.WebBrowser control in
instantiatedBrowserObjects)
if (control != null &&
control.Disposing != true)
control.Dispose();
}

It ain't pretty, and I still don't fully understand why/how the some
WebBrowser controls do stuff after my app closes, but hey: this fixed
my problem (or so it seems, time will tell more).


Well, it's not the browser control who does stuff after your application
closes, it's the finalizer thread that calls the finalize method on the WB
control wrapper (the RCW) after the form is closed. This is one of the
managed process shutdown actions performed by the CLR, this is yet another
reason to dispose of the WB control when you are done with it, instead of
relying on the finalizer to do the right thing.

Willy.
 
J

Jeroen

Willy, thanks again for the explanation. I wasn't aware of the fact
there are types of objects I need to dispose of myself: I was under
the impression that for all managed code (also if it's only a wrapper
for unmanaged code) I needn't worry about it.

To pose one last question then, I would like to know if there's a list
of controls other than the WebBrowser that need this type of
treatment?

Thanks.

-Jeroen
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top