Aus VB.Net Excel beenden

  • VB.NET

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von jvbsl.

    Aus VB.Net Excel beenden

    Hallo zusammen,
    Seit Tagen beschäftigt mich folgendes Problem, was ich trotz Durchforsten aller Foren
    nicht lösen konnte:
    Aus VB.Net
    Excel starten - Datei editieren - Excel beenden
    Eigentlich ganz simpel - es funktioniert auch tadellos (Auch das Beenden ohne Fehlermeldung).

    Habe zu diesem Zweck ein eigenes Projekt angelegt und experimentiere damit bis zur Schmerzgrenze.
    Egal, was ich mache, es bleibt immer ein Hintergrundprozess von Excel aktiv und ich bekomme ihn nicht
    beendet.
    Hat jemand dazu eine Idee? Bin mit meinem "Latein" am Ende. Schon mal Danke!
    Der Quelltext hier


    VB.NET-Quellcode

    1. Imports System.Runtime.InteropServices
    2. Public Class Form1
    3. Public D_Prüfling As String
    4. Dim AnzahlP As Integer
    5. 'Daten Datei(Excel)"Ablesedaten" definieren
    6. Public D_Pfad As String
    7. Public D_Filename As String
    8. Public Quartal As String
    9. Public xlApp As Microsoft.Office.Interop.Excel.Application
    10. Public xlMappe As Microsoft.Office.Interop.Excel.Workbook
    11. Public xlBlatt As Microsoft.Office.Interop.Excel.Worksheet
    12. 'Public xRange As Microsoft.Office.Interop.Excel.Range
    13. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    14. End Sub
    15. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    16. D_Prüfling = "D:\LW-Stammdaten\Daten-Dateien\Strom\Stromzählerlisten\2017\Q1\01_Jan\LH_HR_A.xlsx"
    17. Quartal = "Q1"
    18. xlApp = New Microsoft.Office.Interop.Excel.Application 'Application (Excel.exe) als Objekt deklarieren
    19. xlMappe = xlApp.Workbooks.Open(D_Prüfling) 'Datei (WE) als Objekt definieren
    20. xlBlatt = xlMappe.Worksheets(Quartal) 'Tabellenblatt als Objekt defonieren
    21. xlMappe.Worksheets(Quartal).select() 'Fokus auf dieses Tabellenblatt
    22. 'xRange = xlBlatt.Range("A1") 'Leseart im Tabellenblatt festlegen (1:1 oder A:1 bzw. Cells oder Range)
    23. xlApp.Visible = True 'Ecxel im Hintergrund (nicht sichtbar)laufen lassen
    24. End Sub
    25. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    26. Call Excel_schließen()
    27. End Sub
    28. Public Sub Excel_schließen()
    29. AnzahlP = 0
    30. If System.Diagnostics.Process.GetProcessesByName("excel").Length > 0 Then
    31. For Each Process In Diagnostics.Process.GetProcessesByName("excel")
    32. AnzahlP = AnzahlP + 1
    33. 'Marshal.ReleaseComObject(xRange)
    34. 'xRange.close()
    35. 'xRange = Nothing
    36. Marshal.FinalReleaseComObject(xlBlatt)
    37. 'xlBlatt.close()
    38. xlBlatt = Nothing
    39. Marshal.FinalReleaseComObject(xlMappe)
    40. 'xlMappe.Close() 'schließt Mappe
    41. xlMappe = Nothing
    42. 'xlApp.Quit() 'schließt Ecxel
    43. Marshal.FinalReleaseComObject(xlApp)
    44. xlApp = Nothing
    45. 'MsgBox("Excel noch geöfnet ?")
    46. Next
    47. End If
    48. MsgBox("Excel ist noch " & AnzahlP & " mal geöfnet ")
    49. End Sub
    50. End Class[vbnet]


    Edit by ~blaze~:
    *Thema verschoben*

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „~blaze~“ ()

    @mozart.w Wenn Du Excel aus VB.NET beenden willst, solltest Du Excel auch aus VB.NET heraus starten. Funktioniert prima:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private ProcExcel As Process = Nothing
    3. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    4. Me.ProcExcel = Process.Start("Excel.exe")
    5. End Sub
    6. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    7. If Me.ProcExcel IsNot Nothing AndAlso Not Me.ProcExcel.HasExited Then
    8. ' wenn Prozess noch läuft, beenden
    9. Me.ProcExcel.CloseMainWindow()
    10. End If
    11. If Me.ProcExcel IsNot Nothing Then
    12. ' aufräumen
    13. Me.ProcExcel.Dispose()
    14. ' Ausgangslage
    15. Me.ProcExcel = Nothing
    16. End If
    17. End Sub
    18. End Class
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany Der TE benötigt offenbar Zugriff auf die Excel-API. Da nützt externes Starten des Prozesses gar nichts, weil er in diesem Fall das API-Handle nicht hinterhergeworfen bekommt.

    @mozart.w Diese Frage wird hier im Forum immer wieder gestellt. Dein Code produziert sogenannte handle leaks, also nicht freigegebene Interop-Referenzen. Sie verhindern das Beenden des Excel-Prozesses, weil der richtigerweise annimmt, dass die Objekte noch benötigt werden. Such' im Forum nach Beiträgen von mir mit dem Suchbegriff "Excel".
    Gruß
    hal2000
    So, da bin ich wieder...
    zu RodFromGermany:
    Ja funktioniert.
    Hab das noch etwas modifiziert

    VB.NET-Quellcode

    1. Public Class Form1
    2. Dim pf As String = "D:\"
    3. Dim dd As String = "test.xlsx"
    4. Dim dq As String = "Q1"
    5. Private ProcExcel As Process = Nothing
    6. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    7. Me.ProcExcel = Process.Start(pf & dd)


    Wenn man sonst nichts weiteres machen will - eine gute Lösung.
    Aber - und hier kommt der Einwand von hal2000 ins Spiel mit den "hinterhergeworfenen" API,
    mehr scheint nicht möglich.

    Die Ausführung im Link von hal2000 habe ich versucht umzusetzen, aber nicht richtig verstanden.

    Hier mein Ansatz:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Dim AnzahlP As Integer
    3. Dim D_File As String = "D:\test.xlsx"
    4. Dim Quartal As String = "Q1"
    5. Dim xlApp As New Microsoft.Office.Interop.Excel.Application
    6. Dim xlMappen = xlApp.Workbooks
    7. Dim xlMappe = xlMappen(D_File)
    8. Dim xlBlätter = xlMappe.Worksheets
    9. Dim xlBlatt = xlBlätter(Quartal)
    10. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    11. xlApp.xlMappe.xlBlatt.select()
    12. xlApp.Visible = True 'False = Ecxel im Hintergrund (nicht sichtbar)laufen lassen
    13. End Sub


    Es geht erst mal nur um den Aufruf von Excel und dem Fokussieren des Arbeitsblattes.
    Schon in der Definition "Dim xlMappe = xlMappen(D_File)
    kommt ein Fehler. Kann mir geholfen werden?
    Danke!
    lg Mozart
    Hallo,

    ​hier ein CodeSnippet, welches ich nutze um mit Excel zu arbeiten. Auch dieses benutzt die Kill-Methode, aber ich suche mir über die API die passende Excel-Instanz aus und beende nur diese. Weil alles Excel-Instanzen, die geöffnet sind heißen "EXCEL". Wäre nicht hilfreich, diese alle zu beenden.

    VB.NET-Quellcode

    1. ​Imports Excel = Microsoft.Office.Interop.Excel
    2. Imports System.Diagnostics
    3. Imports System.IO
    4. Public MustInherit Class DataWorkExcel
    5. Protected _xlAppl As New Application
    6. Protected _xlWorkBook As Workbook
    7. Protected _isOpen As Boolean
    8. Protected Sub openExcelAppl(Path As String)
    9. _xlAppl.Visible = False
    10. _xlWorkBook = _xlAppl.Workbooks.Open(Path)
    11. _isOpen = True
    12. End Sub
    13. Public Sub closeExcelAppl() 'quick & dirty Prozess killen
    14. If _isOpen Then
    15. Dim processId As IntPtr
    16. GetWindowThreadProcessId(_xlAppl.Hwnd, processId)
    17. Dim xLProcess As Process = Process.GetProcessById(processId.ToInt32())
    18. xLProcess.Kill()
    19. _isOpen = False
    20. Else
    21. Exit Sub
    22. End If
    23. End Sub
    24. Public Sub SaveAndCloseExcelAppl()
    25. If _isOpen Then
    26. Dim processId As IntPtr
    27. _xlWorkBook.Close(SaveChanges:=True)
    28. GetWindowThreadProcessId(_xlAppl.Hwnd, processId)
    29. Dim xLProcess As Process = Process.GetProcessById(processId.ToInt32())
    30. xLProcess.Kill()
    31. _isOpen = False
    32. Else
    33. Exit Sub
    34. End If
    35. End Sub
    36. Public Sub runMainSub()
    37. _xlAppl.Run("Main.Main")
    38. End Sub
    39. Protected Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Integer, ByRef lpdwProcessId As IntPtr) As IntPtr
    40. End Class
    Normalerweiße würde man nach der Fehlermeldung verlangen, aber ich kann mir schon etwas vorstellen.

    wie wärs wenn du die Werte erst in einer Methode festlegst, damit stellst du sicher, dass auch alles in der richtigen Reihenfolge aufgerufen wird.

    Und um Excel dann zu beenden, anstatt es mittels Kill zu machen, solltest du versuchen deine verwendeten Objekte zu Disposen, das ist es auch, was den Prozess offen hält.(Wie hal2000 schon gesagt hat)
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Erst einmal vielen Dank, an alle die hier gepostet haben.
    ich habe mir alle Beiträge angesehen (auch die Verweise) und fast alle ausprobiert.
    Fazit:
    Über dieses Thema könnte man ein Buch schreiben.
    "Verbockt" hat es MS - die Programmierer versuchen dies durch zusätzlichen Programmeraufwand nun zu kompensieren.
    Was ich daraus gelernt habe:
    - um dem Anwender aus VB.NET Excel zur Verfügung zu stellen (auch mit einer Tabelle) ist die Möglichkeit von RodFromGermany
    eine gute Lösung
    - Excel nur einmal als Prozess am laufen zu halten ist genau so eine "Krücke", wie mühsam laufende Prozesse zu suchen und den Marshal einzusetzen
    - Um Excel-Tabellen zu bearbeiten sollte man besser auf Excel verzichten und Datenschnittstellen benutzen.
    Das ist zwar etwas komplizierter aber man vermeidet Probleme und gewinnt Performanz.

    Nochmal Danke - auch an jene, die verlinkt etwas mit dem Thema zu tun hatten.

    lg mozart
    COM ist kacke ja, aber die einzige andere Möglichkeit ist es einen kompletten Wrapper selbst zu schreiben und das macht noch weniger Spaß.

    Und da Excel nunmal nativ ist muss man sich um dessen Resourcen eben kümmern, bei einem Wrapper könnte man dies für vieles im Wrapper selbst erledigen, tun müsste man es trotzdem.
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---