GOTCHA #68 Default apartment of main thread is inconsistent across languagesIn Example 8-3 you first marked the Main() method with the STAThread attribute, then in Example 8-4 changed it to MTAThread. What is the apartment if you do not mark Main() with either attribute? The answer, unfortunately, depends on which language you are using. Consider Example 8-5. Example 8-5. Default apartmentC# (DefaultApartment) using System; using System.Threading; namespace COMCompUser { class Test { 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()); } 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 (DefaultApartment) Imports System.Threading Module Test 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 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, the apartment attribute is not set on the Main() and Worker() methods. When you execute the code, the output differs between the languages. The output from the C# version is shown in Figure 8-8; the VB.NET output appears in Figure 8-9. Figure 8-8. Output from the C# version of Example 8-5Figure 8-9. Output from the VB.NET version of Example 8-5As you can see, the apartment of Main() is different between the C# and VB.NET versions. This is because in C#, if you don't set either STAThread or MTAThread, the apartment is first unknown. Once you access the COM component, it is set to MTA. In VB.NET, however, if you don't set either of the attributes, the compiler sets the STAThread automatically for Main(). (You'll see this if you view the MSIL for Main() with ildasm.exe.) But the apartment of the worker thread, i.e., the apartment within the Worker() method, is MTA for both languages. So the apartment of the Main() tHRead defaults to different values depending on the language used. This can be troublesome to programmers who have to maintain code in both languages. IN A NUTSHELLUnderstand the apartment in which your thread is running. Don't assume or depend on the defaults. Set it explicitly to the desired value. SEE ALSOGotcha #67, "Cross-apartment calls are expensive," Gotcha #69, "STAThread attribute may have no effect on your methods," and Gotcha #70, "Spattering access to COM components makes code hard to maintain." |