While trying to upgrade a .NET application from VS.NET 2003 to VS.NET 2005 I found I was getting a problem with creating a MAPI.Session object.
I was getting the following exception:

Searching around in www.google.co.nz and everywhere else I was finding nothing on this error.
I decided that I would simply create a new application and see if it failed.
- I opened VS.NET 2003
- I created a new console application
- I added a reference to "Microsoft CDO 1.21 Library"
- I added one line of code MAPI.Session sess = new MAPI.Session(); to my Main() routine
I then run the code and it worked fine.
So I repeated the code in VS.NET 2005
using
System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
MAPI.Session sess = new MAPI.Session();
}
}
}
I was still getting the exception. I decided to post to the New Zealand .NET User group list that I belong to - see www.dot.net.nz
I got the following response from Alex James
" I don’t know the answer, but one thing I would check is whether different thread types have an effect. I.e. is you app [MTAThread] or [STAThread]
You never know that might be the answer, the default between 2003/2005 maybe different? "
I had a look at the code that VS.NET 2003 produced and indeed it has the following attribute above the Main() procedure
[STAThread]
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
[STAThread]
static void Main(string[] args)
{
MAPI.Session sess = new MAPI.Session();
}
}
}
I added the attribute to my code and the problem was gone. So obviously the CDO 1.21 library is compiled for STAThreading and not the VS.NET 2005 default which must be MTAThread.
The following is from http://www.sellsbrothers.com/askthewonk/Secure/WhatdoestheSTAThreadattri.htm
The STAThreadAttribute marks a thread to use the Single-Threaded COM Apartment if COM is needed. By default, .NET won't initialize COM at all. It's only when COM is needed, like when a COM object or COM Control is created or when drag 'n' drop is needed, that COM is initialized. When that happens, .NET calls the underlying CoInitializeEx function, which takes a flag indicating whether to join the thread to a multi-threaded or single-threaded apartment.
A multi-threaded apartment (MTA) in COM is more efficient, since any of a number of RPC threads from a pool can be used to handle a request. However, an object on the MTA thread needs to protect itself from multiple threads accessing it at the same time, so that efficiency comes at a cost.
The single-thread apartment (STA) in COM is inherently single-threaded and therefore no additional thread synchronization is needed. The STA is implemented using the thread's Windows message queue, which is how requests to objects on an STA are serialized. Because of how the STA thread is implemented, calls to objects on that thread are serialized with Windows message handling on that thread, making sure that everything, both the COM objects and the underlying windowing objects, e.g. HWNDs, are all synchronized. This is necessary for UI-oriented COM objects, like controls and drag 'n' drop, which must also be synchronized together with the UI.
When COM is needed .NET will call CoInitializeEx, picking the MTA by default because it's more efficient. However, to get the synchronization needed for controls, windows and drag 'n' drop, you need to mark a thread's entry point with the STAThreadAttribute to let .NET know to initialize the UI thread on the STA. All of the VS.NET project templates put that attribute in to make sure you don't forget: