2011-01-13 121 views
25

我正在创建一个自动化的测试运行应用程序。在这部分应用程序中,我正在使用一个轮询服务器。它的工作原理是不断轮询Web服务器以确定何时应该运行新的自动化测试(对于我们的GUI应用程序的夜间自动运行)。如何将背景工作线程设置为单线程公寓?

当轮询服务器看到一个请求时,它下载所有需要的信息,然后在后台工作者中执行测试运行。问题是测试运行的一部分有后台工作线程中发生的OLE,COM和其他调用(例如,Clipboard.Clear())。当发生这些调用之一时,会发生以下异常:

在进行OLE调用之前,当前线程必须设置为单线程单元(STA)模式。确保您的Main函数具有标记的STAThreadAttribute。

如何将后台工作线程标记为单线程公寓?我的Program.cs中的Main调用显然已经具有该属性。

+0

`Clipboard.Clear()`是不是COM它是原生的Windows API – Aliostad 2011-01-13 21:08:29

+7

剪贴板使用COM进行谈判。剪贴板数据和格式 – 2011-01-13 21:11:50

回答

35

这是不可能的,BGW使用线程池线程。 TP线程始终是MTA,不能更改。您必须使用常规线程,并在启动之前调用SetApartmentState()。这个线程也应该抽取一个消息循环,调用Application.Run()。

也许你应该考虑从UI线程调用这段代码。因为很可能,COM服务器无论如何都在UI线程上运行它的方法。将工作线程调用到创建COM服务器的STA线程是自动的,COM负责处理它。

或者把牛逼的角和自己的元帅。您可以创建您自己的STA线程,为服务器提供一个快乐的家。您将在this post中找到代码,请务必在Initialize()覆盖中创建COM对象。

+1

+1 - 使用UI线程 – 2011-01-13 21:13:55

+0

我想这很有道理,因为我真的看不到用于与应用程序交互的用法, test正在运行 – KallDrexx 2011-01-13 21:22:30

1

您通常通过在入口点定义attributre [STAThread()]来设置它(例如Static Main)。

+1

这只适用于Main方法,不适用于后台任务 – 2013-02-14 19:34:16

8

BackgroundWorker默认使用ThreadPool线程,但可以覆盖此行为。首先,你需要定义一个自定义SynchronizationContext

public class MySynchronizationContext : SynchronizationContext 
{ 
    public override void Post(SendOrPostCallback d, object state) 
    { 
     Thread t = new Thread(d.Invoke); 
     t.SetApartmentState(ApartmentState.STA); 
     t.Start(state); 
    } 
} 

,并覆盖默认的SynchronizationContext,这样,你用你的BackgroundWorker之前:

AsyncOperationManager.SynchronizationContext = new MySynchronizationContext(); 

注:这可能对其余性能的影响应用程序,因此您可能希望限制新的Post实现(例如,使用状态参数)。

+0

对我无效DoWork方法仍然从MTA线程中调用 – Maxence 2015-07-10 14:41:24

3

我还没有测试过它,但是如果你调用WinForms Form,你应该回到UI线程,大部分的东西都应该重新工作。

BackgroundWorker bgw = new BackgroundWorker(); 
bgw.DoWork += new DoWorkEventHandler(this.bgw_DoWork); 
bgw.RunWorkerAsync(); 

private void bgw_DoWork(object sender, DoWorkEventArgs e) 
{ 
    // Invoke the UI thread 
    // "this" is referring to the Form1, or what ever your form is 
    this.Invoke((MethodInvoker)delegate 
    { 
     Clipboard.GetText(); 
     // etc etc 
    }); 
} 
-1

我用+康拉德德湿的想法和它的工作很棒!

虽然该代码有一个小问题,但您必须关闭“this.Invoke .....“就像一个});

这里是康拉德德湿的代码与此修复程序:

BackgroundWorker bgw = new BackgroundWorker(); 
    bgw.DoWork += new DoWorkEventHandler(this.bgw_DoWork); 
    bgw.RunWorkerAsync();> 

    private void bgw_DoWork(object sender, DoWorkEventArgs e) 
    { 
     // Invoke the UI thread 
     // "this" is referring to the Form1, or what ever your form is 
     this.Invoke((MethodInvoker)delegate 
     { 
      Clipboard.GetText(); 
      // etc etc 
     }); 
    } 
相关问题