Outlook 2003 -显示首次出现的开始/结束日期的循环项目
本文关键字:开始 结束 日期 项目 循环 2003 显示 Outlook | 更新日期: 2023-09-27 18:16:42
Background:我正在用c#编写一个应用程序。. NET 3.5),它查看多个用户Outlook 2003日历(使用COM对象),获取约会并将这些约会的数据插入数据库。
问题:在第一个用户日历之后,任何在后续日历中重复出现的项目,将始终具有该项目第一次出现的开始和结束时间。我在用户之间释放COM对象(如果用户有很多项目),并且项目收集被正确限制(由于只有少数重复插入的任务(尽管错误的开始/结束),而不是无限的"无结束"任务)。正确的开始/结束时间是需求的一部分,为这个或另一个应用程序提供可用的信息,以计算出用户在给定的日期和工作时间范围内有多少空闲时间。
代码:(省略变量声明,它们位于相关函数的顶部)
遍历用户(in 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");
}
}
我看不出你的代码有什么明显的问题,但正如我所期望的那样,你很可能知道幕后发生了一些其他的事情,导致了你的问题。
我已经在一篇博客文章- http://jynxeddevelopment.blogspot.com中介绍了一些我在处理这些东西时发现的最佳实践。这可能值得一读,看看是否有什么东西似乎与你正在做的不同,我认为"保持引用一切"这一节可能会有用。
我不确定你的COM对象会被GC调用收集,因为你没有首先将它们设置为null,但是无论哪种方式,这都不应该有什么不同。我让这类事情不需要任何GC调用就能工作。
注意事项:
- objOne应该释放每个循环,如果它是一个COM对象(我希望它是)
- 在发布Outlook应用程序之前关闭它(appOutlook.Close()),我很惊讶你没有得到很多他们闲逛
- 检查你在COM对象上使用的每个字段,如果它们也是COM对象,它们可能也需要finalize
对不起,这是没有具体的,但工作与这些东西是艰苦的工作:/祝你好运!
-Jynx
经过测试,我发现这个问题与我(或任何运行应用程序的人)对正在查看的用户(共享)日历的权限有关。
它对第一个用户起作用,因为在这个例子中,这个用户就是我自己。在那之后,它对用户不起作用,因为我似乎没有足够的权利(通过让我的同事更改它来确认,因此默认用户是他日历上的"所有者"并再次运行应用程序,并且它为他的日历工作)。
我已经尝试使用GetOccurrence(DateTime)
(被一个while循环包围),但是这会导致同样的问题。当没有出现时(如预期的那样),该函数将出错,但当发现出现时,它将返回一个空对象。
然而,因为我没有使用对象来获取任务的开始和结束日期,所以我手动计算出它(我有原始任务,这意味着我可以获得持续时间,通过每天增加,直到我得到一个事件,我将得到循环任务的开始日期,并使用任务的持续时间我计算结束日期)。
这不是一个理想的解决方案,但如果你只是想要得到循环的任务,这是足够简单的(虽然如果你有很多循环的任务和很长一段时间的资源消耗)