Office 中的线程支持

更新:2007 年 11 月

本主题提供有关如何在 Microsoft Office 对象模型中支持线程处理的信息。Office 对象模型不是线程安全的,但可在 Office 解决方案中用于多个线程。Office 应用程序是组件对象模型 (COM) 服务器。COM 允许客户端在任意线程上调用 COM 服务器。对于并非线程安全的 COM 服务器,COM 提供一种序列化并发调用的机制,这样无论何时服务器上都只有一个逻辑线程在执行。此机制称为单线程单元 (STA) 模型。因为调用是序列化的,所以服务器正忙时或处理后台线程上的其他调用时调用方可能会被阻塞一段时间。

使用多线程必备的知识

若要使用多个线程,您必须至少具备以下方面的多线程处理基本知识:

  • Windows API

  • COM 多线程概念

  • 并发

  • 同步

  • 封送处理

有关多线程处理的常规信息,请参见组件中的多线程处理

Office 运行于主 STA 中。了解其含义有助于理解如何通过 Office 使用多个线程。

基本的多线程处理方案

Visual Studio Tools for Office 代码始终在主 UI 线程上运行。您可能想在一个后台线程上运行一个单独的任务,以使应用程序性能变得平稳。其目标是让人们觉得好像是在同时完成两个任务,而不是一个完成之后再完成另一个,从而将导致执行更加平稳(这是使用多线程的主要原因)。例如,您可能将事件代码放在 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 Tools for 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 对象模型支持托管的无模式窗体;但是,不应该在后台线程上使用这些窗体。

请参见

概念

在 Visual Studio 中创建 Office 解决方案

参考

线程处理(C# 编程指南)

其他资源

组件中的多线程处理

托管线程处理

多线程处理 (Visual Basic)

使用线程和线程处理