Программа 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, вы должны проверить сообщение Рона торнамбе, где он делает для каждого цикла, который мне удалось не получить правильно, а не шаткую вещь, которую я создаю. В принципе, вы хотели бы использовать его цикл в моем коде, и вы бы все готово. Спасибо, как всегда переполнение стека.