Excel进程未在VB.net中关闭

jmc*_*ith 8 vb.net com excel interop

我正在使用interop.excel创建一个excel文件,并且该进程未关闭.这是我试图使用的代码.

 Private Sub converToExcel(fileLoc As String, ds As DataSet)
    Dim xlApp As Excel.Application
    Dim xlWorkBook As Excel.Workbook
    Dim xlWorkBooks As Excel.Workbooks
    Dim xlWorkSheet As Excel.Worksheet
    Dim misValue As Object = System.Reflection.Missing.Value
    Dim i As Integer
    Dim j As Integer

    xlApp = New Excel.Application
    xlWorkBooks = xlApp.Workbooks
    xlWorkBook = xlWorkBooks.Add(misValue)
    xlWorkSheet = xlWorkBook.Sheets("sheet1")

    For i = 0 To ds.Tables(0).Rows.Count - 1
        For j = 0 To ds.Tables(0).Columns.Count - 1
            xlWorkSheet.Columns.NumberFormat = "@"
            xlWorkSheet.Cells(i + 1, j + 1) = String.Format("{0}", ds.Tables(0).Rows(i).Item(j).ToString())
        Next
    Next

    xlWorkSheet.SaveAs(fileLoc)
    xlWorkBook.Close()
    xlApp.Quit()

    releaseObject(xlWorkSheet)
    releaseObject(xlWorkBook)
    releaseObject(xlWorkBooks)
    releaseObject(xlApp)

End Sub
Private Sub releaseObject(ByVal obj As Object)
    Try
        System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
        obj = Nothing
    Catch ex As Exception
        obj = Nothing
    Finally
        GC.Collect()
    End Try
End Sub
Run Code Online (Sandbox Code Playgroud)

我想我错过了COM对象,但似乎无法找到解决方案.另外作为一个注释,这是在64位Windows 8上运行.任何帮助都会很棒!谢谢

Han*_*ant 14

像这样的手动内存管理永远不会起作用.这是一个众所周知的问题,也是垃圾收集器发明的核心原因.程序员永远忘记释放内存.

当你看不到正在使用的内存时,它会变得更加困难.在您的代码中肯定是这种情况,xlWorkSheet.Cells(i + 1, j + 1)表达式使用不少于三个引用.一个用于Cells属性返回的范围对象,一个用于选择的子范围对象i+1,另一个用于选择的子范围对象j+1.VB.NET语言提供了非常好的语法糖,没有它就编写COM代码非常痛苦.但是没有帮助让你看到参考文献.您不仅无法在源代码中看到它,调试器也无法帮助您查看它们.

这在.NET中是一个非常解决的问题,它有一个垃圾收集器,它可以看到一切.最基本的问题是你没有给它机会来解决你的问题.你犯的错误就是你停了下来.可能通过在最后一个语句上设置断点,然后查看任务管理器并看到Excel.exe仍在运行.是的,这是正常的.垃圾收集不是即时的.

调用GC.Collect()应该让它立即生效,但是在运行项目的Debug构建的特定情况下这不起作用.然后将局部变量的生命周期扩展到方法的末尾,帮助您在Autos/Locals/Watch窗口中查看它们.换句话说,GC.Collect()实际上并不收集任何接口引用.更多关于这篇文章中的行为.

简单的解决方法是不要停止.继续做有用的事情,让垃圾收集器成为运行的理由.或者让程序在完成后终止,当终结器线程最后一次运行时,Excel终止.这是有效的,因为具有引用的局部变量不再在范围内.

但无论如何,每个人都想要即时修复.你可以通过删除所有releaseObject()调用来获得它.而这样做:

converToExcel(path, dset)
GC.Collect()
GC.WaitForPendingFinalizers()
Run Code Online (Sandbox Code Playgroud)

或者换句话说,在方法返回强制收集.局部变量不再在范围内,因此它们无法保留Excel引用.它现在也可以在您调试它时工作,就像您在没有调试器的情况下运行Release构建时一样.


Chr*_*uer 1

尝试 System.Runtime.InteropServices.Marshal.FinalReleaseComObject,这应该有帮助...如果我没记错的话,您还应该调用 xlWorkBook.Close() 和 xlapp.quit。首先调用它们,然后将它们设置为空。