9

I have been trying to get appointments from outlook via the Outlook interop classes. Specifically those that are reoccurring appointments. I have tried using both v12 and v14 of the interop libraries with the same results. The following code always results in the same exception for me.

Code:

Dim pattern As Outlook.RecurrencePattern = appt.GetRecurrencePattern()
Dim recur As Microsoft.Office.Interop.Outlook.AppointmentItem = Nothing
recur = rp.GetOccurrence(Now())

Exception:

You changed one of the recurrences of this item, and this instance no longer exists. Close any open items and try again.

Note: I have used different values for the parameter to GetOccurrence, I am only using "now()" to simplify the code/problem. So I don't believe the problem lies in using Now(). I tried DateTime.Parse("8/28/2012") or DateTime.Parse("8/28/2012 5:00pm") with the name exception being thrown.

I have looked at samples from here: Question 1, Question 2. Neither seem to have the same problem. I have tried every permutation of closing objects, releasing them, and nulling (nothing) them out. (e.g. Microsoft Office Interop - Tricks and Traps). I coppied and pasted examples directly from MSDN (ex: MDSN) with the same results. I am totally out of ideas!

I am running on Windows Server 2008 R2 64bit OS, Using Visual Studio 2010, .NET 4.0, with Outlook 2007.

Here is a more complete code example which always throws the exception for me:

    Public Sub TestOutlook()
    Dim oApp As Outlook.Application = Nothing
    Dim mapiNamespace As Outlook.[NameSpace] = Nothing
    Dim calFolder As Outlook.MAPIFolder = Nothing
    Dim calItems As Outlook.Items = Nothing

    oApp = New Outlook.Application()
    mapiNamespace = oApp.GetNamespace("MAPI")
    calFolder = mapiNamespace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar)
    calItems = calFolder.Items
    calItems.IncludeRecurrences = True

    For itemIndex As Integer = 1 To calItems.Count

        Dim item As Outlook.AppointmentItem = Nothing
        item = calFolder.Items.Item(itemIndex)

        If item.IsRecurring Then
            Dim rp As Outlook.RecurrencePattern = Nothing
            rp = item.GetRecurrencePattern()
            item.Close(Outlook.OlInspectorClose.olDiscard)
            CleanUpComObject(item)
            item = Nothing
            GC.Collect()

            Try
                rp.GetOccurrence(Now)
            Catch ex As System.Exception
                Debug.WriteLine("Ex with GetOccurrence: " & ex.Message)
            End Try

        End If
        If item IsNot Nothing Then item.Close(Outlook.OlInspectorClose.olDiscard)
        CleanUpComObject(item)
        item = Nothing
        GC.Collect()
    Next

    CleanUpComObject(calItems)
    CleanUpComObject(calFolder)
    CleanUpComObject(mapiNamespace)
    oApp.Quit()
    CleanUpComObject(oApp)
    GC.Collect()
End Sub

Private Sub CleanUpComObject(obj As Object)
    Try
        If obj IsNot Nothing AndAlso System.Runtime.InteropServices.Marshal.IsComObject(obj) Then
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(obj)
            obj = Nothing
        End If
    Catch ex As System.Exception
        Debug.WriteLine("Exception in Clean up: " & ex.Message)
    End Try
End Sub

Thanks

Community
  • 1
  • 1
Sen
  • 1,438
  • 2
  • 12
  • 19
  • I would make a couple of minor change in your CleanUpComObject( ) function: Change the argument to a ByRef and set the value to Nothing in the function. That way you will never forget to set it to nothing afterwards. Change FinalReleaseComObject( ) to just ReleaseComObject( ), there's no need to force it. Finally, you don't have to call GC.Collect each time. I authored a widely used HR Outlook plugin that access tens of thousands of items without memory leaks from versions 2007 through 2013. Outlook is finicky with the COM objects being released. – Brain2000 Aug 03 '15 at 14:58

2 Answers2

11

I've been struggling with exactly the same issue for the last couple of hours, and finally I have arrived at a solution. It seems as though GetOccurrence() always throws that error unless the DateTime value that is passed matches an instance of the recurring appointment - and the thing that caught me out was that the DateTime value has to match on both Date AND Time.

Here's a version of your code that takes the time from the RecurrencePattern and adds it to the DateTime value passed to GetOccurence(), which then should correctly find any instance of the appointment that falls on the selected date.

Dim item As Outlook.AppointmentItem = Nothing 
item = calFolder.Items.Item(itemIndex) 

If item.IsRecurring Then 
    Dim rp As Outlook.RecurrencePattern = Nothing 
    rp = item.GetRecurrencePattern() 

    Dim dt2 as DateTime = DateTime.Parse("8/28/2012")
    dt2 = dt2.AddHours(item.Start.Hour)
    dt2 = dt2.AddMinutes(item.Start.Minute)
    dt2 = dt2.AddSeconds(item.Start.Second)

    item.Close(Outlook.OlInspectorClose.olDiscard) 
    CleanUpComObject(item) 
    item = Nothing 
    GC.Collect()  

    Try 
        rp.GetOccurrence(dt2)

    Catch ex1 As System.Runtime.InteropServices.COMException

// Do Nothing, let this error go.  No instance of the appointment falls on this date.

    Catch ex As System.Exception
        Debug.WriteLine("Ex with GetOccurrence: " & ex.Message) 
    End Try 

End If 

Note that I am a C# developer, so there may well be syntax errors in the above as it's an amalgamation of the OP's code and my code converted from C#, and has not been passed through a compiler.

paulH
  • 1,102
  • 16
  • 43
  • 1
    Brilliant little gotcha! GetOccurrence() apparently requires its DateTime parameter to have the same time as that of the parent appointment. – Mike K Oct 28 '12 at 07:21
  • 1
    Can you open an exception with this function, or does it only return original items? If it returns exceptions, does the time portion need to match the original time, or the exception time (assuming that was one of the changed properties)? – Brain2000 Aug 03 '15 at 14:48
  • There's a timezone catch here. If you have someone create a recurring appointment from one timezone, and then send it to someone in a different timezone, the .StartTime of the recurrence pattern object will be in the senders timezone and the .Start of the appointment item will be in the current user's timezone. So make sure you use the .Start of the appointment item, not the .StartTime of the recurrence pattern object, or the call to GetOccurrence( ) will fail. – Brain2000 Mar 31 '17 at 01:36
0

For VBA for Excel, it is stupid but simple: with .getOccurrence(x), x must be Date, not Double (and must exactly match an occurrence). dim x as Double obj.getOccurrence(x) does not work obj.getOccurrence(CDate(x)) works fine