2010-03-24 4 views
18

Ich bin in das klassische Szenario, wo, beim Erstellen von Word-COM-Objekten in .NET (über das Microsoft.Office.Interop.Word Assembly) wird der WinWord-Prozess nicht beendet, obwohl ich properly closing and releasing the objects bin.WinWord.exe wird nicht beendet nach dem Aufrufen von Word.Documents.Add - Word .NET Interop

Ich habe es auf die Verwendung der Word.Documents.Add() -Methode eingeschränkt. Ich kann problemlos mit Word arbeiten (Öffnen von Dokumenten, Ändern von Inhalten usw.) und WinWord.exe wird beendet, wenn ich es sage. Es ist einmal ich benutze die Add() -Methode (und nur beim Hinzufügen einer Vorlage), dass der Prozess ausgeführt wird.

Hier ist ein einfaches Beispiel, das das Problem reproduziert:

Dim word As New Word.Application() 
word.Visible = False 

Dim documents As Word.Documents = word.Documents 
Dim doc As Word.Document = documents.Add(Template:=CObj(templatePath), NewTemplate:=False, DocumentType:=Word.WdNewDocumentType.wdNewBlankDocument, Visible:=False) 

'' dispose objects 
doc.Close() 
While (Marshal.ReleaseComObject(doc) <> 0) 
End While 
doc = Nothing 

While (Marshal.ReleaseComObject(documents) <> 0) 
End While 
documents = Nothing 

word.Quit() 
While (Marshal.ReleaseComObject(word) <> 0) 
End While 
word = Nothing 

GC.Collect() 

Wie Sie mir das Erstellen und Anordnen der Objekte richtig den zusätzlichen Schritt zu Schleife Marsha.ReleaseComObject, auch sehen können, nehmen, bis sie die richtige zurück Code. Das Arbeiten mit den Word-Objekten ist in anderer Hinsicht in Ordnung, es ist nur das nervtötende Documents.Add, das mir Kummer bereitet. Wird in diesem Prozess ein anderes Objekt erstellt, das ich referenzieren und entsorgen muss? Gibt es noch einen weiteren Entsorgungsschritt, dem ich folgen muss? Etwas anderes? Ihre Hilfe wird sehr geschätzt :)

Update: Ich habe versucht GC.Collect am Ende der Entsorgung Schritt aber immer noch kein Glück.

Update 2: Ich habe das Problem auf die Verwendung von benutzerdefinierten Vorlagen eingegrenzt. Beim Aufrufen von Documents.Add (...) gebe ich eine benutzerdefinierte Vorlage für das neue Dokument an. Wenn ich dies nicht mache und stattdessen Add() ohne Parameter aufruft, passiert das Problem nicht.

+0

Dies könnte auch ein Problem mit einer benutzerdefinierten Vorlage sein. Funktioniert es, wenn Sie einfach 'oWord.Documents.Add()' aufrufen? –

+0

Danke, super Vorschlag! Es funktioniert, wenn ich nur Addiere, so ist es die benutzerdefinierte Vorlage, die das Problem irgendwie verursacht. Ich werde weiter graben. – Keith

+0

Wenn es dann ist, dann wird vielleicht Jim Leonardo Lösung helfen. Lass es Word zeigen, was es tut, vielleicht wartet eine Dialogbox oder etwas darauf. – MadBoy

Antwort

2

Ich fand heraus, dass die Verwendung von Documents.Add() bei Verwendung einer benutzerdefinierten Vorlage ist schuld. Ich kann nicht erklären, warum WinWord.exe hängen würde. Es gibt jedoch andere Möglichkeiten, Dokumente aus Vorlagen zu erstellen, die nicht zu dem gleichen Problem führen.

So ersetzt I:

Dim doc Wie Word.Document = Documents.Add (Vorlage: = CObj (templatePath))

mit:

Dim doc Wie Word.Document = documents.Add()
doc.AttachedTemplate = Vorlage Pfad
doc.UpdateStyles()

Mit AttachedTemplate, um die Vorlage funktioniert für mich funktioniert und bleibt WinWord.exe hängen.

(Ein neues Problem ist jedoch aufgetreten ... Ein Bild in der Fußzeile der Vorlage wird nicht in das Dokument kopiert, wenn AttachedTemplate/UpdateStyles verwendet wird. Ich nehme das als separates Problem auf. Aber da diese Methode meine löst ursprüngliches Problem, ich bin zufrieden Vielen Dank an alle, die mit Antworten angeboten)

+0

Bitte beachten Sie, dass dies * nicht * ein generelles Problem mit Vorlagen ist, aber es ist spezifisch für die Vorlage, die Sie verwenden. Im Allgemeinen ist der Originalcode die Methode zum Erstellen von Dokumenten aus einer Vorlage. –

+0

Als Folge - Es gibt definitiv ein Memory-Leak-Problem, wenn Sie das Word-Interop zum Erstellen von Dokumenten verwenden, die auf Vorlagen basieren, und sogar wenn Sie mit vorhandenen Dokumenten arbeiten, die aus Vorlagen erstellt wurden. Ich glaube, dass dies passiert, weil solche Dokumente dazu führen, dass ein Template-com-Objekt automatisch erstellt und der Vorlagen-Sammlung des Application-Objekts hinzugefügt wird, so dass der Entwickler nicht die Möglichkeit hat, zu referenzieren und ordnungsgemäß zu disponieren. Eine andere Problemumgehung, die ich fand, ist die Verwendung von OpenXml, um ein vorhandenes Dokument (keine Vorlage) zu öffnen und in Inhaltssteuerelemente einzufügen. – Keith

0

hat "oDocuments" eine .Dispose() oder .Close() Methode? Du entsorgst die anderen 2, aber nicht diese.

+0

Vielen Dank, dass Sie darauf hingewiesen haben. Ich entsorge das oDocuments-Objekt, ich hatte es einfach vergessen, es in mein Beispiel zu schreiben. Das Beispiel ist jetzt behoben, aber das Problem bleibt ... – Keith

+0

Versucht, Try/Endlich zu verwenden? Keith? – MadBoy

2

Ich habe nur Excel-Automatisierung, aber ähnliche Probleme aufgetreten sind. Referenzierung einige alte Code, hat der letzte Schritt bei der Schließung der Linie GC.Collect()

Dieser Artikel erwähnt es auch: http://support.microsoft.com/kb/317109

+0

Wenn Sie try/schließlich nicht verwenden, ist es ein Muss, GC.Collect zu verwenden, da ich mehrere Excel-Funktionen geöffnet habe, nachdem Aufgaben erledigt wurden. Allerdings habe ich bei try/finally Excel immer richtig geschlossen. Natürlich hatte ich schließlich immer 3x Marshal.ReleaseComObject (...); – MadBoy

+0

Danke. Ich habe GC.Collect() am Ende meines Entsorgungsschrittes hinzugefügt, aber immer noch kein Glück. – Keith

0

Obwohl diese C# ist aber vielleicht wird es Ihnen helfen. Ich verwende diese Methode, um mehrere Dokumente zu einem zusammenzuführen. Ich übergebe alle Dokumente in Arraylist, und Word scheint nach Abschluss ordnungsgemäß zu schließen.

public static void documentsMerge(object fileName, ArrayList arrayList) { 
     // object fileName = Path.Combine(Environment.CurrentDirectory, @"NewDocument.doc"); 
     File.Delete(fileName.ToString()); 
     try { 
      wordApplication = new ApplicationClass(); 
      var doc = wordApplication.Documents.Add(ref missing, ref missing, ref missing, ref missing); 
      try { 
       doc.Activate(); 
       int count = 0; 
       foreach (var alItem in arrayList) { 
        addDocument(alItem, doc, count == 0); 
        count++; 
       } 
       // addDocument(@"D:\Projects\WordTests\ConsoleApplication1\Documents\Doc1.doc", doc) ; //, false); 
       // addDocument(@"D:\Projects\WordTests\ConsoleApplication1\Documents\Doc2.doc", doc) ; //, true); 
       doc.SaveAs(ref fileName, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing); 
      } finally { 
       doc.Close(ref missing, ref missing, ref missing); 
      } 
     } finally { 
      wordApplication.Quit(ref missing, ref missing, ref missing); 
     } 
    } 

Der schließlich Block ist nützlich für cleaning up irgendwelche im try-Block zugewiesenen Ressourcen sowie beliebigen Code ausführen, die selbst ausführen muß, wenn es eine Ausnahme ist. Die Steuerung wird immer an den finally-Block übergeben, unabhängig davon, wie der try-Block beendet wird.

Also versuchen Sie, Ihren Code in try/finally blockieren und sehen, wie es sich dann verhält?

Für VB.NET

Try 
' Statement which can cause an exception. 
Catch x As Type 
' Statements for handling the exception 
Finally 
End Try 'Any cleanup code 
+0

Danke, aber das Hinzufügen des Versuches .. Catch..finally Block hilft nicht. Ich habe es weiter darauf beschränkt, dass ich eine benutzerdefinierte Vorlage verwende ... bitte sehen Sie die Updates in meinem ursprünglichen Beitrag. – Keith

2

Versuchen GC.WaitForPendingFinalizers() aufrufen und mit Marshal.FinalReleaseComObject statt Marshal.ReleaseComObject. Dies beseitigt die Notwendigkeit, es zu loopen.

Aktualisieren Sie Ihren Code auf diese und versuchen Sie es (die GC Anrufe sind am Anfang absichtlich):

GC.Collect() 
GC.WaitForPendingFinalizers() 

oDoc.Close() 
Marshal.FinalReleaseComObject(oDoc) 

Marshal.FinalReleaseComObject(oDocuments) 

oWord.Quit() 
Marshal.FinalReleaseComObject(oWord) 

Sie könnten auch this related question diskutieren das Problem für Excel prüfen wollen.

+0

Danke für den Tipp. Es hat mein Problem nicht gelöst, aber das sieht nach einer saubereren und stabileren Methode zur Bereinigung von COM-Objekten aus. – Keith

4

Haben Sie versucht,

Ändern
oWord.Visible = False 

zu

oWord.Visible = True 

?

Ich frage, weil Word Sie bitten könnte, etwas zu tun, das mit dieser Vorlage verwandt ist, die Sie verwenden möchten. Wenn es denkt, dass ein Dialog angezeigt wird, wird es normalerweise nicht heruntergefahren. IIRC, es gibt eine Möglichkeit, Quit zu tun, so dass Quit erzwungen wird und nicht auf Dialoge gewartet wird. Aber es ist eine Weile her.

+2

Normalerweise ist es eine gute Idee, 'Application.DisplayAlerts = wdAlertsNone' zu ​​setzen. Dies verhindert, dass die meisten Word-Dialogfelder auftauchen (leider können einige seltene Dialoge immer noch blockiert werden, z. B. eine Meldung über deinstallierte Proof-Tools). –

0

You should not discard the document object created in Word.Documents.Add. Speichern und rufen Sie Marshal.ReleaseComObject für jedes COM-Objekt auf, das Sie von der Automatisierung erhalten, wenn Sie fertig sind, also if you do not cache the objects anywhere.

+0

Microsoft empfiehlt, jedes Objekt, auf das verwiesen wird (in diesem Fall das Dokumentobjekt), in dem Artikel zu verwerfen, den OG veröffentlicht hat: http://support.microsoft.com/kb/317109 – Keith

+0

sieht so aus, als hätten wir das Verwerfen anders verstanden. Verwerfen Sie durch Aufräumen? –

1

ich das gleiche problema bekam, wenn ich es tat.!

object missing = System.Reflection.Missing.Value; 
wordApplication.Quit(ref missing, ref missing, ref missing); 

ich auf diese Weise gelöst:

object objFalse = false; 
wordApplication.Quit(ref objFalse, ref objFalse, ref objFalse); 

Frag mich nicht warum, automatisieren Büro ist ein Abenteuer :)

9

(Alle meine Beratung ist von this answer über Excel-Interop angepasst.

)

Es gibt ein paar wichtige Dinge hier:

1) Verwenden Sie niemals 2 Punkte auf der gleichen Linie. Sehen Sie sich auch einen Indexer als Punkt

Gut

Word.Documents d = wordApp.Documents; 
Word.Document aDoc = d.Open(/*...*/); 

BAD

Word.Document aDoc = wordApp.Documents.Open(/*...*/); 

2) Lassen Sie alle Ihre Zeiger.

3) Nein, wirklich, gehen Sie zurück und veröffentlichen Sie alle Ihre Zeiger, Sie haben irgendwo einen verpasst (oder zumindest immer).

Hier ist ein vollständiges Beispiel von dem, was für mich ENDLICH arbeitete an einem Projekt nach viel Heulen und Zähneknirschen:

object m = Missing.Value; 
// this must be an object, not a string. if you forget though, 
// intellisense will remind you 
object oFilename = @"C:\my sheet.doc"; 

object readOnly = false; 
object isVisible = false; 

Word.Application wordApp = new Word.ApplicationClass(); 
wordApp.Visible = false; 
// remember: don't use 2 dots on 1 line 
Word.Documents d = wordApp.Documents; 
Word.Document aDoc = d.Open(ref oFilename, ref m, ref readOnly, ref m, 
    ref m, ref m, ref m, ref m, ref m, ref m, ref m, ref isVisible, 
    ref m, ref m, ref m, ref m); 
aDoc.Activate(); 

object findText = "my old value"; 
object replaceText = "new and improved value"; 

object oTrue = true; 
object oFalse = false; 
object replace = 2; 
object wrap = 1; 

Word.Selection s = wordApp.Selection; 
Word.Find f = s.Find; 
f.Execute(ref findText, ref oTrue, 
    ref oTrue, ref oFalse, ref oFalse, 
    ref oFalse, ref oTrue, ref wrap, ref oFalse, 
    ref replaceText, ref replace, ref oFalse, ref oFalse, 
    ref oFalse, ref oFalse); 

aDoc.SaveAs(ref oFilename, ref m, ref m, ref m, ref m, ref m, ref m, 
    ref m, ref m, ref m, ref m, ref m, ref m, ref m, ref m, ref m); 

object doNotSaveChanges = Word.WdSaveOptions.wdDoNotSaveChanges; 
// casting here because intellisense complained of ambiguity 
(aDoc as Word._Document).Close(ref doNotSaveChanges, ref m, ref m); 

// release each in the reverse of the order in which it was first used 
// ReleaseComObject might also work as well. I haven't tested yet 
Marshal.FinalReleaseComObject(f); 
Marshal.FinalReleaseComObject(s); 
Marshal.FinalReleaseComObject(aDoc); 
Marshal.FinalReleaseComObject(d); 

// must quit app before releasing 
// again: casting because intellisense complained of ambiguity 
(wordApp as Word._Application).Quit(ref m, ref m, ref m); 
Marshal.FinalReleaseComObject(wordApp); 
+2

Dinahs Antwort hier ist eine großartige Richtlinie für alle Office-Interop-Entwicklungen und wird wahrscheinlich die Probleme der meisten Leute lösen. Mein Problem wurde jedoch durch die Verwendung von Vorlagen verursacht. Ich adressiere das in der Antwort, die ich gepostet habe. – Keith

0
oWord.Visible = True 

das Problem für mich gelöst. Das zugrunde liegende Problem war die Wiederherstellung von Dokumenten. Ein Dialog wurde erscheint trotz einer Linien:

_wordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone; 

ich jeden Trick verwendet, die hier gezeigt wurde, aber bis das Dokument Recovery-Liste ein „Zombie“ Wort Prozess hinter jedem Mal wurde gelöscht gelassen wurde meine Bewerbung lief.

+0

Gibt es Nachteile beim Festlegen von 'oWord.Visible = True'? – Keith

0

dies ist eine perfekte lösung, ich hatte das gleiche problem, ich folgte nur diesem und es funktioniert perfekt.

Objekt objFalse = false;

wordApplication.Quit (ref objFalse, ref objFalse, ref objFalse);

1

Ich stieß auf Ihren Beitrag wegen eines ähnlichen Problems mit der Vorlage. Ich würde eine Nachricht erhalten, die mich auffordert, die .dotm-Datei zu speichern, wenn ich versuche, das Wort in meinem Programm zu schließen. Ich konnte Ihre akzeptierte Antwort nicht verwenden, da ich keinen genauen Vorlagenpfad habe. Ich öffne einfach jedes Dokument, das das Programm erhält.

was früher I

Word.NormalTemplate.Saved = true; 

, wenn ich diesen Code verwendet, bevor ich von der Anwendung angeordnet ist, wäre es nicht mehr den Dialog aufzurufen sagen, dass ich nicht die Vorlage gespeichert hatte, und es würde die Entsorgung laufen ohne den unerwünschten Prozess "winWord.exe" laufen zu lassen.

Ich habe den "NormalTemplate.Saved" Tipp vom Benutzer "NeedSomeAnswers" auf den Visual Basic-Foren here. In seinen Worten "[es] speichert nicht wirklich zur Normalen, teilt es nur mit, dass die Normale bereits gespeichert wurde, so dass sie es nicht speichern muss".

Ich denke, das ist eine zweite Antwort auf das gleiche Problem. Ich hoffe, es hilft.

Einen schönen Tag haben und gut sein.

-alle Tag Ihr Code funktioniert, ist ein guter Tag zum celebrate-

0

ich versucht hatte, die Dokumenterstellung in Wort von vb.net zu automatisieren, aber winword.exe noch lief, auch nachdem ich das Dokument geschlossen . Ich stolperte über eine Lösung für dieses Problem; Ich habe das Dim des Word-Objekts in die Subroutine verschoben, die ich zum Bearbeiten des Dokuments verwendet habe, anstatt es unabhängig von einer Subroutine (meiner ursprünglichen Methode) zu bemaßen.

Hoffe, das hilft.

Verwandte Themen