InvalidCastException with VB .NET 2003 using Outlook 2003

G

Guest

I have an Outlook 2003 using Exchange Server 2003 Public Contacts Folder containing 20,000 Contacts. I am writing a VB .Net 2003 program that loops through all the contacts in a "for each oCt in oItems" loop. After about 250 contacts, the program gives an InvalidCastException Error on the for each loop. I notice that Outlook's memory keeps increasing (using the task manager) until it reaches around 20,000K. When I run the program a second time (without closing Outlook), I then get the error after only 1 or 2 contacts. If I close Outlook and restart it, the program will run until about 250 contacts. Here is the code

Imports System.Reflectio
Imports Outlook = Microsoft.Office.Interop.Outloo
Module Module
Sub Main(
Dim i As Intege
Dim StrName As Strin
' Create Outlook application
Dim oApp As Outlook.Application = New Outlook.Applicatio
' Get namespace and Contacts folder reference
Dim oNS As Outlook.NameSpace = oApp.GetNamespace("MAPI"
Dim cContacts = oNS.Folders.Item("Public Folders").
Folders.Item("All Public Folders").
Folders.Item("Contacts"
Dim oItems As Outlook.Items = cContacts.Item
Dim oCt As Outlook.ContactIte
For each oCt in oItem
Console.Write(CType(i, String) + " "
oCt = oItems.GetNext(
StrName = CType(oCt.EntryID, String
Console.WriteLine(StrName
oCt = Nothin
Nex
oApp = Nothin
oItems = Nothin
End Su
End Modul

Anyone have any ideas on how to fix this? Right now we have 20,000 contacts in the public folder and the response time using Outlook to find a contact is about 1-2 seconds of search time. I have no problem with Outlook accessing all 20K contacts, only using VB .NET 2003. Any solution would be helpful.
 
L

Lifeng Lu

I don't know the exactly reason of this. However, set oCt to Nothing is
unnecessary because the object won't get released until GC happens.

One way to make sure you release it is to call
Marshal.ReleaseComObject(oCt) inside the loop. But you need make sure you
don't use it after you release it.

Thanks
Lifeng
MS VB team
 
G

George McCullen

Thanks, but it does look like GC is not running fast enough to keep up. I
added to the bottom of the loop the call to GC to collect and it seems to be
running without running out of memory although it still is gaining a lot
amount of memory during the loop. It is Outlook that is having the problem,
because if I use VBA in Outlook to do the same thing, it crashes the same
way. Only in Outlook I don't have a way to force GC.

George
 
G

George McCullen

Yes, It is GC's fault and it exists in Outlook. If I port this code over to
VBA in Outlook and loop through the 20K contacts, Outlook crashes the same
way. Out of memory.... I watched it build up on the task manager to over
42,000K before it crashed. In VB .NET I added the line at the bottom of the
loop to force GC and it looped through without problem, but the memory still
built up more than it should. I don't have a way of forcing GC in Outlook
VBA, so any suggestions? Should I stay with forcing GC in VB .NET? Is the
any way to force GC in VBA?

George

George McCullen said:
I have an Outlook 2003 using Exchange Server 2003 Public Contacts
Folder containing 20,000 Contacts. I am writing a VB .Net 2003 program that
loops through all the contacts in a "for each oCt in oItems" loop. After
about 250 contacts, the program gives an InvalidCastException Error on the
for each loop. I notice that Outlook's memory keeps increasing (using the
task manager) until it reaches around 20,000K. When I run the program a
second time (without closing Outlook), I then get the error after only 1 or
2 contacts. If I close Outlook and restart it, the program will run until
about 250 contacts. Here is the code:
Imports System.Reflection
Imports Outlook = Microsoft.Office.Interop.Outlook
Module Module1
Sub Main()
Dim i As Integer
Dim StrName As String
' Create Outlook application.
Dim oApp As Outlook.Application = New Outlook.Application
' Get namespace and Contacts folder reference.
Dim oNS As Outlook.NameSpace = oApp.GetNamespace("MAPI")
Dim cContacts = oNS.Folders.Item("Public Folders"). _
Folders.Item("All Public Folders"). _
Folders.Item("Contacts")
Dim oItems As Outlook.Items = cContacts.Items
Dim oCt As Outlook.ContactItem
For each oCt in oItems
Console.Write(CType(i, String) + " ")
oCt = oItems.GetNext()
StrName = CType(oCt.EntryID, String)
Console.WriteLine(StrName)
oCt = Nothing
Next
oApp = Nothing
oItems = Nothing
End Sub
End Module

Anyone have any ideas on how to fix this? Right now we have 20,000
contacts in the public folder and the response time using Outlook to find a
contact is about 1-2 seconds of search time. I have no problem with Outlook
accessing all 20K contacts, only using VB .NET 2003. Any solution would be
helpful..
 
K

Ken Halter

Sure wish there was a notice somewhere that explained to people that VB
<> VB.Net and crossposting to both groups makes no sense.
 
J

Jay B. Harlow [MVP - Outlook]

Ken,
You did notice that George was pointing out that OUTLOOK has a problem
whether you use VBA or VB.NET.

What does not make sense is this appears to be more an Outlook problem then
a VB or VB.NET problem...

I will do a little research & see what I can find...

Just a thought
Jay
 
J

Jay B. Harlow [MVP - Outlook]

George,
Yes, It is GC's fault and it exists in Outlook. If I port this code over to
VBA in Outlook and loop through the 20K contacts, Outlook crashes the same
way. Out of memory....
If it happens in Outlook's VBA, then it has nothing to do with .NET's GC per
se. As Outlook currently does not use .NET internally!

As the KB article I posted last night indicated, this is a known issue in
Outlook. I have confirmed it is still an issue in Outlook 2003. My
understanding is that Outlook does not release the COM objects the for each
is returning until the end of the procedure.

You have a couple of problems with your loop:

The For Each itself will return the next item in the loop, "oCt =
oItems.GetNext" will return the same item.

Also as Lifeng Lu stated, setting "oCt = Nothing" does exactly that,
Nothing! The for each itself will replace the oCt reference, allowing the GC
to collect the previous item. With COM objects, such as Outlook, you should
use System.Runtime.InteropServices.Marshal.ReleaseComObject instead.
ReleaseComObject will release Outlook's external reference count on the
item. I understand that Outlook may still have an internal reference count,
hence this helps, but does not fix the problem.

Your loop would be something like:

Alternatives to the OOM (Outlook Object Model), to avoid this problem, would
be to use CDO 1.2.2, Redemption or Extended MAPI.

For a number of resources on using Outlook from .NET see:
http://www.microeye.com/resources/res_outlookvsnet.htm

I recently came across the following http://g8.cx/mapi/ "Extended MAPI with
C#" (I have not yet tried this library). The library should be usable from
VB.NET also!

Hope this helps
Jay

Hope this helps
Jay
 
K

Ken Halter

Jay said:
Ken,
You did notice that George was pointing out that OUTLOOK has a problem
whether you use VBA or VB.NET.

Doesn't matter. The subject line and all except the last sentence or two
are .Net related and I'll bet that no one has ever had an
'InvalidCastException' error in VB Classic. No one worries about "GC" in
VB Classic. If anything, the crosspost list should've included a VBA group.
 
G

George McCullen

I would like to thank all of you for your contributions to solving this
problem. Many things are apparent problems with the Outlook object library.
Memory problems being one of them. Your help is finding work arounds and
other ways to do this loop has been a great help.

I have been able to reduce the amount of memory build up using the
ReleaseComObject call and forcing GC to remove the objects.

Thanks,
George
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top