I've been working pretty intensively with COM Interop lately - especially in conjunction with an add-in that I've written that integrates with Outlook. This particular add-in has the need to run asynchronously and multi-threaded within Outlook, while at the same time interacting with COM components. For those uninitiated, COM components have several threading models, single threaded, free threaded, both threaded, neutral threaded, etc. Each of these apartment models has different characteristics and advantages and disadvanges, a topic I won't be covering to any appreciable depth here. Suffice it to say, when interacting with COM components from .NET, you have to be sure that the thread is running in the appropriate apartment state in order to interact with the component.
The two threading apartment states for .NET components are STA (Single Threaded Apartment) and MTA (Multi Threaded Apartment). Many components (especially those targeted to be consumed by VB.NOT (e.g. VB 6.0 and prior)) are intended to be run in a single-threaded apartment.
As it turns out, you can only set the ApartmentState property of a thread once (thereafter the property is readonly). Therefore, care must be taken when calling STA components from an MTA thread.
My solution below, basically creates a new thread (if necessary) to run an STA component. The calling thread effectively waits for the component to finish before continuing.
internal void DoWork() {
if ( ApartmentState.STA != Thread.CurrentThread.ApartmentState ) {
Thread staThread = new Thread(new ThreadStart(doActualWork));
staThread.ApartmentState = ApartmentState.STA;
staThread.Start();
staThread.Join();
}
else {
// we're already running in an STA apartment so it's ok to call the method as-is
doActualWork();
}
}
private void doActualWork() {
}