Maxim Gershkovich
Maxim Gershkovich

Reputation: 47149

Disposing of Microsoft.Office.Interop.Word.Application

(Somewhat of a follow on from the post (which remains unanswered): https://stackoverflow.com/q/6197829/314661)

Using the following code

Application app = new Application();
_Document doc = app.Documents.Open("myDocPath.docx", false, false, false);
doc.PrintOut(false);
doc.Close();

I am attempting to open and print a file programmatically.

The problem is each time I run the above code a new WINWORD.exe process is started and obviously this quickly eats up all the memory.

The application class doesn't seem to contain a dispose/close or similar method.

After a bit of research I (realized) and changed the code to the following.

 Application app = new Application();
 _Document doc = app.Documents.Open(fullFilePath + ".doc", false, false, false);
 doc.PrintOut(false);
 doc.Close();
 int res = System.Runtime.InteropServices.Marshal.ReleaseComObject(doc);
 int res1 = System.Runtime.InteropServices.Marshal.ReleaseComObject(app);

And I can see the remaining reference count is zero but the processes remain?

PS: I'm using Version 14 of the Microsoft.Office.Interop library.

Upvotes: 44

Views: 80457

Answers (9)

Roman Kokhnovets
Roman Kokhnovets

Reputation: 1

In my case it was because i called wordApp.Quit() instead of wordApp.Quit(false). Just added false to call of this method and now it works fine.

Upvotes: 0

Jordan Ryder
Jordan Ryder

Reputation: 2812

Agreed with other posters that GC.Collect() and Marshal.ReleaseComObject() is not needed. If the process still exists after running app.Quit(false), it might be because you're running the app invisible, and there is a prompt that is preventing the application from closing, such as a Document Recovery dialog. If that's the case, you need to add this when creating your application.

app.DisplayAlerts = false;

Upvotes: 2

Charlie
Charlie

Reputation: 69

I think the main issue, which nobody seems to have picked up on, is that you shouldn't be creating a new Application object in the first place if Word is already open. Those of us who have been coding since the days of COM and/or VB6 will remember GetActiveObject. Fortunately .Net only requires a ProgID.

The recommended way of doing this is as follows:

try
{
    wordApp = (word.Application) Marshal.GetActiveObject("Word.Application");
}
catch(COMException ex) when (ex.HResult == -2147221021)
{
    wordApp = new word.Application();
}

Upvotes: 6

Asiri Jayaweera
Asiri Jayaweera

Reputation: 357

Try this..

doc.Close(false);
app.Quit(false);
if (doc != null)
    System.Runtime.InteropServices.Marshal.ReleaseComObject(doc);
if (app != null)
    System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
doc = null;
app = null;
GC.Collect();

Upvotes: 1

T Bass
T Bass

Reputation: 51

The best solution.. last:

try {

    Microsoft.Office.Interop.Word.Application appWord = new Microsoft.Office.Interop.Word.Application();
    appWord.Visible = false;
    Microsoft.Office.Interop.Word.Document doc = null;
    wordDocument = appWord.Documents.Open((INP), ReadOnly: true);

    wordDocument.ExportAsFixedFormat(OUTP, Microsoft.Office.Interop.Word.WdExportFormat.wdExportFormatPDF);

    // doc.Close(false); // Close the Word Document.
    appWord.Quit(false); // Close Word Application.
} catch (Exception ex) {
    Console.WriteLine(ex.Message + "     " + ex.InnerException);
}

Upvotes: 5

a1ashiish
a1ashiish

Reputation: 81

You need to calls app.Quit() to close the application. I used below code & it worked like a charm for me -

try
{
   Microsoft.Office.Interop.Word.Application wordApp = new Microsoft.Office.Interop.Word.Application();
   wordApp.Visible = false;
   Microsoft.Office.Interop.Word.Document doc = null;

   //Your code here...

   doc.Close(false); // Close the Word Document.
   wordApp.Quit(false); // Close Word Application.
}
catch (Exception ex)
{
   MessageBox.Show(ex.Message + "     " + ex.InnerException);
}
finally
{
   // Release all Interop objects.
   if (doc != null)
      System.Runtime.InteropServices.Marshal.ReleaseComObject(doc);
   if (wordApp != null)
      System.Runtime.InteropServices.Marshal.ReleaseComObject(wordApp);
   doc = null;
   wordApp = null;
   GC.Collect();
}

Upvotes: 3

Enigmativity
Enigmativity

Reputation: 117027

Do you not need to call Quit?

app.Quit();

Upvotes: 55

gangelo
gangelo

Reputation: 3172

I close the document, then the application, that works for me, then force garbage collection.

// Document
object saveOptionsObject = saveDocument ? Word.WdSaveOptions.wdSaveChanges : Word.WdSaveOptions.wdDoNotSaveChanges;
this.WordDocument.Close(ref saveOptionsObject, ref Missing.Value, ref Missing.Value);

// Application
object saveOptionsObject = Word.WdSaveOptions.wdDoNotSaveChanges;
this.WordApplication.Quit(ref saveOptionsObject, ref Missing.Value, ref Missing.Value); 

GC.Collect();
GC.WaitForPendingFinalizers();

Upvotes: 1

Nick
Nick

Reputation: 1891

Perhaps try setting doc = null and calling GC.Collect()

Edit, not really my own code I forget where I got it but this is what I use to dispose of Excel, and it does the job maybe you can glean something from this:

public void DisposeExcelInstance()
{
    app.DisplayAlerts = false;
    workBook.Close(null, null, null);
    app.Workbooks.Close();
    app.Quit();
    if (workSheet != null)
        System.Runtime.InteropServices.Marshal.ReleaseComObject(workSheet);
    if (workBook != null)
        System.Runtime.InteropServices.Marshal.ReleaseComObject(workBook);
    if (app != null)
        System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
    workSheet = null;
    workBook = null;
    app = null;
    GC.Collect(); // force final cleanup!
}

Upvotes: 46

Related Questions