CSharp – Interop Excel Prozess richtig beenden

Wer kennt sie nicht die Plagerei mit Interop Excel und den Com-Objekten. Da implementiert man an einer komplexe Verarbeitungen über mehrere Worksheets und denkt sich, endlich geschafft. Aber Vorsicht – mal einen Blick in den Taskmanager geworfen? Wenn man viel bei der Implementierung mittels Debug-Modus getestet hat, findet man schnell mal eine Handvoll Excel Prozesse. Daraufhin schweift der Blick prompt zur Taskleiste. Wo man zur Überraschung nicht eine geöffnet Excel Anwendung vorfindet.

Durch den Einsatz der Microsoft.Office.Interop Libraries kommt das Component Object Model von Microsoft zum Einsatz. Dabei hat man Objekte und Referenzen erschaffen die sich schnell im eigenen Code-Abschnitt heimisch füllen und die beiden Welten COM und .Net verküpfen. Darüber hinaus machen sie sich auch gerne zusammen mit einer gesamten Excel-Instanz im RAM breit. Das kann schnell zu unangenehmen Memory Leaks führen.

Da gilt es entsprechend vorzugehen und auch diesen Programmteilnehmern mitzuteilen, dass die aktuelle Programmausführung dem Ende zugeht und jeder doch bitte seine Ressourcen freizugeben hat.

Jeder Variable die einen Verweis auf COM-Objekt hat muss man mitteilen dass der Verweis freizugeben ist. Hier kommt die Marshal.FinalReleaseComObject-Methode zum Einsatz (ab .Net 2.0). Wichtig ist auch das die Freigabe der Verweise in der umgekehrten Reihenfolge zu erfolgen hat wie sie initialisiert wurden (LIFO Last-In-First-Out).

Zusätzlich können durch For-Anweisungen über z.B. Excel Ranges/Cells weitere Verweise entstehen. Diese können nun aber nicht explizit über eine Variable freigegeben werden. Hier muss man den Garbage Collector um seine Mithilfe bemühen. Dazu wird GC.Collect() und GC.WaitForPendingFinalizers() aufgerufen. Das ganze muss sogar zweimal gemacht werden, da der Runtime Callable Wrapper für jedes COM Objekts den Finalizer ausführen muss und ein zweites Mal für den Finalizer des RCW selbst. Dies stellt dann sich das alles aus dem Speicher entfernt wird.

Da die Ausführung des GC sehr teuer ist, sollte man diesen erst nach Abschluss des regulären Programmablaufes aufrufen. Weiterhin ist es nicht ganz einfach den Überblick über die ganzen COM-Objekte und deren Reihenfolge zu behalten. Um dem vorzubeugen benutzen wir einen ComObjectManager der IDisposable implementiert sowie einen Stack um das LIFO zu realisieren.

ComObjectManager:

Beispiel:

Nun haben auch alle Com-Objekte und deren Verweise gelernt dass sie ihre Ressourcen freigegeben müssen und der Excel-Prozess wird ordentlich beendet.