vikky999
asked on
Outlook instantiated via COM wont quit, hangs around in memory forever?
I am trying to automate Outlook using COM. I am using VB.Net
So I instantiate an outlook object, make it visible, If i quit is using
Outlook.Quit() function it works, however if i close this Outlook instance manually using the mouse and click on the top right hand side close icon. Outlook looks like it quit, but it hangs around in memory forever.
I can see it in the process list using Ctrl+Alt+Del
How do i fix this ?
So I instantiate an outlook object, make it visible, If i quit is using
Outlook.Quit() function it works, however if i close this Outlook instance manually using the mouse and click on the top right hand side close icon. Outlook looks like it quit, but it hangs around in memory forever.
I can see it in the process list using Ctrl+Alt+Del
How do i fix this ?
ASKER
Hi bob....yes i also did the same thing. But for some reason, when i shut outlook manually , the code gets to my event_handler i.e. i see a messagebox with "outlook Shutdown" , but it never reaches the destructor.
Public Class LibMAPI
Inherits WAFL
' The following fields can be provided by user
' but are initialized to defaults set in XML config file
Private WithEvents olApp As Microsoft.Office.Interop.O utlook.App lication
Private olNS As Microsoft.Office.Interop.O utlook.Nam eSpace
Dim olFolder As Microsoft.Office.Interop.O utlook.MAP IFolder
Dim olExplorer As Microsoft.Office.Interop.O utlook.Exp lorer
Public Sub StartOutlook()
olApp = DirectCast(CreateObject("O utlook.App lication") , Microsoft.Office.Interop.O utlook.App lication)
olNS = olApp.GetNamespace("MAPI")
olNS.Logon()
olFolder = olNS.GetDefaultFolder(OlDe faultFolde rs.olFolde rInbox)
olFolder.Display()
olExplorer = CType(olApp.ActiveWindow, Microsoft.Office.Interop.O utlook.Exp lorer)
olExplorer.WindowState = Microsoft.Office.Interop.O utlook.OlW indowState .olMaximiz ed
olExplorer.Display()
End Sub
Protected Overrides Sub Finalize()
MsgBox("Destructor")
MyBase.Finalize()
End Sub
Private Sub olApp_Quit() Handles olApp.Quit
MsgBox("Outlook shutdown")
olExplorer = Nothing
olFolder = Nothing
olNS = Nothing
System.Runtime.InteropServ ices.Marsh al.Release ComObject( olApp)
End Sub
End Class
Public Class LibMAPI
Inherits WAFL
' The following fields can be provided by user
' but are initialized to defaults set in XML config file
Private WithEvents olApp As Microsoft.Office.Interop.O
Private olNS As Microsoft.Office.Interop.O
Dim olFolder As Microsoft.Office.Interop.O
Dim olExplorer As Microsoft.Office.Interop.O
Public Sub StartOutlook()
olApp = DirectCast(CreateObject("O
olNS = olApp.GetNamespace("MAPI")
olNS.Logon()
olFolder = olNS.GetDefaultFolder(OlDe
olFolder.Display()
olExplorer = CType(olApp.ActiveWindow, Microsoft.Office.Interop.O
olExplorer.WindowState = Microsoft.Office.Interop.O
olExplorer.Display()
End Sub
Protected Overrides Sub Finalize()
MsgBox("Destructor")
MyBase.Finalize()
End Sub
Private Sub olApp_Quit() Handles olApp.Quit
MsgBox("Outlook shutdown")
olExplorer = Nothing
olFolder = Nothing
olNS = Nothing
System.Runtime.InteropServ
End Sub
End Class
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Basically, I was to see my destructor getting called after Im done with handling the olapp.quit event.
You can't set the variables to Nothing before you call Marshal.ReleaseComObject.
Bob
Bob
ASKER
So I dont want to quit the outlook instance programatically, I want the user the quit outlook manually , and then after the user quits the instance manually, it should call my destructor where i want to do some final cleanup.
I am talking about in here:
Private Sub olApp_Quit() Handles olApp.Quit
MsgBox("Outlook shutdown")
System.Runtime.InteropServ ices.Marsh al.Release ComObject( olApp)
End Sub
Bob
Private Sub olApp_Quit() Handles olApp.Quit
MsgBox("Outlook shutdown")
System.Runtime.InteropServ
End Sub
Bob
ASKER
sorry bob..yeah i didnt do that in my code. It was too long..copying/pasting..did it in the wrong order. Did not set it to nothing before calling releaseCOMObject.
Anyway...so basically i need to implement IDisposable..But just for my understanding. Why is this happening, i mean why once outlook is shut manually, my quit event handler is being called, in the event handler i release the COM object, and set olApp= NOthing...why isnt my destructor being called ?
Anyway...so basically i need to implement IDisposable..But just for my understanding. Why is this happening, i mean why once outlook is shut manually, my quit event handler is being called, in the event handler i release the COM object, and set olApp= NOthing...why isnt my destructor being called ?
ASKER
okay did the IDispsable stuff..now finally outlook doesnt hang around in memory !!!
yay !
but my destructor still doesnt get called until i shut down my applicatoin
yay !
but my destructor still doesnt get called until i shut down my applicatoin
ASKER
Public Class LibMAPI
Implements IDisposable
' The following fields can be provided by user
' but are initialized to defaults set in XML config file
Private WithEvents olApp As Microsoft.Office.Interop.O utlook.App lication
Private olNS As Microsoft.Office.Interop.O utlook.Nam eSpace
Private outlookVersion As String
Dim olFolder As Microsoft.Office.Interop.O utlook.MAP IFolder
Dim olExplorer As Microsoft.Office.Interop.O utlook.Exp lorer
Dim autoit As New AutoItX3Lib.AutoItX3
'Dim counter1 As New LibMAPIPopUpKiller
'Dim Thread1 As New System.Threading.Thread(Ad dressOf counter1.Count)
Public Sub New()
MyBase.New()
' Set AutoItX to use substring matching for window titles
autoit.Opt("WinTitleMatchM ode", 2)
autoit.ProcessClose("WINWO RD.EXE")
autoit.ProcessClose("OUTLO OK.EXE")
autoit.Sleep(5000)
'Thread1.Start()
End Sub
Public Sub StartOutlook()
olApp = DirectCast(CreateObject("O utlook.App lication") , Microsoft.Office.Interop.O utlook.App lication)
outlookVersion = olApp.Version
olNS = olApp.GetNamespace("MAPI")
olNS.Logon()
olFolder = olNS.GetDefaultFolder(OlDe faultFolde rs.olFolde rInbox)
olFolder.Display()
olExplorer = CType(olApp.ActiveWindow, Microsoft.Office.Interop.O utlook.Exp lorer)
olExplorer.WindowState = Microsoft.Office.Interop.O utlook.OlW indowState .olMaximiz ed
olExplorer.Display()
End Sub
Protected Overrides Sub Finalize()
MsgBox("Destructor")
'Thread1.Abort()
MyBase.Finalize()
End Sub
Protected Sub Dispose() Implements IDisposable.Dispose
olApp.Quit()
Marshal.ReleaseComObject(o lApp)
Marshal.ReleaseComObject(o lExplorer)
Marshal.ReleaseComObject(o lFolder)
Marshal.ReleaseComObject(o lNS)
GC.Collect()
End Sub
Private Sub olApp_Quit() Handles olApp.Quit
MsgBox("Outlook shutdown")
Dispose()
End Sub
Implements IDisposable
' The following fields can be provided by user
' but are initialized to defaults set in XML config file
Private WithEvents olApp As Microsoft.Office.Interop.O
Private olNS As Microsoft.Office.Interop.O
Private outlookVersion As String
Dim olFolder As Microsoft.Office.Interop.O
Dim olExplorer As Microsoft.Office.Interop.O
Dim autoit As New AutoItX3Lib.AutoItX3
'Dim counter1 As New LibMAPIPopUpKiller
'Dim Thread1 As New System.Threading.Thread(Ad
Public Sub New()
MyBase.New()
' Set AutoItX to use substring matching for window titles
autoit.Opt("WinTitleMatchM
autoit.ProcessClose("WINWO
autoit.ProcessClose("OUTLO
autoit.Sleep(5000)
'Thread1.Start()
End Sub
Public Sub StartOutlook()
olApp = DirectCast(CreateObject("O
outlookVersion = olApp.Version
olNS = olApp.GetNamespace("MAPI")
olNS.Logon()
olFolder = olNS.GetDefaultFolder(OlDe
olFolder.Display()
olExplorer = CType(olApp.ActiveWindow, Microsoft.Office.Interop.O
olExplorer.WindowState = Microsoft.Office.Interop.O
olExplorer.Display()
End Sub
Protected Overrides Sub Finalize()
MsgBox("Destructor")
'Thread1.Abort()
MyBase.Finalize()
End Sub
Protected Sub Dispose() Implements IDisposable.Dispose
olApp.Quit()
Marshal.ReleaseComObject(o
Marshal.ReleaseComObject(o
Marshal.ReleaseComObject(o
Marshal.ReleaseComObject(o
GC.Collect()
End Sub
Private Sub olApp_Quit() Handles olApp.Quit
MsgBox("Outlook shutdown")
Dispose()
End Sub
Here is the thing about .NET is if you don't explicitly clear the object, then it will happen when the garbage collector runs, or when the application exits.
Bob
Bob
Imports Microsoft.Office.Interop
Imports System.Runtime.InteropServ
Public Class Appointment
Public AllDayEvent As Boolean
Public Body As String = String.Empty
Public Creation As Date
Public Duration As Integer
Public [End] As Date
Public Importance As String = String.Empty
Public IsRecurring As Boolean
Public MeetingStatus As String = String.Empty
Public Start As Date
Public Subject As String = String.Empty
Public UnRead As Boolean
End Class
<CLSCompliant(False)> _
Public Class OutlookAppointments
Private _appOutlook As Outlook.Application
Public Sub New()
_appOutlook = New Outlook.Application
End Sub
Protected Overrides Sub Finalize()
MyBase.Finalize()
_appOutlook.Quit()
Marshal.ReleaseComObject(_
GC.Collect()
End Sub
Public ReadOnly Property CalendarFolder() As Outlook.MAPIFolder
Get
Return _appOutlook.GetNamespace("
End Get
End Property
Public ReadOnly Property Appointments() As ArrayList
Get
Dim listAppointments As New ArrayList
For Each item As Outlook.AppointmentItem In Me.CalendarFolder.Items
Dim newAppointment As New Appointment
newAppointment.AllDayEvent
newAppointment.Body = item.Body
newAppointment.Creation = item.CreationTime
newAppointment.Duration = item.Duration
newAppointment.End = item.End
newAppointment.Importance = item.Importance.ToString()
newAppointment.IsRecurring
newAppointment.MeetingStat
newAppointment.Start = item.Start
newAppointment.Subject = item.Subject
newAppointment.UnRead = item.UnRead
listAppointments.Add(newAp
Next
Return listAppointments
End Get
End Property
End Class
Bob