27

自動テスト実行アプリケーションを作成しています。アプリケーションのこの部分では、ポーリング サーバーで作業しています。Web サーバーを常にポーリングして、新しい自動テストをいつ実行する必要があるかを判断します (GUI アプリケーションの夜間の自動実行用)。

ポーリング サーバーが要求を確認すると、必要なすべての情報をダウンロードし、バックグラウンド ワーカーでテスト実行を実行します。Clipboard.Clear()問題は、テスト実行の一部に、バックグラウンド ワーカー スレッドで発生するOLE、COM、およびその他の呼び出し (たとえば、 ) があることです。これらの呼び出しのいずれかが発生すると、次の例外が発生します。

OLE 呼び出しを行う前に、現在のスレッドをシングル スレッド アパートメント (STA) モードに設定する必要があります。Main 関数に STAThreadAttribute がマークされていることを確認します。

バックグラウンドワーカースレッドをシングルスレッドアパートメントとしてマークするにはどうすればよいですか? 私の Program.cs の Main 呼び出しには、明らかにその属性が既にあります。

4

5 に答える 5

36

これは不可能です。BGW はスレッドプール スレッドを使用します。TP スレッドは常に MTA であり、変更できません。通常のスレッドを使用する必要があります。開始する前に SetApartmentState() を呼び出します。このスレッドは、Application.Run() を呼び出してメッセージ ループをポンプする必要もあります。

このコードを UI スレッドから呼び出すことを検討する必要があるかもしれません。おそらく、COM サーバーはいずれにしても UI スレッドでメソッドを実行しているためです。ワーカー スレッドから COM サーバーを作成した STA スレッドへの呼び出しのマーシャリングは自動的に行われ、COM が処理します。

または、角で雄牛を取り、自分自身をマーシャリングします。独自の STA スレッドを作成して、サーバーにハッピー ホームを与えることができます。コードはこの投稿にあります。必ず Initialize() オーバーライドで COM オブジェクトを作成してください。

于 2011-01-13T21:09:52.263 に答える
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);
    }
}

BackgroundWorker を使用する前に、次のようにデフォルトの SynchronizationContext をオーバーライドします。

   AsyncOperationManager.SynchronizationContext = new MySynchronizationContext();

注: これは、アプリケーションの残りの部分にパフォーマンスの影響を与える可能性があるため、新しい Post 実装を制限したい場合があります (たとえば、stateまたはdパラメーターを使用)。

于 2013-02-14T09:43:00.847 に答える
7

私はそれをテストしていませんが、WinForms フォームを呼び出すと、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
    });
}
于 2013-08-12T12:07:13.210 に答える
1

通常は[STAThread()]、エントリ ポイント (例: Static Main) で属性を定義して設定します。

于 2011-01-13T21:09:50.003 に答える
1

+Conrad de Wet のアイデアを使用したところ、うまくいきました。

ただし、そのコードには小さな問題が 1 つあります。「this.Invoke.....」を }); のように閉じる必要があります。

この修正を加えた Conrad de Wet のコードは次のとおりです。

    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
        });
    }
于 2014-07-08T17:30:29.637 に答える