Benutzer mit den meisten Antworten
Verständnisfrage: Unterschied zwischen Application und Process

Frage
-
Hallo an Alle,
bin gerade auf ein Problem gestoßen, dass ich nicht so recht verstehe und hoffe, dass mir das jemand erklären kann.
Ausgangssituation:
Aus einer Winform wird eine Klasse aufgerufen, die mir eine Excelapplikation mit allem anderen benötigten Schnickschnack (Workbook,.... Range etc.) via:
Excel.Application xlApp = null; Excel.Workbook xlWorkBook = null; Excel.Worksheet xlWorkSheet = null;
erstellt, ein paar Aufgaben in Excel erledigt und anschließend mittels xlApp.Quitt() wieder geschlossen wird. Funktioniert alles wunderbar. Schaue ich mir aber den Taskmanager an, dann bleibt dieser Prozess (oder bei mehrmaligem Aufruf eben mehrere Prozesse) bis zum Beenden der Gesamtanwendung erhalten. Auch, wenn ich die Objekte auf NULL setze und den GarbageCollector extra noch mal aufrufe.
Zuerst dachte ich, das wäre, weil ich die Prozedur als static deklariert hatte, aber selbst nach entfernen von static bleibt dieser Prozess erhalten.
Kann mir bitte mal jemand erklären woran das liegt?
Die Applikation ist doch ein Objekt, das geschlossen wird. Einen Prozess rufe ich aber nicht explizit auf. Oder war ich nur zu ungeduldig und der GC erledigt das noch mal irgendwann? Geht das irgendwie auf einfache Art und Weise zu lösen oder muss ich mir eine Schleife bauen, die alle offenen Prozesse ermittelt und Excel dann explizit schließt?
Vorab schon einmal Danke für Eure Gedanken...:)
Ralf
Antworten
-
...sorry... so richtig geklärt ist die Sache ja nicht. Hab es zwar halbwegs hinbekommen, trotzdem bleibt der letzte Prozess noch bestehen. Allerdings ist die Sache zumindest nicht mehr akut, deshalb kann der Thread geschlossen werden...
- Als Antwort markiert Ralf A Mittwoch, 12. Februar 2014 16:36
Alle Antworten
-
Hallo,
da du Excel über COM ansteuerst, wird automatisch ein Prozess von Excel gestartet, der die Zugriffe übernimmt. Somit ist es normal das der Prozess auftaucht.Um das Problem zu lösen, kannst du zum Schluss nochmal ReleaseComObject aufrufen um die App, das Workbook usw. frei zu geben (die jeweiligen Instanzen übergeben). Wenn die einzelnen Instanzen eine Dispose-Methode haben, solltest du auch diese aufrufen.
Koopakiller [kuːpakɪllɐ] (Tom Lambert)
Webseite |
Code Beispiele |
Facebook |
Twitter |
Snippets
C# ↔ VB.NET Konverter
Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke. -
Hi Tom,
Danke für Dein Feedback!
Sorry, hatte vergessen, dass ich ReleaseComObject ebenfalls aufrufe, indem ich das Workbook und die Applikation als Objekte übergebe:
private void releaseObject( object obj ) {
try { System.Runtime.InteropServices.Marshal.ReleaseComObject(obj); obj = null; } catch { obj = null; MessageBox.Show("Folgendes Objekt kann nicht freigegeben werden:" + obj.ToString()); } finally { System.GC.Collect(); } }
nutzt aber nix. Der Prozess steht nach wie vor im Taskmanager. Unter Eigenschaften wird zwar die Größe mit 0 Byte angegeben, trotzdem finde ich das eigenartig und wenig erfreulich...
...und... in den Catch Zweig kommt es auch nicht....
Dispose wäre noch eine Option... aber... ich dachte, das erledigt der GC gleich mit (irgendwann...;) )
Ralf
- Bearbeitet Ralf A Donnerstag, 6. Februar 2014 18:58
-
Wenn eine Klasse eine Dispose-Methode aufweißt, dann sorgt diese dafür das alles aufgeräumt wird. Es kann sein, das es sich um Dinge handelt, die der GC garnicht mit bekommt bzw. erst "jahre" später.
Noch ein Hinweis zu ReleaseComObject: Diese Methode gibt 0 zurück, wenn der Vorgang erfolgreich war. Wenn nicht, sollte der Aufruf wiederhohlt werden.
Versuche außerdem Close() für das Workbook aufzurufen.
Wenn garnichts funktioneirt, gucke dir mal das hier an.
Koopakiller [kuːpakɪllɐ] (Tom Lambert)
Webseite |
Code Beispiele |
Facebook |
Twitter |
Snippets
C# ↔ VB.NET Konverter
Markiert bitte beantwortende Posts als Antwort und bewertet Beiträge. Danke. -
...was soll's? Ich füge mal die Klasse an.
using Microsoft.Office.Interop.Excel; using System.Runtime.InteropServices; using System.Windows.Forms; using Excel = Microsoft.Office.Interop.Excel; namespace Anton.Exceltool { public class cExcelHandling { /// <summary> /// Leere Zeilen und Spalten aus Excelsheet löschen. Auch wenn Leerzeichen enthalten sind /// </summary> /// <param name="Datei">Pfad und Dateiname der Exceldatei</param> /// <param name="Tabelle">Name des betreffenden Worksheets</param> public void DeleteEmptyRowsAndColums( string Datei, string Tabelle ) { // string sFile=@"D:\Daten\ExcelDateien\Umsatz.xls"; //string wert = ""; Excel.Application xlApp = null; Excel.Workbook xlWorkBook = null; Excel.Worksheet xlWorkSheet = null; System.IntPtr pt = (System.IntPtr) 0; try { Excel.Range range; Excel.Range testRng; Excel.Range ergRng; xlApp = new Excel.Application(); pt = (System.IntPtr) xlApp.Hwnd; xlWorkBook = xlApp.Workbooks.Open(Datei, 0, false, 5, "", "", false, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "t", false, false, 0, false, 1, 0); xlWorkSheet = (Excel.Worksheet) xlWorkBook.Worksheets.get_Item(1); range = xlWorkSheet.UsedRange; //xlApp.Visible = false; //xlApp.Visible = true; //xlApp.WindowState = XlWindowState.xlMaximized; int spalten = (int) xlWorkSheet.UsedRange.Columns.Count; long zeilen = (long) xlWorkSheet.UsedRange.Rows.Count; int letzteSpalte=spalten; long letzteZeile=zeilen; long erg = 0, ergLeer= 0; //Zelle für Formel = Spalte A, eine Zeile unter der letzten des UsedRange ergRng = xlWorkSheet.get_Range("A" + ( zeilen + 1 ), "A" + ( zeilen + 1 )); string strStartzelle="", strZielzelle = ""; for ( int spalte = spalten ; spalte > 1 ; spalte-- ) { strStartzelle = xlWorkSheet.Cells[2, spalte].Address.ToString().Replace("$", ""); strZielzelle = xlWorkSheet.Cells[zeilen, spalte].Address.ToString().Replace("$", ""); //Range, der geprüft werden soll testRng = xlWorkSheet.get_Range(strStartzelle, strZielzelle); ergRng.Activate(); ergRng.Formula = "=CountBlank(" + testRng.Address + ")"; erg = System.Convert.ToInt64(ergRng.Value2.ToString()); ergRng.Formula = "=CountIf(" + testRng.Address + ",\" \")"; ergLeer = System.Convert.ToInt64(ergRng.Value2.ToString()); if ( erg + ergLeer == zeilen - 1 ) { //Leere Spalte } else //Festlegen der letzten Spalte mit gültigen Werten { letzteSpalte = spalte; goto CheckZeilen; } } CheckZeilen: for ( long zeile = zeilen ; zeile > 1 ; zeile-- ) { strStartzelle = xlWorkSheet.Cells[zeile, 1].Address.ToString().Replace("$", ""); strZielzelle = xlWorkSheet.Cells[zeile, letzteSpalte].Address.ToString().Replace("$", ""); //Range, der geprüft werden soll testRng = xlWorkSheet.get_Range(strStartzelle, strZielzelle); ergRng.Formula = "=CountBlank(" + testRng.Address + ")"; erg = System.Convert.ToInt64(ergRng.Value2.ToString()); ergRng.Formula = "=CountIf(" + testRng.Address + ",\" \")"; ergLeer = System.Convert.ToInt64(ergRng.Value2.ToString()); if ( erg + ergLeer == letzteSpalte ) { //Leere Zeile } else { letzteZeile = zeile; goto Weiter; } } Weiter: if ( letzteSpalte < spalten ) { Excel.Range sp; for ( int i = spalten ; i > letzteSpalte ; i-- ) { sp = (Excel.Range) xlWorkSheet.Columns[i]; //sp.Select(); sp.Delete(); } } if ( letzteZeile < zeilen ) { Excel.Range sp; for ( long i = zeilen + 1 ; i > letzteZeile ; i-- ) { sp = (Excel.Range) xlWorkSheet.Rows[i]; //sp.Select(); sp.Delete(); } } xlApp.DisplayAlerts = false; xlWorkBook.Save(); xlWorkSheet.UsedRange.SpecialCells(XlCellType.xlCellTypeLastCell).Activate(); } catch { System.Windows.Forms.MessageBox.Show("Fehler in ReadExcel: "); } finally { xlApp.DisplayAlerts = true; xlWorkBook.Saved = true; xlWorkBook.Close(); xlApp.Quit(); releaseObject(xlWorkBook); releaseObject(xlApp); KILLProzess(xlApp, pt); } } private void releaseObject( object obj ) { try { System.Runtime.InteropServices.Marshal.ReleaseComObject(obj); obj = null; } catch { obj = null; MessageBox.ShowMessageBox.Show("Folgendes Objekt kann nicht freigegeben werden:" + obj.ToString());
Anzumerken wäre noch, dass keiner der catch-Zweige je angesprungen wird. In KILLProzess allerdings auch keine Bestätigung kommt, dass der Prozess beendet wurde... Bin einigermaßen ratlos...
} finally { System.GC.Collect(); } } void KILLProzess( Excel.Application myExcel, System.IntPtr pt ) { try { var procList = System.Diagnostics.Process.GetProcessesByName("EXCEL"); for ( int i = 0 ; i < procList.Length ; i++ ) { //MessageBox.Show(string.Format("Prozess ID: {0}. Hauptfenster: {1}", procList[i].Id, procList[i].MainWindowTitle)); if ( procList[i].MainWindowHandle == pt ) { procList[i].Kill(); MessageBox.Show(string.Format("Prozess ID: {0}. Hauptfenster: {1} wurde gekillt", procList[i].Id, procList[i].MainWindowTitle)); } } } catch { MessageBox.Show("Shit happens..."); } } } }
-
Hi,
Ist Deine Situation eigentlich abgeklärt ? Können wir den Thread schließen ? Wenn ja - bitte markiere die hilfreichen Beiträge "als Antwort".
Viele Grüße,
Ciprian
Ciprian Bogdan, MICROSOFT
Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip„Entwickler helfen Entwickler“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.
-
...sorry... so richtig geklärt ist die Sache ja nicht. Hab es zwar halbwegs hinbekommen, trotzdem bleibt der letzte Prozess noch bestehen. Allerdings ist die Sache zumindest nicht mehr akut, deshalb kann der Thread geschlossen werden...
- Als Antwort markiert Ralf A Mittwoch, 12. Februar 2014 16:36
-
Hi Ralf,
ohne dein Code durchgelesen zu haben, schliesst sich nach dem closen des worbooks und den closen der application die excel instanz, ganz ohne direkt com programmierung, da c# die com schnittstelle wunderbar maskiert.
Vielleicht testest du erst den einfachsten fall, instantier von excel, öffnen bzw erstellen von werten und danach schliessen des workbooks und application.
-
Hallo Brian,
ist zwar eine Weile her, habe aber Deinen Beitrag erst jetzt entdeckt.
Com Interop und Release scheint ja ein WWW-Renner zu sein. Theoretisch sollte alles funktionieren (und im Prinzip tut es das auch), was ich aber festgestellt habe, sobald die Datei gespeichert wird, bleibt die Instanz im Taskmanager weiterhin sichtbar. Ohne speichern tut sie, was sie soll und verschwindet.
Vorläufig kann ich damit leben. Aber Danke für Deinen Beitrag!
Ralf