Right, what a mess, really. CDO 1.2.1 that comes with Outlook is "client
side" technology, CDO 1.2.1 that comes with Exchange client is "server side"
technology. And we have CDO for Exchange (CDOEX) and CDO for Windows 2000
(CDOSYS) which is also Server side. And don't let us start about CDONTS and
CDO 1.1.
Anyway, the CDO version which comes with outlook is 'apartment' threaded,
so it runs in an STA (COM won't create an apartment threaded object in an
MTA ever), I remember there was a problem with cross-apartment marshaling in
1.2.1, but I supposed this is no longer an issue (could be wrong though).
The Exchange client version is marked 'Both', so it can run in both an STA's
and MTA's, but in .NET it's important to know what the object requirements
are, and as both support STA I would opt for STA threads anyway, unless you
make sure you are talking to the Exchange version, if you don't you are
looking for troubles, really.
Willy.
"Jay B. Harlow [MVP - Outlook]" <Ja************@tsbradley.net> wrote in
message news:%2****************@tk2msftngp13.phx.gbl...
| Willy,
|| Well, the CDO library (CDO 1.2.1) is a client side COM automation
library,
|| that means it is designed to be used from a Windows client style
|| application, not from a multi-threaded server style application.
| Actually CDO 1.2.1 is also a server side COM automation library that is
| installed as part of Exchange Server! The client (Outlook) version causes
| the afore mentioned security prompt, while the server (Exchange Server)
| version does not. The client version is STA & really doesn't like being
| started in an MTA (it appears to be a bug in the client version), while
the
| server version can run both MTA or STA (based on the apartment you start
it
| in)!
|
| In both cases CDO 1.2.1 is explicitly not supported under .NET, however
COM
| interop is. I have used CDO 1.2.1 via COM interop with great success under
| .NET 1.x, I have not converted the application to .NET 2.0 yet. I use the
| server version of CDO 1.2.1 in a mutlithreaded .NET Window Service app.
|
|
| Sean,
| Rather then start 150 threads, I normally use the thread pool, which
| implicitly limits me to about 20 connections. The rational is that with
150
| threads you have 150 open connections on the client & on the server, which
| is consuming & competing for both client & server resources, probably
| hurting performance, rather then helping. I suspect there is a "sweet"
| number between 20 & 150 that provides optimal performance. This "sweet"
| number would be based on size & shape of the server and size & shape of
the
| client, as well as possibly network size and other network/server
concurrent
| usage... Network should not affect my app as my app runs as a service on
the
| Exchange Server box, which in itself is another resource being competed
| for...
|
|| - make sure you release the COM objects and pump the message queue (by
|| calling WaitForPendingFinalizers) before returning from your thread
|| procedures, and
| In this instance I would recommend Marshal.ReleaseComObject in a loop to
| ensure that the COM objects are released (for .NET 2.0 I would recommend
| Marshal.FinalReleaseComObject).
|
| Taking into account all the potential problems that ReleaseComObject
| introduces...
|
|
http://blogs.msdn.com/yvesdolc/archi...17/115379.aspx
|
http://blogs.msdn.com/cbrumme/archiv.../16/51355.aspx
|
http://samgentile.com/blog/archive/2003/04/17/5797.aspx
|
|
|
http://msdn2.microsoft.com/en-us/lib...ct(VS.80).aspx
|
|
http://msdn2.microsoft.com/en-us/lib...ct(VS.80).aspx
|
| --
| Hope this helps
| Jay [MVP - Outlook]
| .NET Application Architect, Enthusiast, & Evangelist
| T.S. Bradley -
http://www.tsbradley.net
|
|
| "Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
| news:ea**************@TK2MSFTNGP09.phx.gbl...
|| Well, the CDO library (CDO 1.2.1) is a client side COM automation
library,
|| that means it is designed to be used from a Windows client style
|| application, not from a multi-threaded server style application. The CDO
|| library uses 'apartment' threaded objects, that means their instances
must
|| and will run in an STA thread. The only STA thread in a windows
| application
|| (by default) is the UI thread, so, if you create CDO object instances
from
|| auxiliary threads in your application, and you don't initialize these
|| threads to enter a STA, your COM objects will run in the UI thread and
| your
|| call will have to be marshaled.
|| That means that in your case you have 150 threads that do nothing else
| than
|| waiting for their calls to be serialized to the one and only STA (UI)
|| thread, I would not call this very inefficient. But there is more, you
| have
|| to make sure that the UI thread survives the other threads and that it
|| survives the finalizer thread. This is needed because the finalizer
thread
|| will have to 'finalize' the RCW's whenever you are releasing the COM
| object
|| references. Now the question is, how do you release the object
references?
|| Is this done before the thread procedure returns, or are you simply
| relying
|| on the finalizer to clean-up? If it's the latter, you are in trouble, the
|| finalizer thread will most certainly be unable to release all the RCW's
|| because the STA will be torn down before or while your finalizers run.
The
|| only option you have to solve this is:
|| - restrict the number of threads (say 2 or 3, more makes no sense,
| really),
|| - initialize them as STA threads,
|| - make sure you release the COM objects and pump the message queue (by
|| calling WaitForPendingFinalizers) before returning from your thread
|| procedures, and
|| - make sure no exceptions in your thread procedures can go unhandled.
||
|| Willy.
||
||
||
||
||
|| "Steve Smith" <st***********@shaw.ca> wrote in message
|| news:eP**************@tk2msftngp13.phx.gbl...
|||I did include the following code when launching the threads at one time,
|| but
||| have since commented it out to see if it was part of the problem.
|||
||| y.theThread.SetApartmentState(ApartmentState.STA);
|||
||| There is no contest here, just trying to get the job done in the most
||| efficient manner. The appilcation seems to work quite well. What use to
|| take
||| 45 minutes is now complete in less than 10 minutes, the only remaining
||| problem is the Application.Exit() issue I have described.
|||
||| The old single-threaded VB6 application takes close to 45 minutes to
||| complete. Some of the CDO calls are very expensive, particularly the
|| mailbox
||| Logon, so I expected that executing those calls once instead of 2 or
more
||| times would be an improvement.
|||
||| This application is run on a dedicated, well-equipped workstation, after
||| system changes have been made to a large Exchange environment. It's
|| purpose
||| is to confirm that each mailbox store on each server has mail flowing
||| between each store, as well as to and from external mail systems. It
also
||| confirms access to Public Folders, and verifies that the virus
detection
||| and notification systems are working.
|||
||| Thanks for the feedback.
|||
||| Steve
|||
|||
||| "Willy Denoyette [MVP]" <wi*************@telenet.be> wrote in message
||| news:un**************@TK2MSFTNGP14.phx.gbl...
||| >
||| > Are you sure all of your threads have entered the STA? This is
required
|| by
||| > CDO.
||| > Note that I see no reason at all to have 150 threads, and all
reporting
||| > back
||| > to the UI thread, is this part of a contest or what? You are just
|| wasting
||| > 150MB of memory for the thread stacks and you waste a lot of CPU
|| resources
||| > just to switch the threads which will just slow down the whole
||| > application.
||| >
||| >
||| > Willy.
||| >
||| > "Steve Smith" <st***********@shaw.ca> wrote in message
||| > news:uI**************@TK2MSFTNGP09.phx.gbl...
||| > |I have written a winforms application that launches approximately 150
||| > | threads with
||| > | Thread.ThreadStart()
||| > |
||| > | Each thread uses CDO 1.21 to logon to a different Exchange mailbox
| and
||| > | send/receive a number of mail messages, reporting back to the UI
|| thread
||| > | through the use of a Queue object. When all messages that are
| expected
||| > have
||| > | been received, each thread sends a final update to the UI and the
|| method
||| > | should exit, which should terminate the thread.
||| > |
||| > | Everything works well for the most part, although I am doing battle
|| with
||| > the
||| > | Outlook Security dialog on some mailboxes.
||| > |
||| > | When all threads have completed their work, the Exit button on the
UI
|| is
||| > | enabled. When I click it, the Application.Exit() function is called,
|| and
||| > the
||| > | UI disappears, but the application continues to run. In the debug
||| > | environment eventually I get a thread deadlock message. At this
| point,
||| > there
||| > | should only be one thread running.
||| > |
||| > | I have read numerous articles on threading and examined many samples
|| and
||| > | cannot see anything wrong with the way I have coded this
application.
||| > |
||| > | If anyone has experienced this type of problem, or has a suggestion
| on
||| > how
||| > I
||| > | could try to nail this down, I would appreciate it. Is it possible
| the
||| > CDO
||| > | object is part of the problem?
||| > |
||| > | Thanks in advance
||| > |
||| > | Steve
||| > |
||| > |
||| > |
||| > |
||| >
||| >
|||
|||
||
||
|
|