Outlook 2003 - повторяющиеся элементы, показывающие дату начала / окончания первого вхождения - PullRequest
4 голосов
/ 02 декабря 2011

Справочная информация : я пишу приложение на C # (.NET 3.5), которое просматривает календари Outlook 2003 для нескольких пользователей (с использованием объектов COM), получает встречи и вставляет данные для этих встреч в база данных.

Проблема: После календаря первых пользователей любые повторяющиеся элементы в следующих календарях всегда будут иметь время начала и окончания первого появления этого элемента. Я выпускаю COM-объекты между пользователями (и во время, если у пользователя много элементов), и коллекция элементов корректно ограничена (из-за того, что была вставлена ​​лишь небольшая часть повторяющихся задач (хотя и неправильный запуск / конец) вместо бесконечных из "без конца" задач). Правильное время начала / окончания является частью требований, имеющих информацию, доступную для того или иного приложения, чтобы определить, сколько свободного времени у пользователя для заданного диапазона дат и рабочих часов.

Код: (объявления переменных опущены, они находятся вверху соответствующих функций)

Цикл по пользователям (в Main ()):

 foreach (DataRow drUserCalendar in dtCalendars.Rows)
                {
                    //for each calendar we're looking at, export their calendar data and put it in the database
                    try
                    {
                        appOutlook = new Outlook.Application();
                        ExportCalendar(drUserCalendar);
                        Marshal.FinalReleaseComObject(appOutlook);
                        GC.Collect();
                    }
                    catch (Exception ex)
                    {
                        //report error
                    }
                }

Извлечение информации из календаря

static void ExportCalendar(DataRow drUser)
        {                    
            strDisplayName = drUser["DisplayName"].ToString();
            strUserID = drUser["ID"].ToString();

            int.TryParse(drUser["PreviousDays"].ToString(), out intPrevious);
            int.TryParse(drUser["FutureDays"].ToString(), out intFuture);

            dtmAllowedPreviousStart = DateTime.Now.AddDays(-intPrevious);
            dtmAllowedFutureStart = DateTime.Now.AddDays(intFuture);

            nsOne = appOutlook.GetNamespace("MAPI");
            nsOne.Logon(null, null, false, false);
            rcpOne = nsOne.CreateRecipient(strDisplayName);

            intCount = 0;

            if (rcpOne.Resolve())
            {
                fldOne = nsOne.GetSharedDefaultFolder(rcpOne, Outlook.OlDefaultFolders.olFolderCalendar);

                strRestrict = "[Start] > '" + MIN_START_DATE.ToString("g") + "' And [End] < '" + MAX_START_DATE.ToString("g") + "'";
                itms = fldOne.Items;
                itms.Sort("[Start]", Type.Missing);
                itms.IncludeRecurrences = true;
                itmsRestricted = itms.Restrict(strRestrict);
                itmsRestricted.Sort("[Start]", Type.Missing);
                itmsRestricted.IncludeRecurrences = true;
                blnIsRecurring = false;
                dicRecurringTaskTracker = new Dictionary<string, int>();

                foreach (object objOne in itmsRestricted)
                {

                    if (intCount >= 100 || blnIsRecurring)
                    {
                        //release COM objects. Outlook doesn't like you having more than 250 ish items without cleaning up.
                        Marshal.FinalReleaseComObject(appOutlook);
                        appOutlook = new Outlook.Application();
                        GC.Collect();
                        intCount = 0;
                    }

                    if (objOne is Outlook.AppointmentItem)
                    {
                        appItem = (Outlook.AppointmentItem)objOne;
                        blnException = false;

                        //get data from the item
                        strEntryID = appItem.EntryID;
                        strSubject = appItem.Subject;
                        strBody = appItem.Body;
                        dtmStart = appItem.Start;
                        dtmEnd = appItem.End;

                        blnException = EXCEPTIONS.Contains(strSubject);

                        //if the item is an exception we're done with it.
                        if (!blnException)
                        {
                            strRecurrenceInterval = "";
                            strRecurrenceType = "";
                            strRecurrenceInfo = "";


                            //check if it's a recurring task.
                            blnIsRecurring = appItem.IsRecurring;
                            if (blnIsRecurring)
                            {
                                //check to see if we've already had a task from this series
                                if (!dicRecurringTaskTracker.Keys.Contains(strEntryID))
                                {
                                    //Start at 0 so the first (this) task
                                    //is number 1.
                                    dicRecurringTaskTracker.Add(strEntryID, 0);
                                }

                                //update number
                                dicRecurringTaskTracker[strEntryID] += 1;
                                //change the subject to add the count on the end
                                strEntryID = strEntryID + '-' + dicRecurringTaskTracker[strEntryID].ToString();

                                //it's a recurring task, so we need to find out when/how often.
                                rpTaskRecurrence = appItem.GetRecurrencePattern();
                                rtTaskRecurrenceType = rpTaskRecurrence.RecurrenceType;
                                strRecurrenceType = rtTaskRecurrenceType.ToString();
                                strRecurrenceInterval = rpTaskRecurrence.Interval.ToString();

                                switch (strRecurrenceType)
                                {
                                    case "olRecursDaily":
                                    case "olRecursMonthNth":
                                    case "olRecursWeekly":
                                        strRecurrenceInfo = rpTaskRecurrence.DayOfWeekMask.ToString();
                                        break;
                                    case "olRecursMonthly":
                                        strRecurrenceInfo = rpTaskRecurrence.DayOfMonth.ToString();
                                        break;
                                }
                            } 

                            if (strEntryID != null && strSubject != null && dtmStart != null && dtmEnd != null
                                && (intPrevious == 0 || (dtmStart > dtmAllowedPreviousStart)) && (intFuture == 0 || (dtmStart < dtmAllowedFutureStart)))
                            {
                                //build up the SQL
                                strSQL = "EXEC UpdateCalendarEntry ";
                                strSQL += "@EntryID='" + strEntryID + "', ";
                                strSQL += "@Subject='" + strSubject.Replace("'", "''") + "', ";
                                strSQL += "@Body='" + strSubject.Replace("'", "''") + "', ";
                                strSQL += "@StartDate='" + dtmStart.ToString("dd-MMM-yyyy HH:mm:ss") + "', ";
                                strSQL += "@EndDate='" + dtmEnd.ToString("dd-MMM-yyyy HH:mm:ss") + "', ";
                                strSQL += "@UserCalendarID=" + strUserID + ",";
                                strSQL += "@Recurring = " + blnIsRecurring.ToString() + ",";
                                strSQL += "@RecurrenceType = '" + strRecurrenceType + "',";
                                strSQL += "@RecurrenceInterval = '" + strRecurrenceInterval + "',";
                                strSQL += "@RecurrenceInfo = '" + strRecurrenceInfo + "';";

                                try
                                {
                                    //Execute SQL
                                }
                                catch (Exception ex)
                                {
                                    //Print error message
                                    MessageBox.Show(ex.ToString());
                                }
                            }
                        }
                        Marshal.FinalReleaseComObject(appItem);
                        GC.Collect();
                    }
                    strEntryID = null;
                    strSubject = null;
                    strBody = null;
                    intCount++;
                }

                //finished looping, do some clean up. 
                Marshal.FinalReleaseComObject(nsOne);
                Marshal.FinalReleaseComObject(rcpOne);
                Marshal.FinalReleaseComObject(fldOne);
                Marshal.FinalReleaseComObject(itms);
                Marshal.FinalReleaseComObject(itmsRestricted);
                GC.Collect();
            }
            else
            {
                throw new Exception("Could not resolve name");
            }
        }

Ответы [ 2 ]

0 голосов
/ 09 декабря 2011

После тестирования я обнаружил, что проблема связана с моими (или теми, кто запускает приложение) разрешениями для пользователей (общих) календарей, которые просматриваются.

Это работает на первом пользователе, потому что это я в этом случае. После этого он не работает для пользователей, потому что у меня нет достаточных прав, как кажется (это подтверждается тем, что мой коллега изменил его, чтобы пользователи по умолчанию стали «владельцами» в его календаре, и снова запустил приложение, и оно работает для его календаря) ,

С тех пор я пытался использовать GetOccurrence(DateTime) (окруженный циклом while), однако это привело к той же проблеме. Функция выдает ошибку, когда вхождения не было (как и ожидалось), но когда она обнаруживает вхождение, она возвращает нулевой объект.

Однако, поскольку я не использовал объект ни для чего, кроме как для получения даты начала и окончания задачи, я решил ее вручную (у меня была исходная задача, то есть я мог получить продолжительность, увеличивая каждый день до Я получаю вхождение, я получаю дату начала повторяющихся задач, и, используя продолжительность задачи, я рассчитываю дату окончания).

Это не идеальное решение, но если вы просто хотите получать повторяющиеся задачи, это достаточно просто сделать (хотя и потребляет много ресурсов, если у вас много повторяющихся задач и циклы выполняются в течение длительного периода времени)

0 голосов
/ 06 декабря 2011

Я не вижу очевидной проблемы с вашим кодом, боюсь, но, как я ожидаю, вы хорошо знаете, что, возможно, за кулисами происходят другие вещи, которые вызывают вашу проблему.

Я рассмотрелнекоторые вещи, которые я нашел наилучшей практикой, когда я работал с этим материалом в статье блога - http://jynxeddevelopment.blogspot.com. Возможно, стоит почитать, чтобы увидеть, не кажется ли что-то отличным от того, что вы делаете, я думаю, что раздел «Сохраняйтессылки на все могут быть полезны.

Я не уверен, что ваши COM-объекты будут собираться с помощью вызова GC, так как вы сначала не устанавливаете их в null, однако в любом случае это не должно иметь значения,Я получил такой вид работы без каких-либо вызовов GC.

На что нужно обратить внимание:

  • objOne должен освобождать КАЖДЫЙ цикл, если это COM-объект (я полагаю, что это так)
  • Закрывая ваше приложение Outlook перед его выпуском (appOutlook.Close ()), я удивляюсь, что вы не получаете много их висящих вокруг
  • Изучите каждое поле, которое вы используете в COM-объекте, еслиони также являются COM-объектами, и им тоже может потребоваться финализация

Извините, это ничего конкретного, но работать с этим материалом - тяжелая работа: / Удачи!

-Jynx

...