文章编号: 317109 - 最后修改: 2006年1月23日 - 修订: 4.1

使用 Visual Studio .NET 客户端执行自动化功能后不退出 Office 应用程序

本页

展开全部 | 关闭全部

症状

使用 Microsoft Visual Basic .NET 或 Microsoft Visual C# .NET 使 Microsoft Office 应用程序执行自动化功能后,当调用 Quit 方法时,不退出 Office 应用程序。

原因

当 Visual Studio .NET 从托管代码调用 COM 对象时,它自动创建运行库可调用包装 (RCW)。RCW 封送 .NET 应用程序和 COM 对象之间的调用。RCW 保留着对 COM 对象的引用计数。因此,如果 RCW 上没有将所有引用全部释放,COM 对象就不会退出。

解决方案

要确保退出 Office 应用程序,自动化代码一定要满足以下条件:
  • 将每个对象声明为新变量。例如,将下面的代码行
    oBook = oExcel.Workbooks.Add()
    					
    更改为以下内容:
    dim oBooks as Excel.Workbooks
    oBooks = oExcel.Workbooks
    oBook = oBooks.Add()
    					
  • 停止使用某个对象时,应使用 System.Runtime.InteropServices.Marshal.ReleaseComObject。这样可以减少 RCW 的引用计数。
  • 要释放对变量的引用,请将变量设置为等于 NothingNull
  • 使用 Office 应用程序对象的 Quit 方法通知服务器关闭。

状态

这种现象是设计导致的。

更多信息

重现问题的步骤

  1. 启动 Visual Studio .NET。
  2. 文件菜单上,单击新建,然后单击项目。在 Visual Basic 项目下,选择 Windows 应用程序,然后单击确定。默认情况下会创建 Form1。
  3. 添加对 Microsoft Excel 对象库的引用。为此,请按照下列步骤操作:
    1. 项目菜单上,单击添加引用
    2. COM 选项卡上,找到 Excel 对象库,然后单击选择

      对于 Microsoft Excel 2002:Microsoft Excel 10.0 对象库

      注意:如果您尚未执行此操作,Microsoft 建议您下载并安装 Microsoft Office XP 主 Interop 程序集 (PIA)。 有关 Office XP PIA 的其他信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:
      328912? (http://support.microsoft.com/kb/328912/ ) Microsoft Office XP 主 interop 程序集 (PIA) 可供下载
      对于 Microsoft Office Excel 2003:Microsoft Excel 11.0 对象库
    3. 添加引用对话框中单击确定,接受您的选择。
  4. 视图菜单上,单击工具箱,然后将一个按钮控件拖到 Form1 上。
  5. 双击 Button1。出现该窗体的代码窗口。
  6. 将以下代码添加到 Form1.vb 的顶部:
    Imports Microsoft.Office.Interop
    					
  7. 将代码窗口中的以下代码
        Private Sub Button1_Click(ByVal sender As System.Object, _
           ByVal e As System.EventArgs) Handles Button1.Click
        End Sub
    					
    替换为:
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim oApp As New Excel.Application()
        Dim oBook As Excel.Workbook = oApp.Workbooks.Add
        Dim oSheet As Excel.Worksheet = oApp.ActiveSheet
    
        oSheet = Nothing
        oBook.Close(False)
        oBook = Nothing
        oApp.Quit()
        oApp = Nothing
    
        Debug.WriteLine("Sleeping...")
        System.Threading.Thread.Sleep(5000)
        Debug.WriteLine("End Excel")
    End Sub
    					
  8. 按 F5,运行该应用程序。
  9. 打开 Windows 任务管理器。在 Visual Studio 中,显示“输出”窗口,查看调试信息。单击命令按钮并注意 Excel.exe 的一个实例会显示在进程列表中。
  10. 即使在应用程序停止休眠后,Excel 的实例仍然会在任务列表中运行。关闭对话框并注意 Excel 会从进程列表中消失。
  11. 执行“解决办法”部分的步骤后,Office 应用程序会在释放最后一个变量后退出。将第 5 步中的函数替换为以下代码:
      Private Sub NAR(ByVal o As Object)
        Try
          System.Runtime.InteropServices.Marshal.ReleaseComObject(o)
        Catch
        Finally
          o = Nothing
        End Try
      End Sub
    
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim oApp As New Excel.Application()
        Dim oBooks As Excel.Workbooks = oApp.Workbooks
        Dim oBook As Excel.Workbook = oBooks.Add
        Dim oSheet As Excel.Worksheet = oApp.ActiveSheet
    
        NAR(oSheet)
        oBook.Close(False)
        NAR(oBook)
        NAR(oBooks)
        oApp.Quit()
        NAR(oApp)
    
        Debug.WriteLine("Sleeping...")
        System.Threading.Thread.Sleep(5000)
        Debug.WriteLine("End Excel")
    End Sub
    					
如果您正在使用 Visual C# .NET,请引用 NAR() 函数的以下代码:
private void NAR(object o)
{
    try 
    {
        System.Runtime.InteropServices.Marshal.ReleaseComObject(o);
    }
    catch {}
    finally 
    {
        o = null;
    }
}

疑难解答

请注意,如果您按照“重现此问题的步骤”一节中的说明执行操作后,服务器仍然没有关闭,则在您释放最后一个对象后,可以使用 GC.Collect()GC.WaitForPendingFinalizers() 方法。因为运行库对 RCW 执行垃圾收集,所以 GC.Collect() 方法会强制垃圾回收器运行,并且会释放 RCW 仍然拥有的任何引用。GC.Collect() 方法尝试回收可用的最大内存。注意,这不能保证所有内存都被回收。

这篇文章中的信息适用于:
  • Microsoft Visual Basic .NET 2003 标准版
  • Microsoft Visual C# .NET 2003 标准版
  • Microsoft Visual .NET 2002 标准版
  • Microsoft Visual C# .NET 2002 标准版
关键字:?
kbautomation kbprb KB317109
Microsoft和/或其各供应商对于为任何目的而在本服务器上发布的文件及有关图形所含信息的适用性,不作任何声明。 所有该等文件及有关图形均"依样"提供,而不带任何性质的保证。Microsoft和/或其各供应商特此声明,对所有与该等信息有关的保证和条件不负任何责任,该等保证和条件包括关于适销性、符合特定用途、所有权和非侵权的所有默示保证和条件。在任何情况下,在由于使用或运行本服务器上的信息所引起的或与该等使用或运行有关的诉讼中,Microsoft和/或其各供应商就因丧失使用、数据或利润所导致的任何特别的、间接的、衍生性的损害或任何因使用而丧失所导致的之损害、数据或利润不负任何责任。
 

文章翻译