I'm running into the classic scenario where, when creating Word COM objects in .NET (via the Microsoft.Office.Interop.Word assembly), the WinWord process won't exit even though I'm properly closing and releasing the objects.
I've narrowed it down to the use of the Word.Documents.Add() method. I can work with Word in other ways without a problem (opening documents, modifying contents, etc) and WinWord.exe quits when I tell it to. It's once I use the Add() method (and only when adding a template) that the process is left running.
Here is a simple example which reproduces the problem:
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()
As you can see I'm creating and disposing the objects properly, even taking the extra step to loop Marsha.ReleaseComObject until it returns the proper code. Working with the Word objects is fine in other regards, it's just that pesky Documents.Add that is causing me grief. Is there another object that gets created in this process that I need to reference and dispose of? Is there another disposal step I need to follow? Something else? Your help is much appreciated :)
Update:
I tried GC.Collect at the end of the disposal step but still no luck.
Update 2:
I've narrowed the problem down to the use of custom templates. When I invoke Documents.Add(...) I specify a custom template for the new document. If I don't do this and instead invoke Add() with no parameters, then the problem does not happen.
1. Click Start>Run> type “cmd” and hit enter or click 'OK'. You will notice that all Winword.exe processes are terminated now.
winword.exe is the executable file name for Microsoft Word which is used when Word is launched. The word WinWord stands for Windows Word (Microsoft Word). This software component is also used by other applications such as Outlook when attachments are to be viewed either in Outlook or in another window in Word.
Winword.exe is Microsoft Word, the most popular word processing software. If you've ever written a document for work or school you most likely used Microsoft Word. Publisher: Winword.exe should be signed by Microsoft Corporation. Winword.exe stands for Windows Word, or Microsoft Word.
(All of my advice is adapted from this answer about Excel interop.)
There are a few important things here:
1) Never use 2 dots on the same line. Also consider an indexer as a dot
Good
Word.Documents d = wordApp.Documents;
Word.Document aDoc = d.Open(/*...*/);
BAD
Word.Document aDoc = wordApp.Documents.Open(/*...*/);
2) Release all of your pointers.
3) No really, go back and release all of your pointers, you missed one somewhere (or at least I always do).
Here's a full example of what FINALLY worked for me on one project after much wailing and gnashing of teeth:
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);
Have you tried changing
oWord.Visible = False
to
oWord.Visible = True
?
I ask because Word may be asking you to do something that's related to this template you are trying to use. If it thinks there's a dialog showing, it will normally not shut down. IIRC, there's a way to do Quit so that it forces Quit and won't wait on any dialogs. But, it's been a while.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With