Link to home
Start Free TrialLog in
Avatar of vikky999
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 ?
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

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
Avatar of vikky999
vikky999

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.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
ASKER CERTIFIED SOLUTION
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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
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.InteropServices.Marshal.ReleaseComObject(olApp)
        End Sub

Bob
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 ?
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
   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
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