• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 545
  • Last Modified:

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 ?
0
vikky999
Asked:
vikky999
  • 6
  • 5
1 Solution
 
Bob LearnedCommented:
Look the Finalize method:

Imports Microsoft.Office.Interop
Imports System.Runtime.InteropServices

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(_appOutlook)

    GC.Collect()

  End Sub

  Public ReadOnly Property CalendarFolder() As Outlook.MAPIFolder
    Get
      Return _appOutlook.GetNamespace("MAPI").GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar)
    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 = item.AllDayEvent
        newAppointment.Body = item.Body
        newAppointment.Creation = item.CreationTime
        newAppointment.Duration = item.Duration
        newAppointment.End = item.End
        newAppointment.Importance = item.Importance.ToString()
        newAppointment.IsRecurring = item.IsRecurring
        newAppointment.MeetingStatus = item.MeetingStatus.ToString()
        newAppointment.Start = item.Start
        newAppointment.Subject = item.Subject
        newAppointment.UnRead = item.UnRead

        listAppointments.Add(newAppointment)
      Next
      Return listAppointments
    End Get
  End Property

End Class

Bob
0
 
vikky999Author Commented:
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.Outlook.Application
        Private olNS As Microsoft.Office.Interop.Outlook.NameSpace
        Dim olFolder As Microsoft.Office.Interop.Outlook.MAPIFolder
        Dim olExplorer As Microsoft.Office.Interop.Outlook.Explorer

     Public Sub StartOutlook()

     

            olApp = DirectCast(CreateObject("Outlook.Application"), Microsoft.Office.Interop.Outlook.Application)

            olNS = olApp.GetNamespace("MAPI")
            olNS.Logon()
            olFolder = olNS.GetDefaultFolder(OlDefaultFolders.olFolderInbox)
            olFolder.Display()
            olExplorer = CType(olApp.ActiveWindow, Microsoft.Office.Interop.Outlook.Explorer)
            olExplorer.WindowState = Microsoft.Office.Interop.Outlook.OlWindowState.olMaximized
            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.InteropServices.Marshal.ReleaseComObject(olApp)
        End Sub
    End Class
0
 
Bob LearnedCommented:
I think that you should implement IDisposable, and use this in the Dispose method:

Imports System.Runtime.InteropServices

...

       Protected Sub Dispose() Implements IDisposable.Dispose    
           olApp.Quit()      
           Marshal.ReleaseComObject(olApp)
           Marshal.ReleaseComObject(olExplorer)
           Marshal.ReleaseComObject(olFolder)
           Marshal.ReleaseComObject(olNS)
           GC.Collect()
        End Sub

Then call the Dispose method for the LibMAPI class.

Bob
0
Granular recovery for Microsoft Exchange

With Veeam Explorer for Microsoft Exchange you can choose the Exchange Servers and restore points you’re interested in, and Veeam Explorer will present the contents of those mailbox stores for browsing, searching and exporting.

 
vikky999Author Commented:
Basically, I was to see my destructor getting called after Im done with handling the olapp.quit event.
0
 
Bob LearnedCommented:
You can't set the variables to Nothing before you call Marshal.ReleaseComObject.

Bob
0
 
vikky999Author Commented:
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.
0
 
Bob LearnedCommented:
I am talking about in here:

        Private Sub olApp_Quit() Handles olApp.Quit
            MsgBox("Outlook shutdown")
            System.Runtime.InteropServices.Marshal.ReleaseComObject(olApp)
        End Sub

Bob
0
 
vikky999Author Commented:
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 ?
0
 
vikky999Author Commented:
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
0
 
vikky999Author Commented:
   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.Outlook.Application
        Private olNS As Microsoft.Office.Interop.Outlook.NameSpace
        Private outlookVersion As String
        Dim olFolder As Microsoft.Office.Interop.Outlook.MAPIFolder
        Dim olExplorer As Microsoft.Office.Interop.Outlook.Explorer
        Dim autoit As New AutoItX3Lib.AutoItX3
        'Dim counter1 As New LibMAPIPopUpKiller
        'Dim Thread1 As New System.Threading.Thread(AddressOf counter1.Count)





        Public Sub New()

            MyBase.New()

            ' Set AutoItX to use substring matching for window titles

            autoit.Opt("WinTitleMatchMode", 2)
            autoit.ProcessClose("WINWORD.EXE")
            autoit.ProcessClose("OUTLOOK.EXE")
            autoit.Sleep(5000)

            'Thread1.Start()

        End Sub

        Public Sub StartOutlook()
            olApp = DirectCast(CreateObject("Outlook.Application"), Microsoft.Office.Interop.Outlook.Application)
            outlookVersion = olApp.Version
            olNS = olApp.GetNamespace("MAPI")
            olNS.Logon()
            olFolder = olNS.GetDefaultFolder(OlDefaultFolders.olFolderInbox)
            olFolder.Display()
            olExplorer = CType(olApp.ActiveWindow, Microsoft.Office.Interop.Outlook.Explorer)
            olExplorer.WindowState = Microsoft.Office.Interop.Outlook.OlWindowState.olMaximized
            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(olApp)
            Marshal.ReleaseComObject(olExplorer)
            Marshal.ReleaseComObject(olFolder)
            Marshal.ReleaseComObject(olNS)
            GC.Collect()

        End Sub


        Private Sub olApp_Quit() Handles olApp.Quit
            MsgBox("Outlook shutdown")
            Dispose()

        End Sub
0
 
Bob LearnedCommented:
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
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

  • 6
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now