Office でのスレッドのサポート
このトピックでは、Microsoft Office オブジェクト モデルでスレッドをサポートする方法について説明します。Office オブジェクト モデルはスレッド セーフではありませんが、Office ソリューションでは複数のスレッドを操作できます。Office アプリケーションは、コンポーネント オブジェクト モデル (COM: Component Object Model) サーバーです。COM により、クライアントは、任意のスレッド上で COM サーバーを呼び出すことができます。スレッド セーフではない COM サーバーのために、COM には、常に 1 つの論理スレッドだけがサーバーで実行されるように同時呼び出しをシリアル化する機構が用意されています。この機構は、シングルスレッド アパートメント (STA: Single-Threaded Apartment) モデルと呼ばれます。呼び出しがシリアル化されるため、サーバーがビジー状態の場合やバックグラウンド スレッドで他の呼び出しを処理している場合は、呼び出し元がその期間ブロックされることがあります。
対象: このトピックの情報は、Office 2013 および Office 2010 のドキュメント レベルのプロジェクトおよびアプリケーション レベルのプロジェクトに適用されます。詳細については、「Office アプリケーションおよびプロジェクト タイプ別の使用可能な機能」を参照してください。
複数のスレッドを使用するときに必要な知識
複数のスレッドを使用するには、少なくとも、マルチスレッドの次の点に関する基本的な知識が必要です。
Windows API
COM マルチスレッドの概念
Concurrency
同期
マーシャリング
マルチスレッドに関する一般的な情報については、「コンポーネントのマルチスレッド」を参照してください。
Office はメイン STA で実行されます。これが意味するところを理解することにより、Office で複数のスレッドを使用する方法を理解できます。
基本的なマルチスレッドのシナリオ
Office ソリューションのコードは、常にメイン UI スレッドで実行されます。個々のタスクをバックグラウンド スレッドで実行して、アプリケーションのパフォーマンスを改善することが必要な場合があります。複数のスレッドを使用する主な目的は、タスクがさらに円滑に実行されるようにすることです。そのためには、2 つのタスクが順に実行されるのではなく、2 つのタスクが一度に完了したように見える必要があります。たとえば、Excel のメイン UI スレッドにイベント コードを配置し、バックグラウンド スレッドでは、サーバーからデータを収集してそのデータで Excel UI のセルを更新するタスクを実行するとします。
Office オブジェクト モデルを呼び出すバックグラウンド スレッド
バックグラウンド スレッドが Office アプリケーションを呼び出すと、呼び出しは STA 境界で自動的にマーシャリングされます。ただし、バックグラウンド スレッドが呼び出したときに Office アプリケーションでその呼び出しを処理できるという保証はありません。いくつかの考慮事項を次に示します。
Office アプリケーションは、入力の機会を得るために、その呼び出しのメッセージを調査する必要があります。この処理が集中的に行われ、スレッドが明け渡されないと、時間がかかることがあります。
別の論理スレッドが既にアパートメントにある場合、新しいスレッドは入ることができません。これは、論理スレッドが Office アプリケーションに入った後、再入可能な呼び出しを呼び出し元のアパートメントに戻す場合によく発生します。アプリケーションは、その呼び出しが戻るのを待っている間にブロックされます。
Excel は、受け取った呼び出しをすぐに処理できないような状態の場合があります。たとえば、Office アプリケーションはモーダル ダイアログを表示している場合があります。
考慮事項 2 と考慮事項 3 については、IMessageFilter インターフェイスが COM に用意されています。サーバーがこのインターフェイスを実装すると、すべての呼び出しが HandleIncomingCall メソッドを介して実行されます。考慮事項 2 では、呼び出しが自動的に拒否されます。考慮事項 3 では、サーバーは、状況に応じて、呼び出しを拒否できます。呼び出しが拒否された場合、呼び出し元は処理を決める必要があります。通常、呼び出し元は、IMessageFilter を実装します。この場合、RetryRejectedCall メソッドによって、拒否されたことが呼び出し元に通知されます。
ただし、Visual Studio の Office 開発ツールで作成されたソリューションの場合、COM 相互運用機能により、拒否されたすべての呼び出しが System.Runtime.InteropServices.COMException ("メッセージ フィルターはアプリケーションがビジーであることを示しています。") に変換されます。バックグラウンド スレッドでオブジェクト モデルを呼び出す場合は、この例外を処理する準備をしておく必要があります。通常、この呼び出しでは、一定時間再試行を行ってから、ダイアログを表示します。ただし、バックグラウンド スレッドを STA として作成してから、そのスレッドのメッセージ フィルターを登録してこのケースを処理することもできます。
スレッドの適切な起動
新しい STA スレッドを作成するときには、アパートメント状態を STA に設定してから、スレッドを起動する必要があります。これを実行する方法を次のコード例に示します。
Dim t As New System.Threading.Thread(AddressOf AnObject.aMethod)
t.SetApartmentState(System.Threading.ApartmentState.STA)
t.Start()
System.Threading.Thread t = new System.Threading.Thread(AnObject.aMethod);
t.SetApartmentState(System.Threading.ApartmentState.STA);
t.Start();
詳細については、「マネージ スレッド処理の実施」を参照してください。
モードレス フォーム
モードレス フォームでは、フォームが表示されている間にアプリケーションに対していくつかの種類の操作を行うことができます。ユーザーはフォームとやり取りし、フォームはアプリケーションを閉じずにアプリケーションとやり取りします。マネージ モードレス フォームは Office オブジェクト モデルでサポートされていますが、バックグラウンド スレッドでは使用しないでください。