Managed and Unmanaged Threading
COM components use apartments to synchronize access to resources. In contrast, managed objects use synchronized regions, synchronization primitives such as mutexes, locks and completion ports, and synchronized contexts to ensure that all shared resources are used in a thread-safe manner. For additional information about the .NET threading model, see Threading.
For interoperability, the common language runtime creates and initializes an apartment when calling a COM object. A managed thread can create and enter a single-threaded apartment (STA) that contains only one thread, or a multi-threaded apartment (MTA) that contains one or more threads. When a COM apartment and a thread-generated apartment are compatible, COM allows the calling thread to make calls directly to the COM object. If the apartments are incompatible, COM creates a compatible apartment and marshals all calls through a proxy in the new apartment.
On the first call to unmanaged code, the runtime calls CoInitializeEx to initialize the COM apartment as either an MTA or an STA apartment. You can control the type of apartment created by setting the System.Threading.ApartmentState property on the thread to MTA, STA, or Unknown. As long as the proxy and stub are registered or the type library is registered, you do not have to set this property.
Note Some programming models require that you set the STA property on a thread. For example, for Windows Forms to initialize elements such as drag and drop, you must create and enter a single-threaded apartment.
**Note **If neither the proxy and stub nor the type library is registered, an InvalidCastException can occur when calling a COM object from managed code.
The following table lists the ApartmentState enumeration values and shows the comparable COM apartment initialization call.
ApartmentState enumeration value | COM apartment initialization |
---|---|
MTA | CoInitializeEx(NULL, COINIT_MULTITHREADED) |
STA | CoIntializeEx(NULL, COINIT_APARTMENTTHREADED) |
Unknown | CoInitializeEx(NULL, COINIT_MULTITHREADED) |
Whenever the COM object and the managed thread are in incompatible apartments, all calls on the object are made through a COM-created proxy. The following code example shows how to create an STA apartment-threaded COM object, AptSimple
, from managed code.
Imports System.Threading
Imports APTOBJLib
...
Dim obj As New AptSimple()
obj.Counter = 1
[C#] using System.Threading;
using APTOBJLib;
...
AptSimple obj = new AptSimple ();
obj.Counter = 1;
To eliminate the proxy and stub mechanism and significantly enhance performance, set the ApartmentState on the thread before creating the object.
Imports System.Threading
Imports APTOBJLib
...
Thread.CurrentThread.ApartmentState = ApartmentState.STA
Dim obj As New AptSimple()
obj.Counter = 1
[C#] using System.Threading;
using APTOBJLib;
...
Thread.CurrentThread.ApartmentState = ApartmentState.STA;
AptSimple obj = new AptSimple ();
obj.Counter = 1;
After setting the apartment state, you can check the state programmatically, as follows:
Thread.CurrentThread.ApartmentState = ApartmentState.STA
If Thread.CurrentThread.ApartmentState = ApartmentState.STA Then
'All is OK.
Else
'Incompatible apartment state.
End If
[C#] Thread.CurrentThread.ApartmentState = ApartmentState.STA;
if (Thread.CurrentThread.ApartmentState == ApartmentState.STA) {
// All is OK.
}
else {
// Incompatible apartment state.
}
A thread can only initialize a COM apartment once. Since the runtime initializes the apartment before making the very first call to unmanaged code on that thread, you should set the ApartmentState as early as possible. Changing the ApartmentState after the apartment has been initialized has no effect. You can neither un-initialize nor re-initialize an apartment. In some situations, the thread might already have called into unmanaged code before the ApartmentState could be set. In such cases, you cannot change the apartment type after the thread is initialized. Your only option is to create a new thread.
As an alternative to setting the ApartmentState enumeration, you can apply the System.STAThreadAttribute or System.MTAThreadAttribute to the main entry point of the application. By applying these attributes you ensure that the main thread of an application is in the proper state.
See Also
Advanced COM Interop | Exposing COM Components to the .NET Framework | Exposing .NET Framework Components to COM