Программа VB.NET Excel остается в Excel.EXE плавающий после завершения
Я пишу программу, которая проходит через все листы в книге Excel и сохраняет каждый лист как свою собственную книгу. Это оказалось немного сложнее, чем я ожидал, так как Sheet.Copy
метод создает странный объект (см. здесь обсуждение MSDN, которое я считаю актуальным:http://msdn.microsoft.com/en-us/library/ms178779.aspx).
так или иначе, я нашел еще один столб переполнения стека это привело меня туда, где я есть, что по существу полный, за пределами одного висящего 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
теперь я думаю, что проблема исходит из конца цикла, где я пытаюсь закрыть файл экспорта и новый рабочий лист, который он создает:
'close excel and release com objects
System.Runtime.InteropServices.Marshal.ReleaseComObject(exportsheet)
exportsheet = Nothing
xlApp1.Workbooks(fileNames(counter - 1)).Close(False)
Я не могу понять, что делать, чтобы освободить ComObject
для нового рабочего листа, который создается. Я был пробовать все виды вещей, но он всегда выдает ошибку COM, когда я это делаю, и если я пытаюсь определить его как ничего (как я делаю с exportsheet), говорит, что он читается только по умолчанию, поэтому я не могу этого сделать. Кажется, это должно быть что-то простое, как:
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp1.Workbooks(fileNames(counter - 1)))
но это не так. Я пробовал несколько вариантов этого, и я думаю, что это связано с ссылкой MSDN выше, но я не могу понять, что делать. Таким образом, код работает для моих целей, за исключением оставления одного ПРЕВОСХОДИТЬ.EXE после того, как это будет сделано.
что касается тестового файла, я просто использую файл Excel с 3 листами, и я помещаю некоторую информацию на каждый и изменяю имя листа, поэтому легко увидеть, работает ли он или нет.
любые мысли будут оценены, спасибо.
Update: я только что отключил видимость от моего основного приложения Excel, и все еще всплывают, что заставляет меня поверить, что я использую Copy
создать новое приложение Excel, но я я не совсем уверен, как ссылаться на него. Если кто знает, как отключить видимость там, это будет высоко ценится.
окончательное обновление: на случай, если какая-то бедная душа столкнулась с той же проблемой, с которой я столкнулся, первое обновление должно решить ее, но также важно отметить, что excel.ехе будет висеть, пока вы не закроете приложение. Я код автоматизации отчетов как приложение Windows form (поэтому коллеги могут указать местоположение файла и тому подобное), и там происходит чтобы быть excel.exe процесс работает, пока вы не закроете всплывающее окно из программы. Возможно, сбор мусора не запускается, пока вы не закроете окно приложения или он просто зависает на экземпляре excel.exe для какой-то другой причине.
4 ответов
Ниже приведен код, который работает для меня (обратите внимание, что я освобождаю объекты, что важно)
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
возможно, Вам потребуется сделать следующее, Если у вас есть создаваемые объекты UNREFERENCED COM:
GC.Collect()
GC.WaitForPendingFinalizers()
взято из этого сообщения форума MSDN: http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/cb5f7948-c229-483e-846b-a1cfbbcd86ca/
хорошо, это работает со мной для очень простого рабочего листа. Дайте мне знать, если у вас возникнут вопросы.
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()
к петле. Я нашел этот ответ в комментариях первый ответ на другой переполнение стека пост. В принципе, проблема у меня была в том, что рабочий лист.метод copy создает объект книги без ссылки, но оказывается, что на него можно ссылаться, ссылаясь на activesheet. Если бы ты хотел сделать с ним больше, чем просто вышвырнуть его за дверь, как я, я думаю, ты мог бы создать новый объект книги и назначить его или, как предполагает сообщение, которое я ссылаюсь, вы можете сохранить его как что-то. Для моих куколок это просто прекрасно, чтобы освободить его после сохранения рабочего листа, который я хочу, и это удалило мой excel.висит процесс exe.
Если вы хотите немного больше опции кода elgant, вы должны проверить сообщение Рона торнамбе, где он делает для каждого цикла, который мне удалось не получить правильно, а не шаткую вещь, которую я создаю. В принципе, вы хотели бы использовать его цикл в моем коде, и вы бы все готово. Спасибо, как всегда переполнение стека.