公寓状态为假人

我刚刚纠正了一个错误使用这个:

_Thread.SetApartmentState(ApartmentState.STA); 

现在我想了解它是什么意思,为什么它的作品!

COM是.NET的祖父。 他们有很高的目标,COM做的事情之一,但是.NET完全跳过了,为一个类提供线程保证。 一个COM类可以发布它有什么样的线程要求。 COM基础结构确保满足这些要求。

在.NET中完全不存在。 你可以在多个线程中使用Queue <>对象,但是如果你没有正确locking,你的代码中会有一个非常难以诊断的恶意错误。

COM线程的确切细节太大,不适合在一个职位。 我将专注于您的问题的具体情况。 创buildCOM对象的线程必须告诉COM对于具有受限制的线程选项的COM类给予什么样的支持。 绝大多数这些类只支持所谓的“公寓线程”,它们的接口方法只能从创build实例的相同线程安全地调用。 换句话说,他们宣布“我不支持任何线程,请注意不要从错误的线程调用我”。 即使客户端代码实际上从另一个线程调用它。

STA(Single Threaded Apartment)和MTA有两种。 它是在CoInitializeEx()调用中指定的,该函数必须由任何对COM执行任何操作的线程调用。 CLR在启动线程时自动进行该调用。 对于程序的主启动线程,它将获得从Main()方法的[STAThread]或[MTAThread]属性传递的值。 默认是MTA。 对于您自己创build的线程,由您对SetApartmentState()的调用确定。 默认是MTA。 线程池线程总是MTA,不能改变。

Windows中有很多需要STA的代码。 值得注意的例子是剪贴板,拖放和shell对话框(如OpenFileDialog)。 WPF或Windows窗体项目的UI线程应始终为STA,就像创build窗口的任何线程一样。

您对COM所做的承诺,即您的线程是STA,但要求您遵循单线程的公寓合同。 他们非常的僵硬,当你违约时你可以很难诊断麻烦。 要求是你永远不会阻塞线程的任何时间,并且你泵送一个消息循环。 后者的要求是通过WPF或Winforms的UI线程来实现的,但是如果您创build自己的STA线程,则需要自己处理。 破坏合同的常见诊断是僵局。

CLR中有相当多的支持来支持这些要求,帮助你摆脱困境。 例如, locking语句将在STA线程上阻塞时抽取消息循环。 大多数同步类也是如此,互斥是一个明显的例外。 然而,这只是照顾永不阻止的要求,您仍然需要创build自己的消息循环。 Application.Run()在WPF和Winforms中。

我之前提供了一个答案,其中包含了有关使消息循环保持COM快乐的重要性的更多细节。 你会在这里find这个职位 。