What you really need to check for in On_Connection is for Explorers.Count >=
1. That tells you that Outlook was started with a UI. ActiveSynch and any
other application that starts Outlook using automation and doesn't add an
Explorer will produce the same problems.
You also need to handle events in the Explorers and Inspectors collections
so you can check in the Close events for Inspectors.Count <= 1 and
Explorers.Count <= 1 to determine when Outlook is closing down. That's so
you can release all your Outlook objects and allow On_Disconnection to fire
(it won't fire if any Outlook objects are still instantiated).
We've worked out a hack that accounts for all those things but it hasn't yet
been translated into .NET code, only VB 6 code. Here's the outline of what
we do in VB 6:
In the class module that handles the IDTExtensibilty2 events we declare
these module level objects to handle events:
Private gBaseClass As New clsAddin 'class for initialization
'reference to trusted Application object
Private mobjOutlook As Outlook.Application
Private mblnTeardown As Boolean
'Event-aware references to Explorers collection & ActiveExplorer
Private WithEvents mcolExplorers As Outlook.Explorers
Private WithEvents molExplorer As Outlook.Explorer
In On_Connection:
'set module level reference to COMAddIn object
Set mobjOutlook = Application
'event-aware reference to Explorers collection
'use NewExplorer event to watch for UI creation
Set mcolExplorers = mobjOutlook.Explorers
'put ProgID in a global variable
gstrProgID = AddInInst.ProgId
AddInInst.Object = Me
mblnTeardown = False
'Are we starting with UI?
If mcolExplorers.Count > 0 Then
Set molExplorer = mobjOutlook.Explorers.Item(1)
'we have UI - initialize base class
gBaseClass.InitHandler mobjOutlook, AddInInst.ProgId
Else
'do nothing
'monitor Explorers collection (in this module)
'if NewExplorer event is raised then we have UI
End If
In OnBeginShutdown and OnDisconnection:
TearDown
Then the supporting procedures in that module:
Private Sub TearDown()
On Error Resume Next
mblnTeardown = True
'Tear down the base class
If gBaseClass.Init = True Then
gBaseClass.UnInitHandler
DoEvents
End If
Set gBaseClass = Nothing
'release reference to Outlook objects
Set molExplorer = Nothing
Set mcolExplorers = Nothing
Set mobjOutlook = Nothing
End Sub
' NewExplorer event will be raised if there is UI
Private Sub mcolExplorers_NewExplorer(ByVal Explorer As Outlook.Explorer)
On Error Resume Next
'assign ActiveExplorer
Set molExplorer = Explorer
If gBaseClass.Init = False Then
'we didn't have UI before - initialize add-in objects
gBaseClass.InitHandler mobjOutlook, gstrProgID
End If
End Sub
' Monitor Explorer_Close to see when UI "disappears"
Private Sub molExplorer_Close()
On Error Resume Next
'release current reference
Set molExplorer = Nothing
Set molExplorer = mobjOutlook.ActiveExplorer
If (molExplorer Is Nothing) And (mobjOutlook.Inspectors.Count = 0) Then
'release add-in objects
gBaseClass.UnInitHandler
End If
End Sub
Then in the addin class that handles init and release:
'Initialization flag
Private mblnInit As Boolean
Private mblnFailed As Boolean
'Expose Init property to Connect class
Friend Property Get Init() As Boolean
Init = mblnInit
End Property
'Expose Failed property to Connect class
Friend Property Get Failed() As Boolean
Failed = mblnFailed
End Property
Friend Sub InitHandler(OLApp As Outlook.Application, strProgID As String)
'do init, set mblnFailed and mblnInit appropriately
Call the uninithandler procedure whenever On_Disconnection fires or the
conditions in those procedures in the IDTExtensibilty2 class handler call
for it or when the tests are met when Inspectors or Explorers are closed.
One final point. In .NET you don't know when an object is really released
after you set it to Nothing. That depends on the garbage collector. Many
people have found that ends up hanging Outlook in memory. The workaround is
to call to release COM object for everything and explicitly call the garbage
collector when you're ready to exit and wait around until the garbage
collector is finished.