WinWord.exe won't quit after calling Word.Documents.Add - Word .NET Interop

24,086

Solution 1

I figured out that the use of Documents.Add() when using a custom template is to blame. I can't explain why this would leave WinWord.exe hanging. However there are other ways to create documents from templates that don't result in the same problem.

So I replaced:

Dim doc As Word.Document = documents.Add(Template:=CObj(templatePath))

with:

Dim doc As Word.Document = documents.Add()  
doc.AttachedTemplate = templatePath  
doc.UpdateStyles()

Using AttachedTemplate to specify the template works for me and doesn't leave WinWord.exe hanging.

(One new issue has arisen however... An image in the template's footer does not get copied to the document when using AttachedTemplate/UpdateStyles. I'm taking that up as a separate issue. But since this method solves my original problem, I'm satisfied. Thanks to everyone who offered answers!)

Solution 2

(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);

Solution 3

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.

Solution 4

I got the same problema when i was doing it:

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

I solved this way:

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

Don't ask me why, automating office is an adventure :)

Solution 5

I've only done Excel automation, but have run into similar problems. Referencing some old code, the final step in closing has the line GC.Collect()

This article mentions it too: http://support.microsoft.com/kb/317109

Share:
24,086
Keith
Author by

Keith

agile development, software architecture, AI, machine learning, design patterns, domain and database design... .NET, SQL Server, ASP.NET MVC, Web API, Angular.js, Node.js, Javascript, JQuery, Lucene, PHP/Perl, regular expressions, full text search...

Updated on July 09, 2022

Comments

  • Keith
    Keith almost 2 years

    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.

  • MadBoy
    MadBoy about 14 years
    If you don't use try / finally indeed it's a must to use GC.Collect as i had multiple excels stay open after tasks are done. However when i was using try / finally excel always closed properly. Of course in finally i always had 3x Marshal.ReleaseComObject(...);
  • Keith
    Keith about 14 years
    Thanks for pointing that out. I am disposing the oDocuments object, I had just forgotten to put it in my example. The example is fixed now but the problem remains...
  • MadBoy
    MadBoy about 14 years
    Tried to use Try / Finally ? Keith ?
  • Keith
    Keith about 14 years
    Thanks. I added GC.Collect() to the end of my disposal step but still no luck.
  • Keith
    Keith about 14 years
    Thanks but adding the try..catch..finally block doesn't help. I've narrowed it down further to the fact that I'm using a custom template...please see the updates in my original post.
  • Dirk Vollmar
    Dirk Vollmar about 14 years
    Usually it is a good idea to set Application.DisplayAlerts = wdAlertsNone. This prevents most of Word dialog boxes to pop up (unfortunately some rare dialogs could still be blocking, e.g. a message about uninstalled proofing tools) .
  • Keith
    Keith about 14 years
    Microsoft recommends discarding every object that is referenced (in this case that includes the Document object) in the article that OG posted: support.microsoft.com/kb/317109
  • Keith
    Keith about 14 years
    Thanks for the tip. It didn't solve my problem but this looks like a cleaner and more stable way of cleaning up COM objects.
  • Sheng Jiang 蒋晟
    Sheng Jiang 蒋晟 about 14 years
    looks like we have different understand of discarding. Do you discard by clean up?
  • Dirk Vollmar
    Dirk Vollmar about 14 years
    Please note that this is not a general problem with templates, but it is specific to the template that you are using. In general, you original code is the way to create documents from a template.
  • Keith
    Keith about 14 years
    As a follow up -- There is definitely a memory leakage issue when using the Word interop to create docs based on templates, and even when working with existing docs created from templates. I believe this happens because such documents cause a Template com object to be automatically created and added to the Application object's Templates collection, thus not giving the developer the chance to reference and properly dispose of it. Another work-around I found is to use OpenXml to open an existing document (not a template) and insert into content controls.
  • Keith
    Keith over 11 years
    Dinah's answer here is a great guideline for all Office interop development and will likely solve most people's issues. However my issue turned out to be caused by the use of templates. I address this in the answer that I posted.
  • Keith
    Keith about 11 years
    Are there any downsides to setting oWord.Visible = True?
  • jivangilad
    jivangilad over 4 years
    Wow thanks. This was a life saver. No joke. When I moved to production and it didn't work. That was stressfull.