NewExplorer event slowing and breaking outlook shutdown.

  • Thread starter Thread starter Dave Townsend
  • Start date Start date
D

Dave Townsend

I am working on a pretty simple addin in C# and I noticed that when it
was installed Outlook would take a while to shutdown. On Outlook 2000 it
doesn't shut down at all which is a major concern. I seem to have
narrowed this down to the NewExplorer event.

If I register an event handler with NewExplorer then on outlook 2003 the
shutdown time rises from under a second to about 7 seconds and on
outlook 2000 it doesnt shut down at all (tried leaving for half an hour).

I have narrowed it down to the point that I am actually only registering
an empty event handler. With it registered, which should cause no
difference to the code, I get problems, without nothing. I am freeing
all object references as the last explorer is closed (I have traced to
check that this happens) so there should be no object references laying
around. I have also tried this with and without shim with no difference.

I then tried the same thing with the NewInspector event and found the
same problem. Interestingly with only NewInspector handled Outlook takes
7 seconds to shut down. With only NewExplorer registered it is also 7
seconds. With both it is also 7 seconds. With neither shutdown is near
instant.

Has anyone come across this before and knows what might be causing it
and how to fix it?

Dave
 
1. Use Inspector.Close to clean up all the references to the Inspector
object and its children (toolbars, buttons, etc)
2. GC: Rather than setting COM objects to null, use
Marshal.ReleaseCOMObject() to force a COM object to be released immediately
rather than relying on the GC to take its time.

Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool
 
Dmitry said:
1. Use Inspector.Close to clean up all the references to the Inspector
object and its children (toolbars, buttons, etc)

I can't call Inspector.Close since all the inspectors are already
closed. Same for the Explorers.
2. GC: Rather than setting COM objects to null, use
Marshal.ReleaseCOMObject() to force a COM object to be released immediately
rather than relying on the GC to take its time.

I have already tried doing this but nothing changed.

Dave
 
See below.

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


Dave Townsend said:
I can't call Inspector.Close since all the inspectors are already
closed. Same for the Explorers.

You cannot call the events, you need to provide even handlers that will be
called by Outlook. Since you are consuming the NewInspector event, you store
some Inspector related objects in that event handler (e.g. Inspector,
CommandBarButton, etc). These objects must be released in the
Inspector.Close event, which you must trap.
I have already tried doing this but nothing changed.

Doyou store any Outlook objects in global/class variables?
 
"Since you are consuming the NewInspector event, you store"
must read
"Since you are consuming the NewInspector event, I assume that you store"

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

Dave
See below.

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





You cannot call the events, you need to provide even handlers that will be
called by Outlook. Since you are consuming the NewInspector event, you store
some Inspector related objects in that event handler (e.g. Inspector,
CommandBarButton, etc). These objects must be released in the
Inspector.Close event, which you must trap.

Ah yeah sorry, misread what you meant.

In the initial situation I was testing yes I was holding inspectors
until they close at which point they were released. But as I said in my
original post I am now in the situation where the registered
NewInspector and NewExplorer event handlers are empty, they do not store
references to the inspectors or explorers anywhere.

Also the way I am testing this is simple. Open outlook then close it
again. In this fashion the NewInspector and NewExplorer event handlers
are never actually getting called so I can't see how anything that goes
on in them would make any difference anyway.
Doyou store any Outlook objects in global/class variables?

Yes, but as I said in my original post they all get released on shutdown
and by using breakpoints I know that this occurs before the delay.
 
Do you remove you event handler (whicn internally holds a reference to the
Application.Inspectors collection)? Did you use Marshal.ReleaseCOMObject on
all OOM objects? What is your startup and shutdown code?

Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool
 
Yeah I removed the event handler. I also hold references to the
Application, Explorers and Inspectors globally, all of which are
released with Marshal.ReleaseCOMObject and then set to null.

The Connect class is basically that given on the Microsoft site with an
added object instantiation in OnConnection and then that object
reference is told to clean itself up (derefencing and releasing
everything) and then released in OnBeginShutdown. Then there is a
garbage collect which occurs before the delay.

Dave
 
OnBeginShutdown is the wrong event to try to handle for that. Due to a
Catch-22 situation with Outlook closing, your holding any Outlook references
of any kind and On_Disconnection not firing until all such references are
released what you really have to do is trap Explorer.Close and
Inspector.Close and test both the Explorers and Inspectors collections for
lack of members to know when to release all of your objects. Also, when you
open Outlook and immediately close it you still have 1 Explorer that has
been opened and needs to be closed unless you have started Outlook using
automation with no UI at all.
 
Ken said:
OnBeginShutdown is the wrong event to try to handle for that. Due to a
Catch-22 situation with Outlook closing, your holding any Outlook
references of any kind and On_Disconnection not firing until all such
references are released what you really have to do is trap
Explorer.Close and Inspector.Close and test both the Explorers and
Inspectors collections for lack of members to know when to release all
of your objects. Also, when you open Outlook and immediately close it
you still have 1 Explorer that has been opened and needs to be closed
unless you have started Outlook using automation with no UI at all.

Yes and I already do this. The bit in OnBeginShutdown is a bit of a
catch all just in case for some bizarre reason the objects haven't
already been cleaned up. As I said, OnBeginShutdown is getting called
and it's getting called before the annoying delay that I am trying to
get rid of.

Also yes there is an explorer open, but since it gets opened before the
addins are initialised, my NewExplorer handler is never called.

I have written a really really simple test case for this. This is a
simple addin that does nothing. Just registers an event handler for
NewExplorer. With this addin in place Outlook takes 7 seconds after
closing to leave the process list. Comment out the line that adds the
event handler and Outlook leaves the processes the moment it exits.

Dave

namespace TestAddin
{
using System;
using Outlook = Microsoft.Office.Interop.Outlook;
using Extensibility;
using System.Runtime.InteropServices;

[GuidAttribute("D5683DF4-2BE5-4478-8606-F76ACEAE5711"),ProgId("TestAddin.Connect")]
public class Connect : Object, Extensibility.IDTExtensibility2
{
public Connect()
{
}

public void OnConnection(object
application,Extensibility.ext_ConnectMode connectMode, object addInInst,
ref System.Array custom)
{
Outlook.Application app = application as Outlook.Application;
app.Explorers.NewExplorer+=new
Microsoft.Office.Interop.Outlook.ExplorersEvents_NewExplorerEventHandler(Explorers_NewExplorer);
}

public void OnDisconnection(Extensibility.ext_DisconnectMode
disconnectMode, ref System.Array custom)
{
}

public void OnAddInsUpdate(ref System.Array custom)
{
}

public void OnStartupComplete(ref System.Array custom)
{
}

public void OnBeginShutdown(ref System.Array custom)
{
}

private void
Explorers_NewExplorer(Microsoft.Office.Interop.Outlook.Explorer Explorer)
{
}
}
}
 
Do try to remove the NewExplorer event handler in your cleanup code.

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


Dave Townsend said:
Ken said:
OnBeginShutdown is the wrong event to try to handle for that. Due to a
Catch-22 situation with Outlook closing, your holding any Outlook
references of any kind and On_Disconnection not firing until all such
references are released what you really have to do is trap
Explorer.Close and Inspector.Close and test both the Explorers and
Inspectors collections for lack of members to know when to release all
of your objects. Also, when you open Outlook and immediately close it
you still have 1 Explorer that has been opened and needs to be closed
unless you have started Outlook using automation with no UI at all.

Yes and I already do this. The bit in OnBeginShutdown is a bit of a
catch all just in case for some bizarre reason the objects haven't
already been cleaned up. As I said, OnBeginShutdown is getting called
and it's getting called before the annoying delay that I am trying to
get rid of.

Also yes there is an explorer open, but since it gets opened before the
addins are initialised, my NewExplorer handler is never called.

I have written a really really simple test case for this. This is a
simple addin that does nothing. Just registers an event handler for
NewExplorer. With this addin in place Outlook takes 7 seconds after
closing to leave the process list. Comment out the line that adds the
event handler and Outlook leaves the processes the moment it exits.

Dave

namespace TestAddin
{
using System;
using Outlook = Microsoft.Office.Interop.Outlook;
using Extensibility;
using System.Runtime.InteropServices;

[GuidAttribute("D5683DF4-2BE5-4478-8606-F76ACEAE5711"),ProgId("TestAddin.Con
nect")]
public class Connect : Object, Extensibility.IDTExtensibility2
{
public Connect()
{
}

public void OnConnection(object
application,Extensibility.ext_ConnectMode connectMode, object addInInst,
ref System.Array custom)
{
Outlook.Application app = application as Outlook.Application;
app.Explorers.NewExplorer+=new
Microsoft.Office.Interop.Outlook.ExplorersEvents_NewExplorerEventHandler(Exp
lorers_NewExplorer);
}

public void OnDisconnection(Extensibility.ext_DisconnectMode
disconnectMode, ref System.Array custom)
{
}

public void OnAddInsUpdate(ref System.Array custom)
{
}

public void OnStartupComplete(ref System.Array custom)
{
}

public void OnBeginShutdown(ref System.Array custom)
{
}

private void
Explorers_NewExplorer(Microsoft.Office.Interop.Outlook.Explorer Explorer)
{
}
}
}
 
Back
Top