C# Threading: COM Apartment Model
September 13, 2010 by
Christoff Truter
C#
Threading
Last week I encountered rather interesting issues regarding threading, .NET and
interaction with COM.
Have a look at the following console snippet:
class Program
{
static void Main(string[] args)
{
new Test().ShowDialog();
while (Console.ReadKey().Key != ConsoleKey.Enter)
{
}
}
}
The Test class is simply a windows form that contains a folder dialog which
is obviously used to select folders.
public partial class Test : Form
{
public Test()
{
InitializeComponent();
}
private void btnGo_Click(object sender, EventArgs e)
{
FolderBrowserDialog folder = new FolderBrowserDialog();
if (folder.ShowDialog() == DialogResult.OK)
{
txtPath.Text = folder.SelectedPath;
}
}
}
The preceding snippet will fail as soon as we try to access the folder dialog.
A quick solution would obviously be to simply do what the exception is telling us
to do and add the STAThread attribute above the main method.
(An assembly that references the System.Windows.Forms namespace's entry point needs to be marked with the STAThread attribute)
But in other cases - when we're working with multiple threads, like in the following
snippet, we need to set STA on the actual thread.
class Program
{
static void o()
{
new Test().ShowDialog();
}
static void Main(string[] args)
{
Thread t = new Thread(o);
t.SetApartmentState(ApartmentState.STA);
t.Start();
while (Console.ReadKey().Key != ConsoleKey.Enter)
{
}
}
}
Now you might wonder what this STAThread attribute is all about?
First of all STA (Single Threaded Apartment) relates to a threading model being used
in regards to COM objects - the folder dialog in the example makes a call to the Win32
API - which is a COM call.
I am going to attempt to explain this model by using the following crude image:
Looking at the image, notice the two silver rectangles - we call these silver blocks
apartments, now an apartment is simply a cosy little place where our com objects live.
You will also notice the abbreviation MTA (Multi Threaded Apartment) - which is the
default apartment for com objects in .net (the reason our snippets broke in the
first place)
A single threaded apartment (like the name suggests) means that only one thread is
allowed to enter our apartment at a time (kinda like a mutex)
The yellow circles represents objects within our apartment, t1 - t4 represents threads
trying to access the objects within our apartment (in this case only t4 gains access to
the objects, while t1-t3 waits in a queue).
Back in the day before threading, we didn't need our objects to be safe against
multiple processes modifying/accessing it at the same time - but as soon as multi
threading came into the picture, it became important to isolate our objects.
In addition our application may only contain one MTA (logical), while it may have multiple STA's
Here is some additional reading on the subject:
http://msdn.microsoft.com/en-us/library/ms809971.aspx
http://msdn.microsoft.com/en-us/library/ms693344(VS.85).aspx