Вопрос по vb.net, excel, garbage-collection, interop – Процесс Excel все еще выполняется после закрытия в VB.net

4

Мой вопрос в основном только о том, как завершить процесс Excel.exe, который запускается при использовании Excel. В приложении я открываю и использую книгу Excel с несколькими листами, а затем оставляю их на усмотрение пользователя, моя проблема в том, что мое приложение никогда не отпускает процесс Excel.

Если приложение закрывается до закрытия Excel, процесс завершается при закрытии Excel, в противном случае, если я закрываю свое приложение после закрытия Excel, процесс продолжает работать.

Я попробовал несколько вещей, которые я нашел в Интернете, чтобы сделать с GC.collect и ждать ожидающих финализаторов или чего-то в этом роде, но ни одна из них не работала.

Я также могу благополучно закрыть процесс Excel, единственная проблема заключается в том, чтобы не знать, закрываю ли я важную для пользователей электронную таблицу, которую они еще не сохранили, или мою.

Я не уверен, что какой-либо мой код поможет с ответом, но я использую microsoft.office.interop.excel, чтобы добиться успеха, и я использую рабочую книгу, уже сохраненную в папке ресурсов приложения.

-Редактировать-

Вот все, что я пробовал, я знаю, что это немного излишне, но, к сожалению, это все еще не заканчивает процесс

Marshal.ReleaseComObject(FirstWorksheet)
Marshal.FinalReleaseComObject(FirstWorksheet)
Marshal.ReleaseComObject(SecondWorksheet)
Marshal.FinalReleaseComObject(SecondWorksheet)
Marshal.ReleaseComObject(ThirdWorksheet)
Marshal.FinalReleaseComObject(ThirdWorksheet)
Marshal.ReleaseComObject(FourthWorkSheet)
Marshal.FinalReleaseComObject(FourthWorkSheet)
Marshal.ReleaseComObject(xlRange)
Marshal.FinalReleaseComObject(xlRange)
Marshal.ReleaseComObject(SecondxlRange)
Marshal.FinalReleaseComObject(SecondxlRange)
Marshal.ReleaseComObject(thirdxlRange)
Marshal.FinalReleaseComObject(thirdxlRange)
Marshal.ReleaseComObject(fourthxlRange)
Marshal.FinalReleaseComObject(fourthxlRange)
Marshal.ReleaseComObject(.activeworkbook)
Marshal.FinalReleaseComObject(.activeworkbook)
Marshal.ReleaseComObject(excelApplication)
Marshal.FinalReleaseComObject(excelApplication)
MSExcelControl.QuitExcel() 'A function made by someone else I work with that was meant to close excel's process
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()

-Edit- Вот метод quitExcel

Friend Shared Sub QuitExcel()
    If Not getExcelProcessID = -1 Then
        If Not excelApp Is Nothing Then
            'Close and quit
            With excelApp
                Try
                    Do Until .Workbooks.Count = 0
                        'Close all open documents without saving
                        .Workbooks(1).Close(SaveChanges:=0)
                    Loop
                Catch exExcel As Exception
                    'Do nothing
                End Try
                Try
                    .ActiveWorkbook.Close(SaveChanges:=0)
                Catch ex As Exception
                    'Do nothing
                End Try

                Try
                    .Quit()
                Catch ex As Exception
                    'Do nothing
                Finally
                    myExcelProcessID = -1
                End Try
            End With
            excelApp = Nothing
        End If
    End If
End Sub

Он уже пытался сделать то же самое с идентификаторами процессов в своем классе, проблема была в том, что он не работал, поэтому я попытался снова получить идентификатор процесса, который сработал.

Спасибо, я посмотрю на них обоих! Alex
Можете ли вы добавить код изMSExcelControl.QuitExcel()? Это, кажется, где проблема. Enigmativity
Может представлять интерес:stackoverflow.com/questions/1610743/… Fionnuala
Также смотрите здесь:stackoverflow.com/questions/1041266/… sloth

Ваш Ответ

4   ответа
3

попробуйте использовать Marshal.ReleaseComObject для ваших объектов Excel. Он расположен в пространстве имен System.Runtime.InteropServices. Также не забудьте закрыть ваши объекты Excel заранее.

xlWorkbook.Close();
xlApp.Close();
Marshal.ReleaseComObject(xlWorkbook);
Marshal.ReleaseComObject(xlApp);
Это то, что я пытался, это все еще не работало: / Alex
4

но я наконец решил, что лучший способ сделать это - записать идентификатор процесса при создании приложения Excel, это означает, что вы знаете уникальный идентификатор, связанный только с вашим процессом.

Для этого я просмотрел все процессы, которые уже были там, записав процессы Excel & apos; Идентификаторы в массиве идентификаторов

            msExcelProcesses = Process.GetProcessesByName("Excel")
            'Get all currently running process Ids for Excel applications
            If msExcelProcesses.Length > 0 Then
                For i As Integer = 0 To msExcelProcesses.Length - 1
                    ReDim Preserve processIds(i)
                    processIds(i) = msExcelProcesses(i).Id
                Next
            End If

Затем повторите процесс сразу после открытия шахты (чтобы попытаться предотвратить их открытие в Excel и наличие 2 новых процессов Excel), запишите новые идентификаторы, проверьте идентификатор, которого не было в последнем списке, и сохраните его как целое число.

Тогда все, что вам нужно сделать в конце, это перебрать список процессов и убить тот, у которого есть ID

                Dim obj1(1) As Process
                obj1 = Process.GetProcessesByName("EXCEL")
                For Each p As Process In obj1
                    If p.Id = MSExcelControl.getExcelProcessID Then
                        p.Kill()
                    End If
                Next
Это никогда не делает хотя? Alex
Я добавил слишком много вещей в свой код, включая инструменты анализа данных для создания гистограммы и огромное количество ячеек ... Кажется, это единственный способ убить Excel. Спасибо за предоставление этого решения.
@ Энигмативность, если бы вы могли помочь больше, чем просто понизить голосование и рассказать мне вещи, которые я уже пробовал, тогда я буду очень признателен Alex
Я не думаю, что это хорошая идея. Если вы аккуратно выходите из Excel, процесс должен завершиться сам по себе.
4

что это старая ветка, но если кто-то вернется к этому, вам придется вызывать каждый объект Interop.Excel, к которому вы прикоснулись в книге. Если вы добавляете экземпляр класса из Excel в свой код, когда вы закончите с ним, Marshal.ReleaseComObject. Даже в каждой клетке. Это безумие, но это единственный способ, которым я смог решить ту же проблему.

И убедитесь, что у вас нет фатального исключения и что-то осталось невыпущенным ... Excel останется открытым.

Excel.Applicaiton? Marshal.ReleaseComObject.

Excel.Workbook? Marshal.ReleaseComObject.

Excel.Workshet? Marshal.ReleaseComObject.

Excell.Range? Marshal.ReleaseComObject.

Цикл по рядам? Marshal.ReleaseComObject каждой строки и ячейки, через которую вы проходите.

Exce.Style? Marshal.ReleaseComObject ... По крайней мере, это то, что я должен был сделать ...

Если вы планируете использовать PIA для доступа к Excel, с первой строки написанного кода спланируйте, как вы собираетесь выпускать свои объекты. Лучший подход, который у меня был, - это убедиться, что я извлекаю значение Excel из объекта Excel и загружаю его в свою собственную внутреннюю переменную. Затем немедленно позвоните Marshal.ReleaseComObject, к которому вы обращались. Как правило, сложнее всего выпустить цикл по объектам Excel через список в приложении, рабочей книге, листе, ListObject, таблице и т. Д. Следовательно, планирование довольно важно.

8

Алекс, нам не нужно этого делать, но мы делаем, EXCEL только что не закончился. Я взял ваше решение и создал приведенный ниже код. Я вызываю ExcelProcessInit перед тем, как мое приложение импортирует или экспортирует в Excel, а затем вызывает ExcelProcessKill после его завершения.

Private mExcelProcesses() As Process

Private Sub ExcelProcessInit()
  Try
    'Get all currently running process Ids for Excel applications
    mExcelProcesses = Process.GetProcessesByName("Excel")
  Catch ex As Exception
  End Try
End Sub

Private Sub ExcelProcessKill()
  Dim oProcesses() As Process
  Dim bFound As Boolean

  Try
    'Get all currently running process Ids for Excel applications
    oProcesses = Process.GetProcessesByName("Excel")

    If oProcesses.Length > 0 Then
      For i As Integer = 0 To oProcesses.Length - 1
        bFound = False

        For j As Integer = 0 To mExcelProcesses.Length - 1
          If oProcesses(i).Id = mExcelProcesses(j).Id Then
            bFound = True
            Exit For
          End If
        Next

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

Private Sub MyFunction()
  ExcelProcessInit()
  ExportExcelData() 'Whatever code you write for this...
  ExcelProcesKill()
End Sub
Это замечательно, спасибо

Похожие вопросы