GOTCHA #69 STAThread attribute may have no effect on your methodsLet's continue with the discussions from Gotcha #68, "Default apartment of main thread is inconsistent across languages" You may think, "Well, I want my worker thread to be in an STA, so let me mark the method with the STAThread attribute just like it's done in Main()." Is that a good idea? Let's find out. Consider Example 8-6. Example 8-6. Effect of using the STAThreadAttributeC# (SettingApartment) using System; using System.Threading; namespace COMCompUser { class Test { [STAThread] static void Worker() { Thread currentThread = Thread.CurrentThread; Console.WriteLine("In worker thread"); Console.WriteLine("Apartment in worker is {0}", currentThread.ApartmentState.ToString()); Console.WriteLine("Creating COM object"); MyCOMCompLib.IMyComp theMyComp = new MyCOMCompLib.MyCompClass(); Console.WriteLine("Apartment in worker is {0}", currentThread.ApartmentState.ToString()); } [STAThread] static void Main(string[] args) { Thread currentThread = Thread.CurrentThread; Console.WriteLine("Apartment in main is {0}", currentThread.ApartmentState.ToString()); Console.WriteLine("Creating COM object"); MyCOMCompLib.IMyComp theMyComp = new MyCOMCompLib.MyCompClass(); Console.WriteLine("Apartment in main is {0}", currentThread.ApartmentState.ToString()); Thread workerThread = new Thread( new ThreadStart(Worker)); //Not setting IsBackground on thread intentionally workerThread.Start(); } } } VB.NET (SettingApartment) Imports System.Threading Module Test <STAThread()> _ Private Sub Worker() Dim currentThread As Thread = Thread.CurrentThread Console.WriteLine("In worker thread") Console.WriteLine("Apartment in worker is {0}", _ currentThread.ApartmentState.ToString()) Console.WriteLine("Creating COM object") Dim theMyComp As MyCOMCompLib.IMyComp _ = New MyCOMCompLib.MyCompClass Console.WriteLine("Apartment in worker is {0}", _ currentThread.ApartmentState.ToString()) End Sub <STAThread()> _ Public Sub Main() Dim currentThread As Thread = Thread.CurrentThread Console.WriteLine("Apartment in main is {0}", _ currentThread.ApartmentState.ToString()) Console.WriteLine("Creating COM object") dim theMyComp as MyCOMCompLib.IMyComp _ = new MyCOMCompLib.MyCompClass() Console.WriteLine("Apartment in main is {0}", _ currentThread.ApartmentState.ToString()) Dim workerThread As New Thread(AddressOf Worker) 'Not setting IsBackground on thread intentionally workerThread.Start() End Sub End Module In this example, you have set the STAThread attribute on the Worker() method, which is called from a separate thread. If you expect the apartment of the thread within the Worker() method to be STA, you're in for a surprise. The output from the program is shown in Figure 8-10. Figure 8-10. Output from Example 8-6Even though you have set the STAThread attribute on the Worker() method, it is running in an MTA thread. How do you make Worker() run in an STA thread? The code that does that is shown in Example 8-7. Example 8-7. Correct way to set apartment for a threadC# (SettingApartment) //... class Test { //[STAThread] static void Worker() { //... } [STAThread] static void Main(string[] args) { //... Thread workerThread = new Thread( new ThreadStart(Worker)); //Not setting IsBackground on thread intentionally workerThread.ApartmentState = ApartmentState.STA; workerThread.Start(); } } } VB.NET (SettingApartment) '... Module Test '<STAThread()> _ Private Sub Worker() '... End Sub <STAThread()> _ Public Sub Main() '... Dim workerThread As New Thread(AddressOf Worker) workerThread.ApartmentState = ApartmentState.STA 'Not setting IsBackground on thread intentionally workerThread.Start() End Sub End Module As soon as you create the thread, set the ApartmentState property on it. Don't set the STAThread attribute (or the MTAThread attribute) on methods like the Worker() method. The output from this modified version is shown in Figure 8-11. Figure 8-11. Output from Example 8-7IN A NUTSHELLFor threads that interact with COM components, set the apartment of the thread yourself; don't use method attributes to do so. SEE ALSOGotcha #67, "Cross-apartment calls are expensive," Gotcha #68, "Default apartment of main thread is inconsistent across languages," and Gotcha #70, "Spattering access to COM components makes code hard to maintain." |