【问题标题】:Outlook 2003 - Recurring items showing the first occurrences start/end dateOutlook 2003 - 显示第一次出现的开始/结束日期的重复项目
【发布时间】:2012-01-11 11:03:24
【问题描述】:

背景:我正在用 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");
            }
        }

【问题讨论】:

    标签: c# com outlook


    【解决方案1】:

    经过测试,我发现问题与我(或运行应用程序的人)对正在查看的用户(共享)日历的权限有关。

    它适用于第一个用户,因为在这种情况下就是我自己。之后它对用户不起作用,因为我似乎没有足够的权限(通过让我的同事更改它来确认,因此默认用户是他日历上的“所有者”并再次运行该应用程序,并且它适用于他的日历) .

    此后我尝试使用GetOccurrence(DateTime)(被一个while循环包围),但这会导致同样的问题。该函数在没有出现时会出错(如预期的那样),但当它发现出现时,它会返回一个空对象。

    但是,因为除了获取任务的开始和结束日期之外,我没有将对象用于其他任何事情,所以我手动计算了它(我有原始任务,这意味着我可以通过每天递增直到我得到一个事件,我会得到重复任务的开始日期,并使用任务的持续时间计算结束日期)。

    这不是一个理想的解决方案,但如果您只是想获得重复性任务,它很简单(但如果您有很多重复性任务并且循环很长时间,则会消耗资源)

    【讨论】:

    • 或许可以试试 Redemption(我相信有试用版)。我在使用 Exceptions 集合时遇到了类似的问题,但是打开了 RDOAppointmentItem 并使用了 RDO(不是 OOM),问题就“解决了”(当然,这也意味着我也可能有细微的 RCW 泄漏)。也许你也有类似的精彩……
    【解决方案2】:

    恐怕我看不出你的代码有明显的问题,但我希望你很清楚,可能在幕后发生了一些其他事情导致你的问题。

    我在一篇博客文章 - http://jynxeddevelopment.blogspot.com 中介绍了一些我在使用这些东西时发现的最佳实践。可能值得一读,看看是否有任何与您正在做的不同的事情,我认为“保留对所有内容的引用”部分可能会有用。

    我不确定您的 COM 对象是否会通过 GC 调用被收集,因为您没有先将它们设置为 null,但是无论哪种方式,这都不会产生影响。我在没有任何 GC 调用的情况下完成了这种工作。

    看点:

    • objOne 如果是 COM 对象,则应该释放每个循环(我希望它是)
    • 在发布之前关闭您的 Outlook 应用程序 (appOutlook.Close()),我很惊讶您没有让很多应用程序闲逛
    • 检查您在 COM 对象上使用的每个字段,如果它们也是 COM 对象,它们可能也需要完成

    抱歉,这并不具体,但使用这些东西很辛苦:/祝你好运!

    -Jynx

    【讨论】:

    • 感谢您的回复。 Unfrooutnatly 我释放了所有被调用的 COM 对象。在那之后和调用 GC 之前,我已经将它们归零。在释放、清空和调用 GC 之前,我还在 Outlook 对象上调用了 Quit 方法(我使用的是早期版本,但事实证明它通过关闭我的 Outlook 让我很恼火......)
    猜你喜欢
    • 1970-01-01
    • 2018-10-22
    • 1970-01-01
    • 2018-03-06
    • 1970-01-01
    • 2020-03-18
    • 2011-07-30
    • 1970-01-01
    • 2020-04-18
    相关资源
    最近更新 更多