Help! Inspector.Close is fired before Inspector.Activate handler finishes

  • Thread starter Sergey Anchipolevsky
  • Start date
S

Sergey Anchipolevsky

Hello all.

I've been developing a C# Addin for OL2002/2003 and encountered a strange
problem.

Sometimes inspector's Close event is fired before the Activate handler finishes.
This can be reproduced by opening many inspectors and then closing them sequentially
as fast as possible. Logs show that Close handler is invoked before the Activate
handler finishes. Both handlers are executed in the same thread. As you can
imagine, this causes numerous problems, since the Close handler frees resources
allocated on Inspector creation.

First I thought that the reason might be an invokation of the message loop
(by calling Application.DoEvents() for example) hidden somewhere inside Activate
handler or its callees. But a thorough code analysis showed this is not the
case (at least in the addin). However the Activate handler makes many calls
to the Outlook object model.

I've made some protection from this situation: I don't free any resources
(that is normally done on Close) until Activate handler finishes. But it
looks like Outlook sometimes releases its internal objects before Close event
is fired, so Activate event handler cannot continue - any access to Outlook
object model causes either a null reference exception or a "COM wrapper"
exception.

Does anybody know the real cause of that? Does my addin do something wrong,
or is it an Outlook's "feature"?

The only workaround that comes in mind is creating proxies for Outlook objects
to use them in Activate event handler (as well as in all other handlers).
These proxies would check if the inspector is "closed" before any real operations.
But this decision is quite costly.

Is there a simpler solution?

Any help would be really appreciated.

Thanks in advance.

WBR,
Sergey Anchipolevsky
 
D

Dmitry Streblechenko

If your code in the Activate event handler does anything that can
potentially run the Windows message loop (such sa displaying a message box
or any other window), then Close event can potentially fire while Activate
is still beign processed. What do you do in the Activate event handler?

Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool
 
J

Josh Einstein

He should be able to find out exactly what is causing the re-entrance by
setting a breakpoint in the Close event handler and then looking at the
stack trace to see what the Activate event handler calls into that leads to
Close.

From what I understand, there are alot of API's that can cause re-entrance
bugs by pumping the message queue that you might not be aware of such as
waiting on waithandles, sleeping threads, etc. There's a ton of information
about this problem over on cbrummes web log.
http://blogs.msdn.com/cbrumme/archive/2004/02/02/66219.aspx

--
Josh Einstein
Einstein Technologies
Microsoft Tablet PC MVP
Tablet Enhancements for Outlook 2.0 - Try it free for 14 days
www.tabletoutlook.com
 
S

Sergey Anchipolevsky

Hello Josh,
He should be able to find out exactly what is causing the re-entrance
by setting a breakpoint in the Close event handler and then looking at
the stack trace to see what the Activate event handler calls into that
leads to Close.

Oh.. How could I miss it? Shame on me! Thank you very much :)
If you're insterested in my findings see my reply to Dmitry in this thread.
From what I understand, there are alot of API's that can cause
re-entrance bugs by pumping the message queue that you might not be
aware of such as waiting on waithandles, sleeping threads, etc.
There's a ton of information about this problem over on cbrummes web
log. http://blogs.msdn.com/cbrumme/archive/2004/02/02/66219.aspx

Oh yes. I shoud be careful. Thank you for the source.
WBR,
Sergey Anchipolevsky
 
S

Sergey Anchipolevsky

Hello Dmitry,
If your code in the Activate event handler does anything that can
potentially run the Windows message loop (such sa displaying a message
box or any other window), then Close event can potentially fire while
Activate is still beign processed. What do you do in the Activate
event handler?

I followed Josh's advice and found out that the message loop is pumped in
CommandBars.GetEnumerator(). (very surprising actually).
I use this method to iterate through toolbar buttons and menu items in order
to hide some of them upon inspector activation.

I implemented the following workaround that seems to work quite well.

I subclassed the inspector's window with the code that suppresses WM_CLOSE
message when it comes while the Activate handler is running. In the end of
the Activate method I explicitly call Inspector.Close() if WM_CLOSE message
has been received.

What do you think about this solution?

WBR,
Sergey Anchipolevsky
 
J

Josh Einstein

If you have a reference to any .NET form or control you can use BeginInvoke
to "defer" the event until the next time the loop is pumped. For example:

private bool _activating = false;

private void Inspector_Activate() {
{
try {
_activating = true;
// do stuff which might pump the loop
} // try
finally {
_activating = false;
} // finally
} // function

private void Inspector_Close() {
if ( _activating ) {
myControl.BeginInvoke(new MethodInvoker(Inspector_Close));
return;
} // if
else{
// Proceed normally
} // else
} // function

--
Josh Einstein
Einstein Technologies
Microsoft Tablet PC MVP
Tablet Enhancements for Outlook 2.0 - Try it free for 14 days
www.tabletoutlook.com
 
D

Dmitry Streblechenko

That should work, but... Why do you need to enumerate through *all* controls
in an inspector? If you are using the Word editor, there could be thousands
of them. Do you really care about all of them?
Did you try to use FindControl() instead to only work with the controls
thata you care about?

Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool
 
S

Sergey Anchipolevsky

Hello Dmitry,

I need the overall enumeration because I have to disable many functions that
aren't consistent with my custom form's functionality. To be more specific,
I have a list of controls that should be left enabled in the custom form.
The rest of the buttons must be hidden. This is a project requirement.

Also, the addin must work under different versions of Outlook which have
different sets of buttons. Since I don't know a priori the exact set of controls
to be hidden, I cannot use FindControl(), but I can iterate over all the
controls and determine if this one must be hidden or not.

WBR,
Sergey Anchipolevsky
 
S

Sergey Anchipolevsky

Hello Josh,

I'm affraid, your solution isn't exactly what I need, because it deffers
my event handling, not the event itself. When I leave Inspector_Close() after
calling BeginInvoke(), Outlook will destroy the Inspector's objects. And
when my finalizing code (the other branch in Inspector_Close()) is finally
starts executing, I'll still have the same problem that I had before supressing
WM_CLOSE - COM wrapper exceptions.

Am I wrong?

WBR,
Sergey Anchipolevsky
 

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