I've wasted A LOT of time trying to figure out why I was getting exception "You changed one of the recurrences of this item, and this instance no longer exists. Close any open items and try again." when running the following code:
if(appointmentItem.IsRecurring)
{
RecurrencePattern recurrencePattern = appointmentItem.GetRecurrencePattern();
DateTime first =
new DateTime(
start.Year,
start.Month,
start.Day,
appointmentItem.Start.Hour,
appointmentItem.Start.Minute,
0
);
DateTime last = end.AddDays(1).Date.AddSeconds(-1);
AppointmentItem recurringAppointment;
for (DateTime date = first; date <= last; date = date.AddDays(1))
{
try
{
// https://learn.microsoft.com/en-us/dotnet/api/microsoft.office.interop.outlook.recurrencepattern.getoccurrence?view=outlook-pia#microsoft-office-interop-outlook-recurrencepattern-getoccurrence(system-datetime)
// The GetOccurrence method generates an error if no appointment of that series exists on the specified date.
recurringAppointment = recurrencePattern.GetOccurrence(date);
dataRow =
CreateDataRowFromAppointmentItem(
recurringAppointment
);
appointments.Rows.Add(dataRow);
}
catch (System.Exception)
{
// Exception is thrown if no
continue;
}
}
}
I finally realized that if Outlook isn't open on the machine the code is running on, it works!
How are you supposed to get recurring appointments if the user has Outlook open on the same machine this code is running on?
Note: When the exception occurs it happens at the call to recurrencePattern.GetRecurrence(data)
I updated my my code to get the Application like this and all is working now:
private Result<Application> GetOutlookApplication()
{
try
{
Application outlookApplication =
Marshal.GetActiveObject(
"Outlook.Application"
) as Application;
if (outlookApplication != null)
return new Result<Application>(
outlookApplication
);
}
catch
{
}
try
{
Application outlookApplication = new Application();
//
// Microsoft says this will automatically initialize the session
// for the default profile if it isn't already initialized and
// to avoid calling Logon.
// https://learn.microsoft.com/en-us/dotnet/api/microsoft.office.interop.outlook._namespace.logon?view=outlook-pia
return new Result<Application>(outlookApplication);
}
catch (System.Exception ex)
{
return new Result<Application>()
.WithException(ex);
}
}
Getting the existing instance running if it is available did the trick. Previously I was creating a new Application object each time.