WinForms应用程序为什么默认是STAThread?

20

使用Visual Studio创建空的WinForms应用程序模板时,主应用程序类中会有STAThread属性。

我阅读了一些相关文档,但我不确定是否完全理解它。

实际上,我有一些问题:

  1. 为什么会添加这个属性?
  2. 它是什么意思?
  3. 如果删除此属性会发生什么?

2
可能是重复问题:http://stackoverflow.com/questions/102437/why-do-all-winforms-programs-require-the-stathread-attribute - Cody Gray
@Cody:是的,抱歉,我没有看到,但在我看来,这个答案比另一个更好。 - Daniel Peñalba
1
没错,这很公平。我没有投票关闭,因为那些答案并不太好。从那个问题中获取的最重要的知识点是这个链接:http://blogs.msdn.com/b/jfoscoding/archive/2005/04/07/406341.aspx - Cody Gray
1
注意事项 -> 添加到vb .net应用程序 <STAThread()> 公共子Main() - John M
4个回答

21

引用自MSDN博客

当应用 STAThreadAttribute 属性时,它会将当前线程的公寓状态更改为单线程。不详细讨论COM和线程问题,此属性确保当前线程与可能通过COM想要与之通信的其他线程之间的通信机制。当您使用Windows Forms时,根据您使用的功能,它可能需要使用COM互操作来与操作系统组件进行通信。好的例子是剪贴板和文件对话框。


如果您在回答中放置博客链接,那就太好了。 - GEOCHET

15

1. 为什么要添加这个属性?

因为它是ActiveX对象模型所需的。您可以在WinForm上放置ActiveX控件(因此它存在于兼容性方面),或者一些.NET类使用需要该属性的本机控件。

2. 它是什么意思?

它表示线程在单线程公寓模型中运行。

3. 如果删除此属性会发生什么?

如果删除属性,则行为未定义。程序可能会随机失败,并且有时会显示合理的错误消息。例如,现在可能正常工作,但在服务包中会出现问题。


1
你将遇到的最大问题是COM互操作。不要说你不会这样做或者不关心 - Windows在幕后进行了很多工作。 - Cody Gray
至少WPF拒绝在MTA中工作并立即抛出异常。WinForms也可能会这样做。 - Joey
3
不仅仅是ActiveX控件,很多其他东西都依赖于它。例如,剪贴板、拖放功能、任何像OpenFileDialog这样的shell对话框,还有很多使用COM API作为底层的.NET包装器。这些都是COM互操作,你看不到,但只能在STA线程中正常工作。即使CLR也知道这一点,例如当在UI线程上调用Thread.Join()时,它会泵送一个消息循环。 - Hans Passant

4

3. 如果您删除此属性会发生什么?

我添加了一个简单的示例来演示这个问题。

我创建了一个简单的WinForms应用程序,其中包含一个按钮和一个OpenFileDialog。在按钮点击时,我运行一个线程来显示openFileDialog。我使用STAThread和不使用STAThread启动应用程序,点击按钮的结果是相同的 - 它抛出异常“跨线程操作无效:从创建它的线程以外的线程访问控件'Form1'。” 看起来没有区别。但其实是有区别的。

然后我通过调用下面的方法来改变显示openFileDialog:

private void ShowOFD()
{
    if (InvokeRequired)
    {
        BeginInvoke(new Action(ShowOFD));
        return;
    }

    openFileDialog1.ShowDialog(this);
}

使用STAThread时,它按预期正常工作。没有STAThread时,会抛出异常:“在进行OLE调用之前,必须将当前线程设置为单线程公寓(STA)模式。确保您的Main函数已标记STAThreadAttribute。只有在调试器连接到进程时才会引发此异常。”

然后我多次启动应用程序而没有调试器(从Visual Studio分离)。有一次应用程序悄无声息地关闭,另一次应用程序带有“vshost已停止工作”的消息而关闭。


0

这意味着Windows Forms程序使用单线程公寓状态。MTA和自由线程公寓状态不受支持。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接