2013-10-07 4 views
1

Я использую код followiwing сделать некоторые копирования и вставки с Excel файлов:Невозможно убить первенствует процессов

Imports Excel = Microsoft.Office.Interop.Excel 
Imports System.IO 
Imports System.Runtime.InteropServices 

Private Sub btnCombine_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCombine.Click 

    Dim xlAppSource As New Excel.Application 
    Dim xlAppTarget As New Excel.Application 
    Dim xlWbSource As Excel.Workbook 
    Dim xlWbTarget As Excel.Workbook 
    Dim xlsheetSource As Excel.Worksheet 
    Dim xlsheetTarget As Excel.Worksheet 
    Dim xlRangeSource As Excel.Range 
    Dim xlRangeTarget As Excel.Range 

    Dim Progress As Integer = 0 
    pbrProgress.Minimum = 0 
    pbrProgress.Maximum = amountOfFiles 

    btnCombine.Enabled = False 
    btnSelect.Enabled = False 
    pbrProgress.Visible = True 

    getSaveLocation() 
    MakeExcelFile() 

    'loop through all excel files to get the required data 
    For i = 0 To amountOfFiles - 1 


     Dim CurrentFile As String = strFileNames(i) 
     Dim IntAmountOfRows As Integer = amountOfRows(CurrentFile) 
     Dim intStartOfEmptyRow As Integer = amountOfRows(SummaryLocation) 

     xlAppSource.DisplayAlerts = False 
     xlAppTarget.DisplayAlerts = False 

     'Set current workbook 
     xlWbSource = xlAppSource.Workbooks.Open(CurrentFile) 
     xlWbTarget = xlAppTarget.Workbooks.Open(SummaryLocation) 

     'set current worksheet 
     xlsheetSource = xlWbSource.ActiveSheet 
     xlsheetTarget = xlWbTarget.ActiveSheet 

     'copy range of data from source to target file 
     xlRangeSource = xlsheetSource.Range("A2:k" & IntAmountOfRows) 
     xlRangeSource.Copy() 

     xlRangeTarget = xlsheetTarget.Range("A" & intStartOfEmptyRow) 
     xlRangeTarget.PasteSpecial(Excel.XlPasteType.xlPasteValues) 

     'save summary file before closing 
     xlsheetTarget.SaveAs(SummaryLocation) 

     'updating progress bar 
     Progress = Progress + 1 
     pbrProgress.Value = Progress 

    Next 

    'close excel 
    xlWbSource.Close(True) 
    xlWbTarget.Close(True) 
    xlAppSource.Quit() 
    xlAppTarget.Quit() 

    xlAppSource.DisplayAlerts = True 
    xlAppTarget.DisplayAlerts = True 


    'Cleanup 
    Marshal.ReleaseComObject(xlAppSource) 
    Marshal.ReleaseComObject(xlAppTarget) 
    Marshal.ReleaseComObject(xlWbSource) 
    Marshal.ReleaseComObject(xlWbTarget) 
    Marshal.ReleaseComObject(xlsheetSource) 
    Marshal.ReleaseComObject(xlsheettarget) 
    Marshal.ReleaseComObject(xlRangeSource) 
    Marshal.ReleaseComObject(xlRangeTarget) 

    xlAppSource = Nothing 
    xlAppTarget = Nothing 
    xlWbSource = Nothing 
    xlWbTarget = Nothing 
    xlsheetSource = Nothing 
    xlsheetTarget = Nothing 
    xlRangeSource = Nothing 
    xlRangeTarget = Nothing 

    MsgBox("Samenvoegen compleet") 

    init() 

End Sub 

Я попытался каждое решение, приведенная на SO:

  • Никогда не использовать 2 очка на линии
  • Я попытался с помощью marshall.ReleaseComObject
  • Я попытался установить объекты, «Nothing»

Однако каждый раз, когда я запускаю приложение, будет продолжаться 10-20 процессов excel.

+2

Вы забыли tmpSource и tmpTarget. Фактически, они вам не нужны, можно заменить xlWbTarget = tmpTarget.Open (SummaryLocation) с помощью xlWbTarget = xlAppTarget.Workbooks.Open (SummaryLocation). Не уверен относительно точной точки DisplayAlerts после того, как объекты были закрыты. Также вы можете раскомментировать последнюю связку Nothing (по крайней мере, объекты приложения). Если вы все это сделаете, когда вы закроете свое приложение, не будет никакого работающего процесса Excel. – varocarbas

+1

PS: Теперь я понял (после прочтения вашего комментария), что вы создаете/удаляете объекты Excel внутри цикла. Вам не нужно это делать (на самом деле ВЫСОКО НЕРАСПРОСТРАНЕННО, именно из-за проблем, связанных с выпуском объектов Excel); вы можете использовать одни и те же объекты снова и снова и только освобождать их перед закрытием приложения. Если вам нужно открыть разные окна Excel, создайте столько объектов, сколько вам нужно. – varocarbas

+0

Причина, по которой я сделал tmpTarget, состоит в том, что по другому вопросу людям было сказано никогда не использовать более 1 точки (.) С interop – Gutanoth

ответ

3
Option Explicit 

Sub Main() 

    Dim xlApp As Excel.Application 
    Set xlApp = New Excel.Application 

    xlApp.Visible = False 
    xlApp.DisplayAlerts = False 

    Dim xlWb As Workbook 
    Set xlWb = xlApp.Workbooks.Open("C:\...\path") 

    Dim xlSht As Worksheet 
    Set xlSht = xlWb.Sheets(1) 

    xlSht.Range("A1") = "message from " & ThisWorkbook.FullName 

    xlWb.Saved = True 
    xlWb.Save 
    xlWb.Close 

    xlApp.Quit 

End Sub 

работает для меня каждый раз, и не оставляет никаких процессов Excel висит в диспетчере задач.

Примечание: Если ваш код в какой-то момент сломается, и вы неправильно обрабатываете уже открытые объекты, они просто будут висеть на вкладке процессов в диспетчере задач. Если вы не выполнили обработку ошибок в своем коде, запустите here.

просто рассматривать это как альтернатива

Option Explicit 

Sub Main() 

    On Error GoTo ErrHandler 
    Dim xlApp As Excel.Application 
    Set xlApp = New Excel.Application 

    xlApp.Visible = False 
    xlApp.DisplayAlerts = False 

    Dim xlWb As Workbook 
    Set xlWb = xlApp.Workbooks.Open("C:\...\path") 

    Dim xlSht As Worksheet 
    Set xlSht = xlWb.Sheets(1) 

    xlSht.Range("A1") = "message from " & ThisWorkbook.FullName 

    xlWb.Saved = True 
    xlWb.Save 
    xlWb.Close 

    xlApp.Quit 
    Exit Sub 

ErrHandler: 
    xlWb.Saved = True 
    xlWb.Save 
    xlWb.Close 

    xlApp.Quit 
End Sub 
+1

Извините, но это не так, как все работает с Interop Excel. Процессы Excel остаются, и вы должны сделать достаточно много, чтобы удалить их (в соответствии с тем, что сделал OP). Не знаете, почему вы не видите его с кодом, возможно, из-за .Visible = False или просто с использованием одного объекта Excel, но это, безусловно, проблема. – varocarbas

+0

Как вы можете видеть в моем коде, я уже использую .save, .close и .quit в своем приложении. Тем не менее, он продолжает накапливать процессы excel до тех пор, пока мое приложение не сработает, потому что он думает, что у кого-то еще есть файл excel, который я пытаюсь использовать. 'Примечание. Прежде чем я запустил приложение, я убеждаюсь, что все процессы excel прекращены, поэтому он не может быть старыми экземплярами – Gutanoth

+0

@Gutanoth вы прочитали часть об обработке ошибок? вам нужно, чтобы в вашем коде, чтобы контролировать, что происходит. Добавьте строку debug.print в ErrHandler, чтобы увидеть, есть ли ошибки при обработке файлов. 'Kill'ing Excel-процессы не рассматриваются как обработка ошибок, а способ избежать неприятностей. Если у вас была правильная обработка ошибок, закодированная в вашем макросе, вы не должны были оставлять какие-либо нежелательные процессы. –

0

The Interop Marshal release doesn't always work because Excel XP and lower suck at releasing. I had to use your loop, but replace the Process.Close() and Process.Quit() with Process.Kill(). Works like a charm. Just be careful that you want ALL versions of excel.exe to be killed, because they will.

Я использую это:

Workbook.Save() 
Workbook.Close() 
Application.Quit() 

System.Runtime.InteropServices.Marshal.ReleaseComObject(Application) 

Worksheet = Nothing 
Workbook = Nothing 
Application = Nothing 

Dim proc As System.Diagnostics.Process 

For Each proc In System.Diagnostics.Process.GetProcessesByName("EXCEL") 
proc.Kill() 
Next 
+0

Без сомнения, ваш код работает. И я бы солгал, если бы сказал, что я никогда не использовал его; но такие подходы следует рекомендовать только в случае отсутствия другого варианта. И здесь есть другие варианты. – varocarbas

+0

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

0

Когда вы делаете что-нибудь с Excel Interop, он создает новый процесс.

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

Dim proc As System.Diagnostics.Process 
Dim info As ManagementObject 
Dim search As New ManagementObjectSearcher("SELECT ProcessId FROM Win32_process WHERE caption = 'Excel'") 
For Each info In search.Get() 

    'The string will give you the time that the process started 
    'You can then subtract that from the current time to see if you want to kill the process 
    Dim TheString As String = info.GetText(TextFormat.Mof).ToString 

    'Kill the process according to its ID 
    proc = System.Diagnostics.Process.GetProcessById(Mid$(TheString, _ 
                (Len(TheString) - 8), 4)) 
    proc.CloseMainWindow() 
    proc.Refresh() 
    If proc.HasExited Then GoTo NoKill 
    proc.Kill() 
NoKill: 
Next 

Вам нужно добавить:

Imports System.Management 

и добавить ссылку на «System.Management» в ваш проект.

+0

Ваш код выглядит так же, как тот, который предложил Кодер. Но я не хочу «Случайно» убивать процессы excel, с которыми работает другой пользователь в то время, когда они используют мое приложение. – Gutanoth

+0

Итак, вы можете только убить процесс, если он был открыт более X минут. Я копирую из некоторого кода, который у меня есть, но я думаю, что мы использовали Val (Mid $ (TheString, 57, 2)), чтобы получить минуту, когда начался процесс Excel. Если вы отлаживаете TheString, вы увидите, что она содержит дату и время создания процесса. Кстати, имя процесса - EXCEL.exe, а не только EXCEL. –

+0

Вы также можете использовать «SELECT * FROM Win32_process WHERE caption =« EXCEL.exe ». Это даст вам гораздо больше информации о процессе.Там должно быть что-то, что позволит вам увидеть, какие процессы вы начали, а затем убить процесс на основе этих данных. –

0

Вы можете получить идентификатор процесса из html Excel.Application и использовать его для безопасного удаления процесса.

Смежные вопросы