Office でのスレッドのサポート

この記事では、Microsoft Office オブジェクト モデルでのスレッド処理のサポートについて説明します。 Office オブジェクト モデルはスレッド セーフではありませんが、Office ソリューションで複数のスレッドを操作できます。 Office アプリケーションは、コンポーネント オブジェクト モデル (COM) サーバーです。 COM では、クライアントが任意のスレッドで COM サーバーを呼び出すことができます。 スレッド セーフでない COM サーバーに対しては、COM には、同時呼び出しをシリアル化して、サーバー上で一度に 1 つの論理スレッドだけが実行されるようにするメカニズムが用意されています。 このメカニズムは、シングル スレッド アパートメント (STA) モデルと呼ばれています。 呼び出しがシリアル化されるため、サーバーがビジー状態であるかバックグラウンド スレッドで他の呼び出しを処理しているときに、呼び出し元が一定期間ブロックされることがあります。

対象: このトピックの情報は、ドキュメントレベルのプロジェクトおよび VSTO アドイン プロジェクトに適用されます。 「Office アプリケーションおよびプロジェクトの種類別の使用可能な機能」を参照してください。

複数のスレッドを使用する場合に必要な知識

複数のスレッドを操作するには、マルチスレッドの次の側面について、少なくとも基本的な知識を持っている必要があります。

  • Windows APIs

  • COM マルチスレッドの概念

  • コンカレンシー

  • 同期

  • マーシャリング

    マルチスレッドの一般的な情報については、「マネージド スレッド処理」を参照してください。

    Office はメインの STA で実行されます。 これによる影響を理解することで、Office で複数のスレッドを使用する方法を理解できます。

基本的なマルチスレッドのシナリオ

Office ソリューションのコードは、常にメイン UI スレッド上で実行されます。 別のタスクをバックグラウンド スレッドで実行することで、アプリケーションのパフォーマンスを向上させたいとします。 目標は、2 つのタスクが 1 つずつ順にではなく同時に完了するように見え、その結果、実行がよりスムーズになることです (複数のスレッドを使用する主な理由)。 たとえば、メインの Excel UI スレッドにイベント コードがあるとします。バックグラウンド スレッドでは別のタスクを実行して、サーバーからデータを収集し、そのデータで Excel UI のセルを更新することができます。

Office オブジェクト モデルを呼び出すバックグラウンド スレッド

バックグラウンド スレッドが Office アプリケーションの呼び出しを行うと、その呼び出しは STA の境界を越えて自動的にマーシャリングされます。 ただし、バックグラウンド スレッドによって呼び出しが行われたときに、それを Office アプリケーションで処理できる保証はありません。 いくつかの可能性があります。

  1. 呼び出しが実行に入る機会を得られるように、Office アプリケーションでメッセージをポンプする必要があります。 大量の処理を中断なく実行している場合は、これには時間がかかることがあります。

  2. 別の論理スレッドがアパートメント内に既に存在する場合、新しいスレッドは実行に入ることができません。 これは多くの場合、論理スレッドが Office アプリケーションに入ってから、呼び出し元のアパートメントに対する再入可能なコールバックを行うときに発生します。 アプリケーションは、その呼び出しが戻るのを待機してブロックされます。

  3. Excel が、受け取った呼び出しをすぐに処理できない状態になっている可能性があります。 たとえば、Office アプリケーションがモーダル ダイアログ ボックスを表示している可能性があります。

    ケース 2 および 3 に対しては、COM には IMessageFilter インターフェイスが用意されています。 サーバーがそれを実装している場合は、すべての呼び出しが HandleIncomingCall メソッドを介して実行に入ります。 ケース 2 の場合、呼び出しは自動的に拒否されます。 ケース 3 の場合、サーバーは状況に応じて呼び出しを拒否できます。 呼び出しが拒否された場合は、呼び出し元で対処方法を決定する必要があります。 通常、呼び出し元は IMessageFilter を実装しています。その場合、RetryRejectedCall メソッドによって拒否が通知されます。

    ただし、Visual Studio の Office 開発ツールを使用して作成されたソリューションの場合は、COM 相互運用機能によって、拒否されたすべての呼び出しが COMException に変換されます ("メッセージ フィルターはアプリケーションがビジーであることを示しています")。 バックグラウンド スレッドでオブジェクト モデルを呼び出す場合は常に、この例外を処理できるように準備する必要があります。 通常は、一定の時間だけ再試行してから、ダイアログを表示します。 ただし、バックグラウンド スレッドを STA として作成した後、そのスレッドでこのケースを処理するためのメッセージ フィルターを登録することもできます。

スレッドを正しく開始する

新しい STA スレッドを作成するときは、スレッドを開始する前にアパートメントの状態を STA に設定します。 これを実行する方法を次のコード例に示します。

System.Threading.Thread t = new System.Threading.Thread(AnObject.aMethod);

t.SetApartmentState(System.Threading.ApartmentState.STA);
t.Start();

詳細については、「マネージド スレッド処理のベスト プラクティス」を参照してください。

モードレス フォーム

モードレス フォームを使用すると、フォームの表示中にアプリケーションとの間で一種の対話を行うことができます。 ユーザーはフォームと対話し、フォームは閉じることなくアプリケーションと対話します。 Office オブジェクト モデルでは、マネージド モードレス フォームがサポートされています。ただし、バックグラウンド スレッドでは使用しないでください。