简体   繁体   中英

How to get recurring appointments from Outlook interop when Outlook is open on the machine running the code?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM