【问题标题】:.net 4.5 Excel.Application - how to cancel elegantly.net 4.5 Excel.Application - 如何优雅地取消
【发布时间】:2016-01-08 18:42:56
【问题描述】:

这是我当前的代码:我有一个构建 excel 文件的函数。 该文件只有一个工作簿和一个工作表。 这个过程大约需要 10 分钟。

我想允许用户取消此过程,而不保存文件。但如果我取消程序 excel.exe 在任务管理器中徘徊。如何优雅地退出程序?

这是我的简化代码:

Dim oExcel As Excel.Application = New Excel.Application
oExcel.Workbooks.Add()
Dim sht As New Excel.Worksheet
sht = oExcel.Worksheets.Add

如果用户取消该功能,这是我的代码:尝试优雅地退出

If BackgroundWorker1.CancellationPending Then
  e.Cancel = True
  releaseObject(sht)
  releaseObject(oExcel.ActiveWorkbook)
  releaseObject(oExcel)
  oExcel = Nothing
  GC.Collect()
  Exit Sub
End If

这是releaseObject函数

Shared Sub releaseObject(ByVal obj As Object)
    Try
        System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
        obj = Nothing
    Catch ex As Exception
        obj = Nothing
    End Try
End Sub

【问题讨论】:

  • 您是否在任何地方对 Excel 的 Application 对象调用 .Quit?见stackoverflow.com/questions/17777545/…
  • 我尝试了各种版本的 activeworkbook.close(0) 和 activeworkbook.close 或 thisworkbook.close 并添加了 oExcel.quit.. 似乎没有一个工作

标签: .net vb.net excel


【解决方案1】:

使用 Office 互操作并没有什么优雅之处,这就是为什么您应该完全避免使用它。有很多库支持对 Excel 电子表格的 DOM 级访问(如 NPOI)。

我看到你读到过关于释放 COM 对象的困难,但你错过了这里的关键:编译器持有对你永远无法释放的临时对象的隐藏引用。再加上你释放了错误的东西。加上将参数设置为Nothing 确实,讽刺的是,什么都没有。

由于您没有发布所有代码,因此我无法指出您搞砸的所有实例,但第一个实例是这样的:

oExcel.Workbooks.Add()

在这里,编译器将保存对oExcel.Workbooks 的引用,您永远不会释放它。在 .NET 中使用 COM 的一个好的经验法则是永远不要使用两个点,并以相反的创建顺序释放所有内容。

您的代码的另一个问题是这一行:

releaseObject(oExcel.ActiveWorkbook)

这是您在此处阅读有关问题的某种提示,但有点错过了重点。调用该属性实际上会返回您需要跟踪和释放的另一个实例,它不会释放之前的活动工作簿对象。

【讨论】:

  • Office 产品避免使用 COM 的另一个原因是,如果您尝试在 Web 环境中运行它们,您的代码将会崩溃并更快地烧毁。 Office 并不意味着要在服务器上运行。像 EPPluss 这样的工具是要走的路(我想 NPOI 也是如此)。
  • 哇,感谢您提供的信息。这是我知道如何生成用户可以灵活使用的数据的唯一方法。我将阅读 NPOI 并了解如何将其应用于我的解决方案谢谢!
【解决方案2】:

我最终在这里遵循指令: Excel process still runs after closing in VB.net

在创建对象之前基本上比较所有excel的processID 在我创建对象之后 这很危险,因为如果用户在此过程中打开 excel,我可能会杀死错误的...但所有其他选项似乎对我不起作用:(

    Private mAllExcelBefore() As Process
    Private Sub ExcelProcessInit()
        Try
            mAllExcelBefore = Process.GetProcessesByName("Excel")
        Catch ex As Exception
        End Try
    End Sub
    Private Sub CloseExcel()
        Dim mAllExcelAfter() As Process
        Dim bFound As Boolean
        Try
            mAllExcelAfter = Process.GetProcessesByName("Excel")
            If mAllExcelAfter.Length > 0 Then
                For i As Integer = 0 To mAllExcelAfter.Length - 1
                    bFound = False
                    For j As Integer = 0 To mAllExcelBefore.Length - 1
                        If mAllExcelAfter(i).Id = mAllExcelBefore(j).Id Then
                            bFound = True
                            Exit For
                        End If
                    Next

                    If Not bFound Then
                        mAllExcelAfter(i).Kill()
                    End If
                Next
            End If
        Catch ex As Exception
        End Try
    End Sub

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多