Looping through Items in Outlook 2003 and having speed issues?


Looping through contacts or other items using Outlook Object Model and C++ is faster than using C#. The primary reason being the "Interop" layer and the marshalling of data that takes place when we use C# with Outlook Object Model.

In this case I was looping through 10,000 contacts and it took me just 20-25 seconds in C++ and almost 2 minutes in C#. The challenge was to improve the performance. Here is how I did it.

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection; // to use Missing.Value
using System.IO;
using Outlook = Microsoft.Office.Interop.Outlook;

namespace ReadContact
{
    public class Program
    {
        public static void Main(string[] args)
        {
            //Holds the start time
            DateTime start;

            //Holds the end time
            DateTime end;

            // Create the Outlook application.
            Outlook.Application oApp = new Outlook.Application();

            // Get the NameSpace information.
            Outlook.NameSpace oNS = oApp.GetNamespace("MAPI");

            // Log on by using a dialog box to choose the profile.
            oNS.Logon(Missing.Value, Missing.Value, true, true);

            // Get the contacts folder
            Outlook.MAPIFolder myContacts = oNS.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts);

            // Get the items in the contact folder
            Outlook.Items myContactItems = myContacts.Items;

            // Record the start time
            start = System.DateTime.Now;

            // use SetColumns - This greatly improves performance
            myContactItems.SetColumns("CompanyName,FirstName,LastName,Email1Address,IMAddress,BusinessTelephoneNumber, HomeTelephoneNumber,MobileTelephoneNumber");

            // Use the foreach loop and get each item as an object instead of Microsoft.Office.Interop.Outlook.ContactItem
            foreach (object item in myContactItems)
            {
                //Use reflection to get the desired properties
                string FirstName = (string)GetProperty(item, "FirstName");
                string LastName = (string)GetProperty(item, "LastName");
                string HomeTelephoneNumber = (string)GetProperty(item, "HomeTelephoneNumber");
                string IMAddress = (string)GetProperty(item, "IMAddress");
                string BusinessTelephoneNumber = (string)GetProperty(item, "BusinessTelephoneNumber");
                string MobileTelephoneNumber = (string)GetProperty(item, "MobileTelephoneNumber");
                string CompanyName = (string)GetProperty(item, "CompanyName");
                string Email1Address = (string)GetProperty(item, "Email1Address");

                Console.WriteLine("First Name:" + " " + FirstName);
                Console.WriteLine("Last Name:" + " " + LastName);
                Console.WriteLine("Home Telephone Number:" + " " + HomeTelephoneNumber);
                Console.WriteLine("IM Address:" + " " + IMAddress);
                Console.WriteLine("Business Telephone Number:" + " " + BusinessTelephoneNumber);
                Console.WriteLine("Mobile Telephone Number:" + " " + MobileTelephoneNumber);
                Console.WriteLine("Company Name:" + " " + CompanyName);
                Console.WriteLine("Email Address:" + " " + Email1Address);
            }
            //Record the end time
            end = System.DateTime.Now;

            //Get the difference
            System.TimeSpan result2 = end.Subtract(start);

            //Print the time taken
            Console.WriteLine(String.Format("With SetColumns this took {0} ticks.", result2.Ticks));
            Console.WriteLine(start.ToString());
            Console.WriteLine(end.ToString());

            // Log off.
            oNS.Logoff();

            //Clean up
            oNS = null;
            myContacts = null;
            myContactItems = null;
            oApp = null;
        }

        private static object GetProperty(object targetObject,string propertyName)
        {
            return targetObject.GetType().InvokeMember(propertyName,
              System.Reflection.BindingFlags.Public |
              System.Reflection.BindingFlags.Instance |
              System.Reflection.BindingFlags.GetProperty,
              null,
              targetObject,
              null,
              System.Globalization.CultureInfo.CurrentCulture);
        }
    }
}

Although I was not able to get the exact performance that I got using C++ but results were a lot better - from 2 minutes to 55-60 seconds.

Comments (1)

  1. Itay Sagui says:

    You can greatly improve performance by caching a MethodInfo object during the reflection part. I believe that it will save the reflection engine the time it takes to "locate" the requested member….

Skip to main content