title: Outlook 2003 - Recurring items showing the first occurrences start/end date
body: <p><strong>Background</strong>: I'm writing an application in C# (.NET 3.5), that looks at multiple users  Outlook 2003 calendars (using COM objects), gets the appointments and inserts the data for those appointments into a database.</p>
  
  <p><strong>Problem:</strong> After the first users calendar, any recurring items on the following calendars, will always have a start and end time of the first occurrence of that item. I'm releasing the COM Objects between users (and during, if the user has a lot of items), and The item collection is being restricted correctly (due to there only being a handful of the recurring tasks inserted (albeit the wrong start/end) instead of infinite from the "no end" tasks). The correct start/end time is part of the requirements, having the information available for this or another application to work out how much free time a user has for a given range of dates, and working hours. </p>
  
  <p><strong>Code:</strong> (Variable declarations omitted, they're at the top of the relevant functions) </p>
  
  <p>Looping through the users (in Main()):</p>
  
  <pre><code> 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
                      }
                  }
  </code></pre>
  
  <p>Extracting information from the calendar</p>
  
  <pre><code>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] &gt; '" + MIN_START_DATE.ToString("g") + "' And [End] &lt; '" + 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&lt;string, int&gt;();
  
                  foreach (object objOne in itmsRestricted)
                  {
  
                      if (intCount &gt;= 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 &amp;&amp; strSubject != null &amp;&amp; dtmStart != null &amp;&amp; dtmEnd != null
                                  &amp;&amp; (intPrevious == 0 || (dtmStart &gt; dtmAllowedPreviousStart)) &amp;&amp; (intFuture == 0 || (dtmStart &lt; 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");
              }
          }
  </code></pre>