Wie säubere ich Excel-Interop-Objekte ordnungsgemäß?
Ich bin mit der Excel-interop in C# (ApplicationClass
gelegt habe und den folgenden code in der finally-Klausel:
while (System.Runtime.InteropServices.Marshal.ReleaseComObject(excelSheet) != 0) { }
excelSheet = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Obwohl diese Art der arbeiten, die Excel.exe
- Prozess noch im hintergrund, auch nachdem ich Excel schließen. Es ist nur freigegeben, sobald meine Bewerbung wird manuell geschlossen.
Was mache ich falsch, oder gibt es eine alternative zu sorgen-interop-Objekte, die ordnungsgemäß entsorgt werden?
InformationsquelleAutor der Frage HAdes | 2008-10-01
Du musst angemeldet sein, um einen Kommentar abzugeben.
Excel nicht beenden, da Ihre Anwendung immer noch hält Referenzen auf COM-Objekte.
Ich denke, du bist Berufung mindestens ein Mitglied der COM-Objekt ohne Zuweisung an eine variable.
Für mich war es die excelApp.Arbeitsblätter Objekt, die ich direkt verwendet werden, ohne Zuweisung an eine variable:
Wusste ich nicht, dass intern C# erstellt einen wrapper für die Arbeitsblätter COM-Objekt, das nicht veröffentlicht wird durch meinen code (weil ich war nicht bewusst) und war die Ursache, warum Excel nicht entladen.
Fand ich die Lösung zu meinem problem auf auf dieser Seitedie hat auch eine nette Regel für die Verwendung von COM-Objekten in C#:
Also mit diesem wissen auf die richtige Weise zu tun, die oben genannten ist:
InformationsquelleAutor der Antwort VVS
Können Sie tatsächlich lassen Sie Ihre Excel-Application-Objekt sauber, aber Sie haben nicht zu kümmern.
Den Rat zu pflegen eine benannte Referenz für absolut jedes COM-Objekt abrufen und dann explizit freigeben, die es über
Marshal.FinalReleaseComObject()
ist richtig in der Theorie, aber leider sehr schwierig zu handhaben in der Praxis. Wenn man immer rutscht überall und Verwendungen, von "zwei Punkte", oder iteriert Zellen über einenfor each
Schleife, oder jede andere ähnliche Art von Befehl, dann haben Sie nicht referenzierte COM-Objekte und das Risiko eines hang. In diesem Fall gäbe es keine Möglichkeit, die Ursache zu finden in dem code, die Sie haben würde, um alle überprüfen Sie Ihren code, indem Auge und hoffentlich die Ursache finden, eine Aufgabe, könnte fast unmöglich sein, für ein großes Projekt.Die gute Nachricht ist, dass man eigentlich nicht aufrecht zu erhalten, eine benannte variable Referenz zu jedem COM-Objekt, das Sie verwenden. Stattdessen rufen
GC.Collect()
und dannGC.WaitForPendingFinalizers()
zu release alle (meist kleinere) Gegenstände, auf die Sie nicht halten eine Referenz, und dann explizit freigeben der Objekte, auf die Sie halten eine benannte variable Referenz.Sollten Sie auch lassen Sie Ihre benannten Referenzen in umgekehrter Reihenfolge der Wichtigkeit: - Bereich Objekte zuerst, dann Arbeitsblättern, Arbeitsmappen und dann endlich können Sie Ihre Excel-Application-Objekt.
Zum Beispiel, vorausgesetzt, Sie hatten ein Range-Objekt-variable mit dem Namen
xlRng
eine Worksheet-variable mit dem NamenxlSheet
eine Arbeitsmappe variable mit dem NamenxlBook
- und einer Excel-Anwendung variable mit dem NamenxlApp
dann ist dein cleanup-code Aussehen könnte etwas wie das folgende:In den meisten code-Beispiele sehen Sie für die Reinigung von COM-Objekten .NET, die
GC.Collect()
undGC.WaitForPendingFinalizers()
Aufrufe DOPPELT so hoch wie in:Sollte dies nicht erforderlich sein, es sei denn, Sie sind mit Visual Studio Tools für Office (VSTO), die verwendet Finalizer, verursachen eine ganze Graphen von Objekten gefördert werden, die in der finalization queue. Solche Objekte nicht freigegeben werden, bis die nächsten garbage collection. Allerdings, wenn Sie nicht mit VSTO, Sie sollten in der Lage sein zu rufen
GC.Collect()
undGC.WaitForPendingFinalizers()
nur einmal.Ich weiß, dass explizit aufrufen
GC.Collect()
ist ein no-no (und sicherlich tun Sie es zweimal hört sich sehr schmerzhaft), aber es gibt keine Möglichkeit um ihn herum, um ehrlich zu sein. Durch den normalen Betrieb erzeugen Sie versteckte Objekte, die Sie halten, kein Verweis, dass Sie, also nicht die Freisetzung durch andere Mittel, die andere als AufrufGC.Collect()
.Dies ist ein Komplexes Thema, aber das ist wirklich alles dort ist zu ihm. Einmal schaffen Sie diese Vorlage für Ihre cleanup-Prozedur können Sie den code normalerweise, ohne die Notwendigkeit von Wrapper, etc. 🙂
Habe ich ein tutorial dazu finden Sie hier:
Automatisieren von Office-Programmen mit VB.Net /COM Interop
Es ist geschrieben für VB.NET aber nicht abschrecken lassen, dass die Grundsätze sind genau die gleichen wie bei der Verwendung von C#.
InformationsquelleAutor der Antwort
Vorwort: meine Antwort enthält zwei Lösungen, also seien Sie vorsichtig beim Lesen und nichts verpassen.
Gibt es verschiedene Möglichkeiten und Tipps, wie man Excel-Instanz entladen, wie:
Freigabe JEDES com-Objekt explizit
mit dem Marschall.FinalReleaseComObject()
(nicht zu vergessen, über implizit
erstellt von com-Objekten). Zu release
jeder erstellte com-Objekt, die Sie verwenden können
die Regel von 2 Punkten die hier erwähnt werden:
Wie kann ich richtig aufzuräumen Excel-interop-Objekte?
Aufruf von GC.Collect() und
GC.Waitforpendingfinalizers Tauchen() zu machen
CLR-Version nicht verwendete com-Objekte * (Tatsächlich, es funktioniert, siehe meine zweite Lösung für die details)
Überprüfen, ob die com-server-Anwendung
vielleicht zeigt eine message-box warten
der user zu beantworten (obwohl ich nicht bin
sicher, es kann verhindern, dass Excel aus
schließen, aber ich hörte es ein paar
mal)
Senden von WM_CLOSE-Meldung auf der main
Excel-Fenster
Ausführen der Funktion, die funktioniert
mit Excel in einer separaten Anwendungsdomäne.
Einige Leute glauben Excel-Instanz
wird geschlossen, wenn AppDomain ist
entladen.
Tötung aller excel-Instanzen, die instanziiert wurden nach unserer excel-interoping-code begann.
ABER! Manchmal alle diese Optionen einfach nicht helfen, oder kann nicht angemessen sein!
Zum Beispiel, gestern fand ich heraus, dass in einer meiner Funktionen (mit excel) Excel behält ausgeführt wird, nachdem die Funktion beendet. Ich habe alles versucht! Ich sorgfältig geprüft, die ganze Funktion 10 mal und fügte Marschall.FinalReleaseComObject() für alles! Ich hatte auch GC.Collect() und GC.Waitforpendingfinalizers Tauchen(). Ich überprüfte für die versteckte message-Boxen. Ich versuchte, senden von WM_CLOSE-Nachricht zu der Haupt-Excel-Fenster. Ich ausgeführt meine Funktion in eine separate AppDomain-und entladen, die domain. Nichts hat geholfen! Die option mit dem schließen aller excel-Instanzen ist unpassend, weil, wenn der Benutzer beginnt eine weitere Excel-Instanz manuell, während der Ausführung der Funktion, die funktioniert auch mit Excel, dann diese Instanz auch geschlossen werden von meiner Funktion. Ich Wette, der Benutzer wird nicht glücklich sein! Also, ehrlich gesagt, das ist ein lame-option (nichts für ungut Jungs). So verbrachte ich ein paar Stunden, bevor ich einziehen (meiner bescheidenen Meinung nach) Lösung: Töten excel-Prozess durch die hWnd-Eigenschaft des das Hauptfenster (es ist eine erste Lösung).
Ist hier der einfache code:
Wie Sie sehen können habe ich zwei Methoden, nach Try-Parse-Muster (ich denke es ist hier angebracht): eine Methode keine Ausnahme auslösen, wenn der Prozess konnte nicht getötet werden (zum Beispiel der Prozess existiert nicht mehr), und eine andere Methode wirft Ausnahme, falls der Prozess wurde nicht getötet. Die einzige schwache Stelle in diesem code wird die Sicherheit Berechtigungen. Theoretisch, kann der Benutzer nicht die Berechtigung hat, den Prozess zu beenden, aber in 99.99% aller Fälle wird der Benutzer die entsprechenden Berechtigungen besitzt. Ich habe auch getestet mit einem Gast-Konto - es funktioniert perfekt.
So, Ihr code, arbeiten mit Excel, kann wie folgt Aussehen:
Voila! Excel ist beendet! 🙂
Ok, gehen wir zurück zu der zweiten Lösung, wie ich versprach, in der Anfang der post.
Die zweite Lösung ist der Aufruf von GC.Collect() und GC.Waitforpendingfinalizers Tauchen(). Ja, Sie tatsächlich arbeiten, aber Sie müssen hier vorsichtig sein!
Viele Menschen sagen (und ich sagte), dass der Aufruf von GC.Collect() nicht helfen. Aber der Grund, warum es nicht hilft, ist, wenn es noch Referenzen auf COM-Objekte! Einer der beliebtesten Gründe für die GC.Collect() nicht hilfreich ist, läuft das Projekt im Debug-Modus. Im debug-Modus-Objekte, sind wirklich nicht mehr referenziert werden, werden nicht von der garbage Collection eingesammelt, bis das Ende der Methode.
Also, wenn Sie versucht, die GC.Collect() und GC.Waitforpendingfinalizers Tauchen() und es hat nicht helfen, versuchen Sie Folgendes:
1) Versuchen Sie, führen Sie Ihr Projekt im Release-Modus und überprüfen Sie, ob Excel richtig geschlossen
2) Wickeln Sie die Methode, die das arbeiten mit Excel in eine separate Methode.
Also, statt so etwas wie dieses:
schreiben Sie:
Nun in Excel in der Nähe =)
InformationsquelleAutor der Antwort nightcoder
UPDATE: Hinzugefügt C# - code und link zum Windows-Arbeitsplätze
Verbrachte ich irgendwann versuchen, herauszufinden, dieses problem, und zu der Zeit XtremeVBTalk war die aktive und reaktionsschnell. Hier ist ein link zu meinem ursprünglichen post, Schließen einer Excel-Interop-Prozess sauber, auch wenn die Anwendung abstürzt. Unten ist eine Zusammenfassung der post, und den code kopiert diesen Beitrag.
Application.Quit()
undProcess.Kill()
funktioniert für die meisten Teil, aber schlägt fehl, wenn die Anwendungen stürzt katastrophal. I. e. wenn die app abstürzt, wird der Excel-Prozess läuft weiterhin Locker.Ich fand das eine saubere Lösung, da das Betriebssystem ist die eigentliche Arbeit erledigen die Säuberung. Alles, was Sie tun müssen, ist registrieren Excel-Prozess.
Windows Job Code
Wrappt die Win32-API-Aufrufe registrieren Interop-Prozesse.
Hinweis über Konstruktor-code
info.LimitFlags = 0x2000;
genannt wird.0x2000
ist dieJOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
enum-Wert, und dieser Wert ist definiert durch MSDN:Extra Win32-API-Aufruf, um die Prozess-ID (PID)
Mit dem code
InformationsquelleAutor der Antwort joshgo
Dieser arbeitete für ein Projekt, das ich arbeiten war:
Haben wir gelernt, dass es wichtig war, zu setzen jeder Verweis auf eine Excel-COM-Objekt auf null, wenn Sie fertig waren. Diese enthalten Zellen, Blätter und alles.
InformationsquelleAutor der Antwort Philip Fourie
Alles, was ist in der Excel-namespace freigegeben werden muß. Zeitraum
Können Sie nicht tun:
Müssen Sie tun
gefolgt von der Freigabe der Objekte.
InformationsquelleAutor der Antwort MagicKat
Ich gefunden eine nützliche generische Vorlage, die helfen kann, implementieren Sie die korrekte Entsorgung ein Muster für COM-Objekte, die Marschall.ReleaseComObject aufgerufen wird, wenn Sie gehen out of scope:
Verwendung:
Vorlage:
Referenz:
http://www.deez.info/sengelha/2005/02/11/useful-idisposable-class-3-autoreleasecomobject/
InformationsquelleAutor der Antwort Edward Wilde
Ich kann nicht glauben, dieses problem verfolgt die Welt für 5 Jahre.... Wenn Sie eine Anwendung erstellt haben, müssen Sie es Herunterfahren ersten, bevor Sie Sie entfernen den link.
beim schließen
Wenn Sie eine neue excel-Anwendung, es öffnet sich ein excel-Programm in den hintergrund. Sie müssen den Befehl, dass excel-Programm beenden, bevor Sie lassen Sie die Verbindung, weil das excel-Programm ist nicht Teil Ihrer direkten Kontrolle. Es wird also offen bleiben, ob der link veröffentlicht wird!
Gut programmiert alle~~
InformationsquelleAutor der Antwort Colin
Erste - Sie nie zu nennen
Marshal.ReleaseComObject(...)
oderMarshal.FinalReleaseComObject(...)
tun, wenn Excel-interop. Es ist eine verwirrende anti-pattern, aber keine Informationen über dieses, auch von Microsoft, die anzeigt, müssen Sie manuell freigeben COM-Verweise aus .NET falsch. Die Tatsache ist, dass die .NET-runtime und garbage collector korrekt nachverfolgen und bereinigen die COM-Verweise. Für deinen code, das heißt, Sie können entfernen Sie das gesamte " while (...) Schleife an der Spitze.Sekunde, wenn Sie wollen, um sicherzustellen, dass die COM-Verweise, um eine out-of-process-COM-Objekt bereinigt werden, wenn ein Prozess beendet wird (so dass der Excel-Prozess wird in der Nähe), die Sie benötigen, um sicherzustellen, dass der garbage collector ausgeführt wird. Sie machen das richtig mit anrufen zu
GC.Collect()
undGC.WaitForPendingFinalizers()
. Der Aufruf dieser zweimal ist sicher und gewährleistet, dass die Zyklen sind definitiv bereinigt zu (obwohl ich nicht sicher bin ob es benötigt wird, und würde schätzen, ein Beispiel, das zeigt dieser).Dritten bei der Ausführung im debugger lokale Referenzen werden künstlich am Leben gehalten, bis das Ende der Methode (so dass die lokalen Variablen arbeiten). So
GC.Collect()
Anrufe sind nicht wirksam für die Reinigung Objekt wierng.Cells
von der gleichen Methode. Sie aufteilen soll der code tun, die COM-interop von der GC Aufräumen in separate Methoden. (Dies war eine wichtige Entdeckung für mich, von einem Teil der Antwort hier gepostet von @nightcoder.)Das Allgemeine Muster wäre also:
Es gibt eine Menge falscher Informationen und die Verwirrung über dieses Thema, darunter auch viele Beiträge auf der MSDN-Website und auf Stack Overflow (und vor allem dieser Frage!).
Was hat mich schließlich überzeugt zu haben, genauer hinzuschauen und herauszufinden, die richtige Beratung war blog-post Marschall.ReleaseComObject Als Gefährlich Eingestuft zusammen mit der Suche nach dem Problem mit Referenzen am Leben gehalten, unter dem debugger, das war verwirrend meiner früheren Tests.
InformationsquelleAutor der Antwort Govert
Gemeinsamen Entwickler, keine der Lösungen hat bei mir,
also entscheide ich mich für die Implementierung eines neuen trick.
Lassen Sie uns zunächst festlegen, "Was ist unser Ziel?" => "Nicht zu sehen, excel-Objekt, nachdem unser job, die im task-manager"
Ok. Lassen Sie nicht die Herausforderung und beginnen, es zu zerstören, aber denken Sie daran, nicht zu zerstören, anderen Instanz os Excel, die parallel laufen.
Also , Holen Sie sich die Liste der aktuellen Prozessoren und Holen PID EXCEL-Prozesse , die dann, sobald Ihre Arbeit erledigt ist, haben wir einen neuen Gast in der Prozesse-Liste mit einer eindeutigen PID ,finden und zerstören.
< beachten Sie alle neuen excel-Prozess während Ihrer excel-Arbeit wird erkannt werden als neue und zerstört >
< Eine bessere Lösung ist, um zu erfassen PID des neu erzeugten excel-Objekt und nur zerstören, dass>
Dies löst mein Problem, hoffe auch von dir.
InformationsquelleAutor der Antwort Mohsen Afshin
Akzeptierte Antwort hier richtig ist, aber beachten Sie auch, dass nicht nur "zwei Punkt" Referenzen müssen vermieden werden, aber auch Objekte, die abgerufen werden über den index. Sie brauchen auch nicht zu warten, bis Sie fertig sind mit dem Programm zu bereinigen, diese Objekte, es ist am besten zum erstellen von Funktionen, reinigen Sie Sie, sobald Sie fertig sind mit Ihnen, wenn möglich. Hier ist eine Funktion, die ich erstellt, weist einige Eigenschaften eines Style-Objekt aufgerufen
xlStyleHeader
:Beachten Sie, dass ich musste
xlBorders[Excel.XlBordersIndex.xlEdgeBottom]
auf eine variable, um Sie zu reinigen, (Nicht wegen der zwei Punkte, die sich auf eine Aufzählung, die nicht freigegeben werden müssen, sondern weil das Objekt das ich mich beziehe, ist tatsächlich ein Border-Objekt, die freigegeben werden müssen).Diese Art der Sache ist nicht wirklich notwendig in standard-Anwendungen, die machen einen tollen job, Aufräumarbeiten nach sich selbst, sondern in ASP.NET Anwendungen, wenn Sie verpassen auch nur eine von diesen, egal wie oft Sie den Aufruf der garbage collector, Excel wird immer noch ausgeführt werden, auf Ihren server.
Es erfordert eine Menge Aufmerksamkeit zum detail und viele test-Ausführungen, während die überwachung der Task-Manager, wenn Sie schreiben den code, aber damit spart man sich die mühevolle verzweifelt auf der Suche durch die Seiten code zu finden, der einen Instanz, die Sie verpasst. Dies ist besonders wichtig bei arbeiten in Schleifen, wo Sie brauchen, um release JEDE INSTANZ ein Objekt ist, obwohl es verwendet die gleichen Variablen-Namen jedes mal, wenn Sie es Schleifen.
InformationsquelleAutor der Antwort Chris McGrath
Hinzufügen Gründe, warum Excel nicht schließen, auch beim erstellen von direkt-refrences für jedes Objekt auf Lesen Sie, die Schöpfung, ist die 'For' - Schleife.
InformationsquelleAutor der Antwort Grimfort
Diese scheint sicher, dass es über-kompliziert. Aus meiner Erfahrung gibt es nur drei wichtige Dinge, um Excel richtig zu schließen:
1: stellen Sie sicher, es gibt keine verbleibenden Verweise auf die excel-Anwendung, die Sie erstellt haben (Sie sollten nur ein wie auch immer; setzen Sie es auf
null
)2: rufen Sie
GC.Collect()
3: Excel geschlossen werden, entweder durch den Benutzer manuell schließen Sie das Programm, oder rufen Sie
Quit
auf die Excel-Objekt. (Beachten Sie, dassQuit
wird funktionieren, wie wenn der Benutzer versucht, das Programm zu schließen, und wird ein Bestätigungs-Dialogfeld, wenn ungespeicherte änderungen vorhanden sind, auch wenn Excel nicht sichtbar ist. Der Benutzer kann auf Abbrechen drücken, und dann wird Excel nicht geschlossen worden.)1 geschehen muss, bevor 2, aber 3 kann jederzeit passieren.
Eine Möglichkeit dies umzusetzen ist, wickeln Sie die interop-Excel-Objekt mit Ihrer eigenen Klasse, erstellen Sie die interop-Instanz im Konstruktor und implementieren Sie IDisposable mit Dispose Suche so etwas wie
Bereinigt excel aus Ihrem Programm-Seite der Dinge. Sobald Excel geschlossen wird (manuell durch den Benutzer oder rufen Sie
Quit
) der Prozess, der Weg gehen wird. Wenn das Programm schon geschlossen ist, dann wird der Prozess verschwindet auf derGC.Collect()
nennen.(Ich bin mir nicht sicher, wie wichtig es ist, aber möchten Sie vielleicht einen
GC.WaitForPendingFinalizers()
Anruf nach derGC.Collect()
nennen, aber es ist nicht unbedingt notwendig, um loszuwerden, der Excel-Prozess.)Dies funktionierte bei mir ohne Problem für Jahre. Halten Sie im Verstand, obwohl, dass, während dies funktioniert, müssen Sie in der Nähe anmutig für ihn zu arbeiten. Sie erhalten weiterhin akkumulieren excel.exe Prozesse, wenn Sie unterbrechen Ihr Programm, bevor Excel bereinigt (in der Regel durch drücken der "Stopp", während das Programm gedebuggt wird).
InformationsquelleAutor der Antwort Dave Cousineau
Nach dem Versuch
GC.Collect()
undGC.WaitForPendingFinalizers()
zweimal am Endedie endgültige Lösung, die funktioniert für mich ist, um einen Satz von
dass wir Hinzugefügt, um das Ende der Funktion ein wrapper wie folgt:
InformationsquelleAutor der Antwort D.G.
Habe ich traditionell folgte die Beratung in VVS Antwort. Jedoch, in einer Anstrengung, um diese Antwort up-to-date mit den neuesten Möglichkeiten, ich denke, dass alle meine zukünftigen Projekte verwenden Sie die "NetOffice" Bibliothek.
NetOffice ist ein vollständiger Ersatz für die Office-PIAs und ist komplett version-Agnostiker. Es ist eine Sammlung von Verwalteten COM-Wrapper, kann mit den Aufräumarbeiten, verursacht oft Kopfschmerzen bei der Arbeit mit Microsoft Office .NET.
Einige der wichtigsten features sind:
Ich bin in keiner Weise verbunden mit dem Projekt, ich habe Sie nur wirklich schätzen die krasse Reduktion von Kopfschmerzen.
InformationsquelleAutor der Antwort BTownTKD
°º¤ø„ Schießen Excel-proc und chew bubble gum „ø¤º°
InformationsquelleAutor der Antwort Antoine Meltzheim
Müssen Sie sich bewusst sein, dass Excel sehr empfindlich auf die Kultur, die Sie unter sowie.
Können Sie feststellen, dass Sie brauchen, um die Kultur EN-US vor dem Aufruf von Excel-Funktionen.
Dies gilt nicht für alle Funktionen - aber einige von Ihnen.
Dies gilt auch dann, wenn Sie mit VSTO.
Details: http://support.microsoft.com/default.aspx?scid=kb;en-us;Q320369
InformationsquelleAutor der Antwort
Folgte ich diesem genau... Aber ich lief in Probleme bei 1 von 1000 mal. Wer weiß, warum. Zeit, um den hammer...
Direkt nach der Excel-Application-Klasse instanziiert wird, bekomme ich den Excel-Prozess, die gerade erstellt wurde.
Dann, sobald ich getan habe, all die oben genannten COM-clean-up, ich stellen Sie sicher, dass der Prozess nicht ausgeführt wird. Wenn es noch läuft, es töten!
InformationsquelleAutor der Antwort craigtadlock
"Verwenden Sie niemals zwei Punkte mit COM-Objekten" ist eine gute Faustregel, um zu vermeiden Leckage von COM-Verweise, aber Excel PIA kann führen zu Leckagen in mehr als offensichtlich auf den ersten Blick.
Einer dieser Wege ist die Anmeldung zu jeder Veranstaltung ausgesetzt, die durch die Excel-Objekt-Modell der COM-Objekte.
Zum Beispiel, Abonnement, um die Application-Klasse ist WorkbookOpen-Ereignis.
Einige Theorie auf COM-Ereignisse
COM-Klassen setzen eine Gruppe von Ereignissen durch call-back-Schnittstellen. Um Ereignisse zu abonnieren, die mit dem client-code registrieren Sie sich einfach ein Objekt der Implementierung der call-back-Schnittstelle und der COM-Klasse werden die Methoden aufrufen, die in Reaktion auf bestimmte Ereignisse. Da die call-back-Schnittstelle eine COM-Schnittstelle, ist es die Pflicht der Umsetzung-Objekt dekrementiert den Verweiszähler von jedem COM-Objekt erhält (als parameter) für den Ereignis-Handler.
Wie Excel PIA aussetzen COM-Ereignisse
Excel-PIA stellt COM-Ereignisse von Excel-Application-Klasse als konventionelle .NET-events. Wenn der client-code abonniert ein .NET event (Betonung auf 'a'), PIA schafft eine Instanz einer Klasse die Implementierung der call-back-Schnittstelle und registriert Sie mit Excel.
Daher, eine Nummer des call-back-Objekte registriert mit Excel in der Reaktion auf die verschiedenen Abonnement-Anfragen aus .NET-code. Ein call-back-Objekt pro Ereignis-Abonnement.
Einen call-back-Schnittstelle für event-handling bedeutet, dass, PIA hat zu abonnieren, um alle Schnittstellen-Ereignisse für jeden .NETZ-Ereignis-Abonnement-Anfrage. Es kann nicht wählen, und wählen. Auf ein Ereignis empfangen call-back, call-back-Objekt prüft, ob der Zusammenhang .NET event handler ist daran interessiert, das current-Ereignis ist oder nicht und dann entweder ruft der hf oder ignoriert die call-back.
Wirkung auf die COM Instanz Referenzzähler
All diese call-back Objekte nicht dekrementiert den Verweiszähler jede von der COM-Objekte, die Sie erhalten (als Parameter) für alle von der call-back-Methoden (auch für diejenigen, die werden stillschweigend ignoriert). Sie verlassen sich ausschließlich auf die CLR garbage collector freizugeben, die COM-Objekte.
Da GC-Ausführung ist nicht-deterministisch, das kann dazu führen das der Betrieb aus der Excel-Prozess für eine längere Dauer als gewünscht, und erstellen Sie einen Eindruck von einem 'memory leak'.
Lösung
Die einzige Lösung besteht derzeit darin, zu vermeiden, die PIA ist event-provider für die COM-Klasse und schreiben Sie Ihre eigene event-Anbieter, die deterministisch Versionen von COM-Objekten.
Für die Anwendung Klasse, diese kann getan werden, durch die Umsetzung der AppEvents-Schnittstelle und registrieren die Umsetzung mit Excel, mit IConnectionPointContainer-Schnittstelle. Die Anwendung der Klasse (und für diese Angelegenheit alle COM-Objekte freilegen-events mit callback-Mechanismus) die IConnectionPointContainer-Schnittstelle implementiert.
InformationsquelleAutor der Antwort Amit Mittal
Als andere betont haben, müssen Sie erstellen eine explizite Referenz für jede Excel-Objekt, das Sie verwenden, und rufen Sie Marschall.ReleaseComObject auf den Verweis, wie beschrieben in in diesem KB-Artikel. Sie müssen auch verwenden Sie try/finally um sicherzustellen ReleaseComObject wird immer aufgerufen, auch wenn eine Ausnahme geworfen wird. I. e. statt:
müssen Sie etwas tun, wie:
Müssen Sie auch call-Anwendung.Beenden Sie vor der Freigabe des Application-Objekts, wenn Sie möchten Excel zu schließen.
Wie Sie sehen können, dies wird schnell extrem unhandlich, sobald Sie versuchen zu tun, was auch nur mäßig Komplex. Ich habe erfolgreich entwickelt .NET-Anwendungen mit einem einfachen wrapper-Klasse, wickelt ein paar einfache Griffe für die Excel-Objekt-Modell (eine Arbeitsmappe öffnen, schreiben Sie eine Reihe, speichern/schließen Sie die Arbeitsmappe, etc). Die wrapper-Klasse implementiert IDisposable, sorgfältig implementiert Marschall.ReleaseComObject auf jedem Objekt, das es benutzt, und nicht pubicly auszusetzen, Excel-Objekte, um den rest der app.
Aber dieser Ansatz nicht gut skaliert für komplexere Anforderungen.
Dies ist ein großer Mangel .NET COM-Interop. Für komplexere Szenarien, ich würde ernsthaft erwägen, dem schreiben von ActiveX-DLL in VB6 oder anderen nicht verwalteten Sprache, die Sie delegieren können alle Interaktionen mit out-proc-COM-Objekte, wie etwa Office. Sie können dann auf diese ActiveX-DLL aus Ihrer .NET-Anwendung, und die Dinge werden viel einfacher, da Sie nur freigeben müssen diese eine Referenz.
InformationsquelleAutor der Antwort Joe
Wenn alle die Sachen, die oben nicht funktioniert, versuchen Sie geben Sie Excel einige Zeit, um in der Nähe seiner Blätter:
InformationsquelleAutor der Antwort spiderman
Stellen Sie sicher, dass Sie lassen Sie alle Objekte im Zusammenhang mit Excel!
Ich verbrachte ein paar Stunden mit dem Versuch mehrere Möglichkeiten. Alle sind tolle Ideen, aber ich fand schließlich mein Fehler: Wenn Sie nicht lassen Sie alle Objekte, keine der Möglichkeiten oben kann Ihnen helfen, wie in meinem Fall. Stellen Sie sicher, Sie lassen Sie alle Objekte, einschließlich der Auswahl!
Die Optionen sind zusammen hier.
InformationsquelleAutor der Antwort Ned
Den zwei-Punkte-Regel hat nicht funktioniert für mich. In meinem Fall erstellte ich eine Methode, um zu reinigen meine Ressourcen wie folgt:
InformationsquelleAutor der Antwort Hahnemann
Sollten Sie sehr vorsichtig sein mit Word/Excel-interop-Anwendungen. Nach dem Versuch, alle Lösungen, die wir hatten noch eine Menge von "WinWord" Prozess-Links öffnen auf dem server (mit mehr als 2000 Benutzer).
Nach der Arbeit auf das problem für Stunden, ich erkannte, dass wenn ich mehr als ein paar Dokumente mit
Word.ApplicationClass.Document.Open()
auf verschiedene threads gleichzeitig, IIS-Arbeitsprozess (w3wp.exe) Abstürzen würde, verlassen alle WinWord-Prozesse öffnen!So, ich denke, es gibt keine absolute Lösung für dieses problem, aber der Wechsel zu anderen Methoden wie Office Open XML Entwicklung.
InformationsquelleAutor der Antwort Arvand
Einen großen Artikel über die Freigabe von COM-Objekten ist 2.5 Freigabe von COM-Objekten (MSDN).
Die Methode, die ich befürworten würde, ist null Ihr Excel.Interop-Referenzen, wenn Sie sind nicht-lokale Variablen und rufen dann
GC.Collect()
undGC.WaitForPendingFinalizers()
zweimal. Lokal gültigen Interop-Variablen werden automatisch erledigt.Damit entfällt die Notwendigkeit, halten Sie eine benannte Referenz für jeder COM-Objekt.
Hier ist ein Beispiel aus dem Artikel:
Diese Worte sind direkt aus dem Artikel:
InformationsquelleAutor der Antwort
Meine Lösung
InformationsquelleAutor der Antwort Loart
Akzeptiert die Antwort nicht für mich arbeiten. Der folgende code im Destruktor hat den job.
InformationsquelleAutor der Antwort Martin
Ich bin momentan auf Office-Automatisierung und haben stolperte über eine Lösung für dieses, funktioniert jedes mal für mich. Es ist einfach und nicht um zu töten alle Prozesse.
Scheint es, dass allein durch die Schleife durch die aktuellen aktiven Prozesse, und in irgendeiner Weise 'Zugriff auf eine offene Excel-Prozess, jede streunende hängen Instanz von Excel entfernt werden. Den code unten einfach überprüft, ob Prozesse, in denen der name 'Excel', dann schreibt die MainWindowTitle-Eigenschaft des Prozesses in einen string. Diese 'Interaktion' mit dem Prozess zu machen scheint Windows aufholen und bricht die gefrorenen Instanz von Excel.
Ich führen Sie die folgenden Verfahren, kurz bevor das add-in die ich die Entwicklung beendet, als es feuert es das entladen-Ereignis. Es entfernt alle hängen Instanzen von Excel zu jeder Zeit. In aller Ehrlichkeit, ich bin nicht völlig sicher, warum dies funktioniert, aber es funktioniert gut für mich und konnte sich am Ende der Excel-Anwendung ohne sich sorgen über ein double dots, Marschall.ReleaseComObject, noch töten Prozesse. Ich wäre sehr daran interessiert, irgendwelche Vorschläge, warum dies so ist, wirksam.
InformationsquelleAutor der Antwort Tom Brearley
Ich denke, dass einige, die genau so ist, dass das framework übernimmt Office-Anwendungen, aber ich könnte falsch sein. An manchen Tagen, einige Anwendungen bereinigen, die Prozesse sofort, und an anderen Tagen scheint es, zu warten, bis die Anwendung geschlossen wird. In allgemein, beende ich die Aufmerksamkeit auf die details und stellen Sie sicher, dass es keine zusätzlichen Prozesse im Umlauf am Ende des Tages.
Auch, und vielleicht bin ich über die Vereinfachung Dinge, aber ich denke, man kann nur...
Wie gesagt, ich glaube nicht, neigen dazu, die Aufmerksamkeit auf die details, wenn Sie die Excel-Prozess angezeigt wird oder verschwindet, aber das funktioniert in der Regel für mich. Ich weiß auch nicht wie zu halten, Excel-Prozesse, um für etwas anderes als die minimale Menge an Zeit, aber ich bin wahrscheinlich einfach nur paranoid.
InformationsquelleAutor der Antwort bill_the_loser
Da haben einige wohl schon geschrieben, es ist nicht nur wichtig, wie du schließen das Excel-Objekt (Objekt); es ist auch wichtig, wie du öffnen und auch von der Art des Projekts.
In einer WPF Anwendung, die im Grunde den gleichen code arbeiten ohne oder mit sehr wenige Probleme.
Ich habe ein Projekt, in dem die gleichen Excel-Datei bearbeitet wird, mehrere Male mit unterschiedlichen parameter-Wert - z.B. Analyse, basierend auf Werte in einer generischen Liste.
Ich habe alle Excel-Funktionen in der Basisklasse, und parser, die in einer Unterklasse (verschiedene Parser verwenden Allgemeine Excel-Funktionen). Ich wollte nicht, dass Excel geöffnet und wieder geschlossen, die für jedes Element in einer generischen Liste, also habe ich öffnete es nur einmal in der Basisklasse und in der Nähe es in der Unterklasse. Ich hatte Probleme beim bewegen der code in einer desktop-Anwendung. Ich habe versucht, viele der oben genannten Lösungen.
GC.Collect()
bereits implementiert vor, zweimal als vorgeschlagen.Dann habe ich entschieden, dass ich den code zum öffnen Excel in eine Unterklasse. Anstatt zu öffnen, nur einmal, jetzt habe ich ein neues Objekt erstellen (Basis-Klasse) und öffnen Sie Excel für jedes Element, und schließen Sie es am Ende. Es gibt einige performance-Einbußen, aber basierend auf mehreren tests Excel-Prozesse schließen ohne Probleme (im debug Modus), also auch temporäre Dateien entfernt werden. Ich werde weiter testen und mehr dazu schreiben, wenn ich werde einige updates.
Die Quintessenz ist: Sie müssen auch überprüfen Sie die Initialisierung code, vor allem, wenn Sie viele Klassen, etc.
InformationsquelleAutor der Antwort Blaz Brencic