Outlook 2007 Add-in Bug with with Exchange - Long explanation

  • Thread starter Thread starter Andrew
  • Start date Start date
A

Andrew

Hello Folks: This is a strange issue which needs a long explanation!

We have an Outlook 2007 add-in written in VB.Net, which on load of Outlook
loops through all the contacts adds a property if all the criterias are met
and then closes the contact. We tested this on multiple machines with over
2000 contacts and though it took significantly longer to complete, it did not
break.

When the add-in was loaded on an Outlook install with over 1000 contacts,
that worked with exchange however, after looping through 242 contacts it
threw an error which said that "the systems administrator had limited the
amount of items that can be opened simultaneously, and that we needed to
close some items in order to get it function properly." After that error, the
calendar view broke and wasn't displaying properly and multiple other things
did not function properly.

I am closing each contact by running this line of code so that I know its
was closed by the add-in "oContact.Close(Outlook.OlInspectorClose.olSave)"
and setting "oContact = Nothing" just to be safe. That still didn't fix the
problem.

To get an idea as to what exactly was running, I added code to write to a
text file the count of each contact that was opened and closed. This I added
at the end of the loop and in a "Catch" in the event it threw the error. This
allowed me to see it was breaking after the 243 'rd contact.

So by luck I added another line in the loop which wrote to the log file.
Adding this "fixed" the problem because it successfully completed the loop
and everything worked fine on load of Outlook. The log file showed it looped
through the 1003 contacts the user had.

This user was did not have the "Cached Exchange Mode" checkbox set. When it
was set, there was no problem at all even without writing to the log file.

When it was not using the Cached Exchange Mode, it broke. My theory is that
even though I'm closing the contact, Outlook still has it open or has a
reference to it because it needs to update the information on the Exchange
Server. Hence the reason it thinks the contacts are still opened. Somehow,
the extra time needed to write to the text file gave it enough time to update
the exchange server and properly close the contact.

I hope I provided enough information to get a proper idea as to what's going
on.

Does anyone know exactly what's going on, so that I can have a proper fix
for this issue.

Regards,
 
That sounds like the RPC channel problem.

When used with Exchange there's a usual limit of roughly 255 open RPC
channels, set by a registry setting on the server. When that limit is
exhausted you see problems like those you are seeing. This is not a problem
with PST files, or usually with cached mode because that's writing locally
to the OST file and the data gets written back to the server only when the
OST is synched with the server-side mailbox.

In a loop, setting an object to Nothing will release the object, but not
necessarily release the RPC channel until the garbage collector runs. That
can be a while. So your workaround with the log probably provides enough
time (by accident) for the garbage collector to run.

Outlook will open internal object instances for every dot operator you use,
so you have to be careful with those usages since those objects won't be
released until the procedure ends. The fix for that is to explicitly declare
all objects and not to let Outlook create them for you. For example, instead
of this:

Dim value As String = folder.Items.Item(1).Body

You should use something like this:

Dim colItems As Outlook.Items = folder.Items
Dim oContact As Outlook.ContactItem = colItems.Item(1)
Dim value As String = oContact.Body

That way you can explicitly release your intermediate objects.

Also of course your contact item oContact should be declared outside the
loop, along with other objects so that you aren't creating new objects in
each loop pass, but just setting an existing object. And you should set each
object you use in the loop to Nothing in each pass through the loop.

If that isn't enough, you can also call the garbage collector on each pass
through the loop, and call WaitForPendingFinalizers. You may also need to
call Marshal.ReleaseComObject on your objects on each pass, before calling
to GC.Collect and GC.WaitForPendingFinalizers.
 
Hello Ken,

Thanks again, for the informative response/solution. All objects are
declared outside the loop, but they were not declared in the way you
suggested is best, so I'll make those changes, including the other things
you've specified and test it again to see if that fixes it.

Will post back with the results!

Regards,
Andrew
 
Back
Top