由於所有的COM對象都會被分配到一個相應的套間裏面,因此在.NET裏面,爲了方便.NET程序調用COM對象,每一個.NET線程都會被分配到一個套間裏面――即使你沒有在代碼裏面指定線程運行的套間。在.NET線程裏面創建的COM對象都會被分配到特定的套間裏面,如果兩個.NET線程 被分配到了不同的套間裏,那麼兩個線程之間互相調用COM對象就需要列集函數調用。
在.NET 2.0以後,默認情況下.NET的線程是運行在多套間(MTA)裏面的,但是在Visual Studio裏面創建C#工程的時候,Visual Studio的項目模板會在你代碼的Main函數上加上[STAThread]屬性,表示主線程運行在STA套間裏面,這樣就會造成.NET程序有線程運行在兩個不同的套間裏面:
[STAThread] public static void Main() |
在Main函數上面加上[STAThread]屬性會使.NET將主線程放在STA套間裏面,而加上[MTAThread]屬性則會將主線程放在MTA套間裏面。
而對於其他線程,則需要使用Thread.SetApartmentState()函數來設置線程所運行的套間,而這個函數必須在線程啓動之前調用,也就是在Thread.Start ()之前調用,這也是爲什麼.NET提供一個[STAThread]屬性和[MTAThread]屬性的原因――因爲你沒有辦法在主線程啓動之前設置主線程運行的套間。在線程裏面,你可以使用Thread.GetApartmentState()函數來獲取線程所運行的套間信息。
在COM套間對.NET程序使用COM對象的影響(上)文章裏面的代碼的修復方案如下,即將主線程的STAThread屬性去掉,讓大家都運行在程序裏面唯一一個MTA套間裏面,這樣就沒有列集接口的問題了:
1. using System; 2. using System.Collections.Generic; 3. using System.Linq; 4. using System.Runtime.InteropServices; 5. using System.Text; 6. using System.Diagnostics; 7. using System.Security.Cryptography; 8. using System.Security.Principal; 9. using Microsoft.Win32.SafeHandles; 10. using System.ComponentModel; 11. using System.Reflection; 12. using System.Security; 13. using System.IO; 14. using System.Threading; 15. using System.Security.Permissions; 16. 17. using ApartmentComponentLib; 18. 19. namespace CSharpQuestions 20. { 21. public class Watcher 22. { 23. private object m_IStaObject = null; 24. 25. public static void Main() 26. { 27. Console.WriteLine(Thread.CurrentThread.GetApartmentState()); 28. Watcher watcher = new Watcher(); 29. watcher.Initialize(); 30. watcher.CreateThreads().Join(); 31. 32. Console.WriteLine("Press any key"); 33. Console.ReadLine(); 34. } 35. 36. private Thread CreateThreads() 37. { 38. Thread thread = new Thread(ThreadFunc); 39. thread.Start(); 40. 41. return thread; 42. } 43. 44. private void ThreadFunc() 45. { 46. Console.WriteLine(Thread.CurrentThread.GetApartmentState()); 47. IStaObject2 obj = (IStaObject2)m_IStaObject; 48. obj.TestMethod(); 49. } 50. 51. private void Initialize() 52. { 53. m_IStaObject = new StaObject2Class(); 54. } 55. } 56. } |