VB.NET Excel程序完成后,EXCEL.EXE浮动
我正在编写一个程序,循环遍历Excel工作簿中的所有工作表,并将每个工作表保存为自己的工作簿。 事实certificate,比我预期的有点棘手,因为Sheet.Copy
方法创build一个奇怪的对象(请参阅这里的MSDN讨论,我认为是相关的: http : //msdn.microsoft.com/en-us/library /ms178779.aspx )。
无论如何,我发现另一个堆栈溢出的post ,让我到我所在的地方,这基本上是完整的,除了一个挂在程序完成后留下的EXCEL.EXE过程之外(检查更新的另一个问题,但我认为他们是相关的)。
这是我的代码:
Imports System.Data Imports System.IO Imports Microsoft.Office.Interop Imports Office = Microsoft.Office.Core Imports xlNS = Microsoft.Office.Interop.Excel Imports System.Runtime.InteropServices Class Form1 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 'Get information from text boxes Dim InputLocation As String Dim OutputLocation As String InputLocation = InputLoc.Text & "\" & FileName.Text If OutputLoc.Text = "" Then OutputLocation = InputLoc.Text Else OutputLocation = OutputLoc.Text End If 'Make file to save files in ' Get date and time in filename as well Dim TLDateTime As String Dim TLDay As String Dim TLMonth As Integer Dim TLYear As Integer Dim TLHour As Integer Dim TLMinute As Integer Dim TLDate As String Dim TLTime As String Dim TLSecond As Integer TLDay = DateTime.Now.Day TLMonth = DateTime.Now.Month TLYear = DateTime.Now.Year TLHour = DateTime.Now.Hour TLMinute = DateTime.Now.Minute TLSecond = DateTime.Now.Second Dim MyDate As New DateTime(TLYear, TLMonth, TLDay, TLHour, TLMinute, TLSecond) Dim MyString As String = MyDate.ToString("MMMddyyyy_HHmmss") TLDate = TLMonth.ToString + TLDay.ToString + TLYear.ToString TLTime = TLHour.ToString + TLMinute.ToString TLDateTime = TLDate + "_" + TLTime Try Directory.CreateDirectory(OutputLocation & "\" & "Field Sales Report Graphs " & TLDateTime) OutputLocation = OutputLocation & "\" & "Field Sales Report Graphs " & TLDateTime Catch MsgBox("Trying to create a file that exists, please delete it. If the file does not exist check to make sure your output location exists") End Try 'Open up excel file with information in it Dim xlApp1 As Excel.Application Dim locs As Excel.Workbook Dim exportsheet As Excel.Worksheet xlApp1 = New Excel.Application xlApp1.Visible = True xlApp1.Application.DisplayAlerts = False locs = xlApp1.Workbooks.Open(InputLocation) 'locsws = locs.ActiveSheet Dim wkshtcount = locs.Worksheets.Count - 1 Dim fileNames As New ArrayList For counter = 1 To wkshtcount + 1 'identify and copy sheet to move exportsheet = CType(locs.Worksheets(counter), Excel.Worksheet) fileNames.Add(exportsheet.Name) exportsheet.Copy(Type.Missing, Type.Missing) exportsheet = xlApp1.Workbooks("Book" & counter).Sheets(1) exportsheet.SaveAs(Filename:=OutputLocation & "\" & fileNames(counter - 1) & ".xlsx") 'close excel and release com objects System.Runtime.InteropServices.Marshal.ReleaseComObject(exportsheet) exportsheet = Nothing System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp1.ActiveWorkbook) xlApp1.ActiveWorkbook.Close(False) Next 'close excel and release com objects locs.Close(False) System.Runtime.InteropServices.Marshal.ReleaseComObject(locs) locs = Nothing xlApp1.Quit() System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp1) xlApp1 = Nothing End Sub End Class
现在我认为问题来自循环结束,我试图closures导出文件和它创build的新工作表:
'close excel and release com objects System.Runtime.InteropServices.Marshal.ReleaseComObject(exportsheet) exportsheet = Nothing xlApp1.Workbooks(fileNames(counter - 1)).Close(False)
我不知道该怎么做才能释放所创build的新工作表的ComObject
。 我一直在尝试各种各样的东西,但是当我这样做的时候总会抛出一个COM错误,如果我试图将它定义为什么(就像我对出口表格所做的那样)是说默认情况下它是只读的,所以我可以“不要这样做。 它似乎应该是这样简单的事情:
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp1.Workbooks(fileNames(counter - 1)))
但事实并非如此。 我已经尝试了几个变种,我想这是与上面的MSDN链接,但我不能完全理清该怎么做。 所以这个代码适用于我的目的,在完成之后留下一个EXCEL.EXE。
至于testing文件,我只是使用3张工作表的Excel文件,我把每个信息,并改变表名,所以很容易看到它是否工作。
任何想法,将不胜感激,谢谢。
更新:我只是从我的主Excel应用程序的能见度closures,事情仍然popup,这导致我相信,我使用Copy
的方式是创build一个新的Excel应用程序,但我不知道如何引用它。 如果有人知道如何closures能见度,那将是非常感谢。
最终更新:在一些可怜的灵魂遇到同样的问题时,第一次更新应该可以解决这个问题,但是也需要注意,excel.exe会一直挂起直到closures应用程序。 我将自动化代码报告为Windows窗体应用程序(所以同事可以给出文件位置等),并且将会运行excel.exe进程,直到您closures程序的popup窗口。 也许垃圾收集不会运行,直到您closures应用程序窗口,或者由于其他原因,它只是挂在一个excel.exe的实例。
下面是适合我的代码(注释我释放对象,这很重要)
xlWorkBook.Close() xlApp.Quit() ReleaseObject(xlWorkSheet) ReleaseObject(xlWorkBook) ReleaseObject(xlApp) 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
如果您有正在创build的未引用的COM对象,则可能需要执行以下操作:
GC.Collect() GC.WaitForPendingFinalizers()
采取从此MSDN论坛post: http : //social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/cb5f7948-c229-483e-846b-a1cfbbcd86ca/
好吧,这个工作forms为我一个非常简单的工作表。 如果您有任何问题,请告诉我。
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click 'Get information from text boxes Dim InputLocation As String Dim OutputLocation As String InputLocation = InputLoc.Text & "\" & Filename.Text If OutputLoc.Text = "" Then OutputLocation = InputLoc.Text Else OutputLocation = OutputLoc.Text End If 'Make file to save files in ' Get date and time in filename as well Dim TLDateTime As String Dim TLDay As String Dim TLMonth As Integer Dim TLYear As Integer Dim TLHour As Integer Dim TLMinute As Integer Dim TLDate As String Dim TLTime As String Dim TLSecond As Integer TLDay = DateTime.Now.Day TLMonth = DateTime.Now.Month TLYear = DateTime.Now.Year TLHour = DateTime.Now.Hour TLMinute = DateTime.Now.Minute TLSecond = DateTime.Now.Second Dim MyDate As New DateTime(TLYear, TLMonth, TLDay, TLHour, TLMinute, TLSecond) Dim MyString As String = MyDate.ToString("MMMddyyyy_HHmmss") TLDate = TLMonth.ToString + TLDay.ToString + TLYear.ToString TLTime = TLHour.ToString + TLMinute.ToString TLDateTime = TLDate + "_" + TLTime Try Directory.CreateDirectory(OutputLocation & "\" & "Field Sales Report Graphs " & TLDateTime) OutputLocation = OutputLocation & "\" & "Field Sales Report Graphs " & TLDateTime Catch MsgBox("Trying to create a file that exists, please delete it. If the file does not exist check to make sure your output location exists") End Try 'Open up excel file with information in it Dim xlApp1 As Excel.Application = New Excel.Application xlApp1.Visible = True xlApp1.Application.DisplayAlerts = False Dim locs As Excel.Workbook locs = xlApp1.Workbooks.Open(InputLocation) Dim fileNames As New ArrayList Dim counter As Integer = 1 For Each ws As Excel.Worksheet In locs.Worksheets fileNames.Add(ws.Name) ws = xlApp1.Workbooks(counter).Sheets(1) ws.SaveAs(Filename:=OutputLocation & "\" & fileNames(counter - 1) & ".xlsx") 'close excel and release com objects System.Runtime.InteropServices.Marshal.ReleaseComObject(ws) xlApp1.Workbooks(counter).Close(False) counter += 1 Next System.Runtime.InteropServices.Marshal.ReleaseComObject(locs) locs = Nothing xlApp1.Quit() System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp1) xlApp1 = Nothing End Sub
我终于遇到的解决办法是补充
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp1.ActiveWorkbook) xlApp1.ActiveWorkbook.Close()
到循环。 我在另一个堆栈溢出post的第一个答案的评论中find了这个答案。 基本上,我遇到的问题是worksheet.copy方法创build一个没有引用的工作簿对象,但事实certificate,它可以通过引用activesheet引用。 如果你想做更多的事情,而不是像我这样踢出门,我想你可以创build一个新的工作簿对象,并分配它或作为我build议链接的post,你也可以保存它。 对于我的puposes来说,在保存我想要的工作表之后释放它就好了,这样就可以去掉我的excel.exe挂起进程。
如果你想要一个更优雅的代码选项,你应该检查一下ron tornambe的post,他在哪里做每个循环,我设法得到正确的,而不是我创造的东西。 基本上,你会想在我的代码中使用他的循环,你会把它设置。 感谢一如既往的堆栈溢出。