More Outlook Resource Sites

Microsoft Developer Network (MSDN)

FAQs and other general resources

forum 25-Oct-2014 06:53

Looking for help with Outlook programming projects — VSTO, add-ins, VBA, custom Outlook forms, etc.? You′ve come to the right place!

NEW! >> Subscribe to this site via RSS. For more RSS options, see the complete list of feeds on our main news page.

Login Password
Remember me
Register | Send my password
    Page [ 1 ]  
 Outlook and .NET Printer Friendly Version
Writing code with C# and VB.NET to create Outlook add-ins and other projects
Topic
Iterate Outlook contacts stored in Exchange using VB.Net
Hello,

This is my problem:
I'm writing a VB.NET application that at some points needs to iterate through the contacts folder in Outlook. Within the VB.NET application I connect to a local Outlook instance and get its Contacts folder reference. This Contacts folder is stored in a Exchange server located at other remote computer. Then when I try to iterate through the contacts, it will go through only up to a certain point and then an error will popup. I "fixed" this error by introducing a sleep time and Application.DoEvents() in the VB.NET application for each contact that is to be retrieved. Unfortunately for around 4000 contacts it takes around 15 minutes. If I shorten the time, the error will surely show up again.

My guess is that it has something to do with synchronizing between exchange and outlook, since I'm contacting outlook to retrieve the contacts and outlook needs to contact exchange to actually retrieve the contacts. I'm not an expert on this so I'm not sure this is the issue, moreover, I've been trying to find information regarding this but no luck.

I'd really appreciate you helping me with this.

Gonzalo.

  22-Mar-2007  14:46
  22-Mar-2007  15:02   
You didn't say what the error was.

You might be running up against the 255 RPC channel limit, in which case aggressively releasing objects and running GC.Collect every 200 or so might be necessary.

Outlook does not need to contact Exchange if the user is configured for Cached Exchange mode in Outlook 2003 or later.

Have you considered going to a more performant API like Outlook Redemption?
  22-Mar-2007  21:29   
Sue,

Thank you very much. I also just realized that you had posted something related to this before.

I do the releasing of objects and GC collect at intervals of 100, everything is working fine now (no errors). Except that the process is really slow, similarly slow as before.

Do you have any idea on how to improve this? Without considering Outlook Redemption, which I also checked its features.

Thank you again.

Gonzalo.
  22-Mar-2007  21:34   
Given that you've shown no code and not given your Outlook version, it's impossible to say. We don't even have any idea of what properties you're accessing or whether SetColumns might be useful.

Redemption, though, would be faster.
  22-Mar-2007  22:10   
Sue,
Sorry for not displaying the code. Here is one of the sections in the code that needs iteration, and it's the one that's taking longer, since it has to do a Save on contacts that are read from a database and need to be in outlook contacts folder.

        Dim c As Outlook.ContactItem

        Dim dataReader As Odbc.OdbcDataReader
        Dim conn As Odbc.OdbcConnection
        Dim query As String
        conn = Utils.getConnection()

        Dim cmd As Odbc.OdbcCommand
        query = "Select tblIndividual.*"
        cmd = New Odbc.OdbcCommand(query, conn)
        dataReader = cmd.ExecuteReader()
        If Not dataReader.HasRows Then
            GoTo Final
        End If

        While dataReader.Read()
            id = Utils.getNoNullInteger32(dataReader, 0)

            countCf = countCf + 1
            If (countCf > cf.Items.Count) Then
                c = app.CreateItem(Outlook.OlItemType.olContactItem)
                c.MessageClass = "IPM.Contact"
            Else
                c = cf.Items.Item(countCf) ' Reuse a contact if already there we know that only IPM.Contact exist in the folder
            End If
            ' Create all built-in Outlook fields.
            c.Title = Utils.getNoNullString(dataReader, 1)
            '1: Title
            c.FirstName = Utils.getNoNullString(dataReader, 2)
            '2: FirstName
            ...
            c.Save()
            c = Nothing
            Marshal.ReleaseComObject(cf.Items.Item(countCf))
            If countExp Mod 100 = 0 Then
               GC.Collect()
                progress.updateProgressDlg(countExp)
                Application.DoEvents()
            End If
            countExp = countExp + 1
        End While
Final:
        ...
        Utils.releaseConnection(conn)
        Exit Sub
 
  23-Mar-2007  07:17   
I'm confused. This code bears no resemblance to your original description of iterating thousands of Outlook items. It looks like instead you're iterating a recordset and creating new items. The two are very different operations.

You also didn't say whether this is a folder in the user's mailbox or in the Public Folders collection. Such details almost always matter.

BTW, this statement is unnecessary since CreateItem always creates an item with the standard message class:

                  c.MessageClass = "IPM.Contact"

 
  23-Mar-2007  10:29   
Dear Sue,
The folder is the user's contacts folder:
        Dim cf as As Outlook.MAPIFolder
        cf = appNameSpace.GetDefaultFolderOutlook.OlDefaultFolders.olFolderContacts)

Regarding the iteration: the first time this procedure is executed, there are around 4000 contacts that need to be created (the contacts information is retrieved from a database), i.e. this will be executed 4000 times:
       c = app.CreateItem(Outlook.OlItemType.olContactItem)
Now, the second and on times, there will be some updates done to the data in the database that need to be reflected in the contacts folder for the user. Let's say we don't add nor delete any contacts, just modify some of their information, in that scenario, we would like just to reuse the contacts in outlook and overwrite the information (hence the iteration is done there):
         c = cf.Items.Item(countCf)
countCf just keeps track how many contacts are being written so far.
In this specific case, there doesn't seem to be an improvement in creating or just updating the contacts already present (updating sounded faster to me). The iteration in the database is not a problem I tested it in isolation and takes a couple of seconds.

This is one place in which I do an iteration on the contacts in outlook. In other one I want to see whether certain information is present in the contacts folder, more specifically I want to test whether there is a certain distribution list:
                For i=1 to cf.Items.Count)
                             c = cf.Items.Item(i)
                             If Utils.IsEqualStr(c.MessageClass,"IPM.DistList") Then
                                          .....
                             EndIf
                             ' Release and gc after some time
                End For

This one takes also a while to execute, but not as bad as when I have to do an update.

Thank you for your help,

Gonzalo.
  23-Mar-2007  10:41   
Why iterate 4000 items if you want to update just one? Use the MAPIFolder.Items.Find method to search on any of the common built-in properties or -- better yet -- when you create an item, record its EntryID value in your database so you can return it directly with the Namespace.GetItemFromID method.
    Page [ 1 ]