由于所有的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. } |