Bulletproof Exiting Outlook (and not crashing)

K

Ken Slovak - [MVP - Outlook]

I would try 2 things. First I'd get rid of objFolder.Items and explicitly
instantiate an Items collection that can be released. I'd also get rid of
that For Each loop as I had mentioned and use an iterator For loop (For i =
1 To colIems.Count) and see if that helps.
 
D

Derek Hart

Darn, I'm sorry. Don't understand how you would change this code. Can you
show me how you would instantiate this items collection and use the for
loop? Please clarify.

Is this the for loop?
For i = 0 To objFolder.Items.Count - 1
Next
 
K

Ken Slovak - [MVP - Outlook]

All Outlook collections are 1 based, not 0 based.

Dim colItems As Outlook.Items
Set colItems = objFolder.Items
For i = 1 To colItems.Count
Set objItem = colItems.Item(i)
' whatever
Set objItem = Nothing
Next
 
D

Derek Hart

This code only exits Outlook when I exit the program. What do you think I
need to do to exit Outlook at the end of this routine?

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim objNameSpace As Outlook.NameSpace
Dim objFolder As Outlook.MAPIFolder
Dim colItems As Outlook.Items
Dim objItem As Outlook.MailItem
Dim iterations As Integer

Try
InstantiateOutlook()
objNameSpace = objOutlook.GetNamespace("MAPI")
objFolder =
objNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox)
objNameSpace.Logon()
colItems = objFolder.Items

For i = 1 To colItems.Count
iterations += 1
objItem = colItems.Item(i)
' whatever
objItem = Nothing
If iterations = 50 Then Exit For
Next

Marshal.ReleaseComObject(objFolder)
Marshal.ReleaseComObject(objNameSpace)
objOutlook.Quit()
Marshal.ReleaseComObject(objOutlook)
objOutlook = Nothing
GC.Collect()
GC.WaitForPendingFinalizers()
Catch ex As Exception
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK,
MessageBoxIcon.Information)
End Try
End Sub
 
K

Ken Slovak - [MVP - Outlook]

You also want to release colItems and a final release of objItem. You also
might want to call ReleaseComObject() and look at the return value to make
sure no COM instances are hanging around.
 
D

Derek Hart

Success... but a couple questions...

Confused about the canQuit variable... Is this how the instantiate routine
should look? I never saw you setting canQuit to true. See how I set it in 3
places. It is declared globally.

Private Sub InstantiateOutlook()
Try
Dim olProcess As String = "Outlook.exe"
Dim query As New SelectQuery("SELECT Name FROM Win32_Process
WHERE name='" & olProcess & "'")
Dim searcher As New ManagementObjectSearcher(query)
Dim objectCollection As ManagementObjectCollection =
searcher.Get()
Dim collCount As Integer = objectCollection.Count
searcher.Dispose()
objectCollection.Dispose()
searcher = Nothing
objectCollection = Nothing
If collCount <> 0 Then
' Outlook already running, hook into the Outlook instance
objOutlook =
TryCast(Marshal.GetActiveObject("Outlook.Application"), Outlook.Application)
If objOutlook IsNot Nothing Then
canQuit = False
Else
canQuit = True
End If
Else
' Outlook not already running, start it
canQuit = True
Dim _app As New Outlook.ApplicationClass()
objOutlook = DirectCast(_app, Outlook.Application)
End If
Catch ex As System.Exception
MessageBox.Show(ex.Message)
End Try
End Sub

And now when I use my routine I am unclear how to use the canQuit variable.
If Outlook is already running, I simply don't want to exit it? I tried this,
and then exited the Outlook UI by hand, but Outlook still stays in memory.
How did you mean this canQuit should be used?

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Try
Dim objNameSpace As Outlook.NameSpace
Dim objFolder As Outlook.MAPIFolder
Dim colItems As Outlook.Items
Dim objItem As Outlook.MailItem
Dim iterations As Integer

InstantiateOutlook()

objNameSpace = objOutlook.GetNamespace("MAPI")
objFolder =
objNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox)
objNameSpace.Logon()
colItems = objFolder.Items

For i = 1 To colItems.Count
iterations += 1
objItem = colItems.Item(i)
' whatever
Marshal.ReleaseComObject(objItem)
objItem = Nothing
If iterations = 50 Then Exit For
Next

If canQuit Then ' what to do here?
Marshal.ReleaseComObject(colItems)
Marshal.ReleaseComObject(objFolder)
Marshal.ReleaseComObject(objNameSpace)
objOutlook.Quit()
Marshal.ReleaseComObject(objOutlook)
GC.Collect()
GC.WaitForPendingFinalizers()
End If

Catch ex As Exception
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK,
MessageBoxIcon.Information)
End Try
End Sub
 
K

Ken Slovak - [MVP - Outlook]

I set that flag if and only if I get an Outlook session by using New or
CreateObject(). Otherwise if Outlook was already running it's set to false.

When it comes time to end the program I check the flag and if it's true I
call the Quit() method of the Outlook.Application object. Otherwise I don't
call Quit(). I still release all objects in either case, otherwise Outlook
won't release properly when it is closed, but I only call Quit() if I want
the Outlook session to be terminated at that time.
 

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