单线程单元 - 无法实例化ActiveX控件

74

我需要获取HTML页面中应用的CSS样式信息。我使用了AxWebBrowser和迭代IHTMLDOMNode。我能够获取到所有需要的数据并将代码移入我的应用程序。问题是,这部分代码正在后台工作者中运行,我在尝试实例化控件时遇到了异常。

AxWebBrowser browser = new AxWebBrowser();

ActiveX control '8856f961-340a-11d0-a96b-00c04fd705a2' cannot be instantiated
because the current thread is not in a single-threaded apartment.

有没有别的解决方法或者比 AxWebBrowser 更好的选项?

4个回答

95
你遇到的问题是大多数后台线程/工作线程API将在线程上创建一个多线程公寓状态。错误消息表明该控件需要线程为单线程公寓。
您可以通过自己创建线程并在线程上指定STA公寓状态来解决此问题。
var t = new Thread(MyThreadStartMethod);
t.SetApartmentState(ApartmentState.STA);
t.Start();

1
谢谢,太好了,这个可行。还有一个问题/问题。我正在使用的类只是类,而AxWebBrowser似乎需要添加到this.Controls()中。有没有办法伪造控件?还是我需要单独为此创建一个窗体? - martin.malek
1
嗨,代码应该是 t.SetApartmentState(ApartmentState.STA); - Santiago Corredoira
谢谢,这非常有帮助! - Andrei G
2
请注意,这段代码并不足以正确实现STA线程,还必须要有一个消息循环。尤其是WebBrowser将会出现故障,无法触发其DocumentCompleted事件。请查看此帖子获取替代方案。 - Hans Passant
你如何在Compact Framework中实现这个(即Compact Framework没有[STAThread]能力)。 - bvdb
显示剩余4条评论

67

在你的应用程序的主入口处添加 [STAThread],这表示COM线程模型是单线程公寓(STA)。

例如:

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new WebBrowser());
    }
}

在框架4.5中无法工作 - 在最后一行给出了无效参数。 - pat capozzi

4
如果您在应用程序的主入口处使用了[STAThread],但仍然遇到错误,您可能需要对控件进行线程安全调用... 就像下面这样。在我遇到相同问题的情况下,以下解决方案有效!
Private void YourFunc(..)
{
    if (this.InvokeRequired)
    {
        Invoke(new MethodInvoker(delegate()
        {
           // Call your method YourFunc(..);
        }));
    }
    else
    {
        ///
    }

这里应该调用什么?浏览器吗?处于哪种状态?在我的情况下,浏览器停留在对话框上。 - C4d

0
我的问题是我将我的Main方法标记为async。所以我只需将其修复为static void,并在内部的所有可等待方法中添加.wait()即可解决它。

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