How to close a file that was opened using - Microsoft.Office.Interop.Word.Application

I have some code that accesses an MS Word documents within a folder via "Microsoft.Office.Interop.Word.Application".

I open the file using the code below: (...this works)

Microsoft.Office.Interop.Word.Application wordObject = new Microsoft.Office.Interop.Word.Application();

Microsoft.Office.Interop.Word.Document docs = wordObject.Documents.Open(file, nullobject, nullobject, nullobject, nullobject, nullobject, nullobject, nullobject, nullobject, nullobject, nullobject, nullobject, nullobject, nullobject, nullobject, nullobject);


Then, when I'm done I close the file using the following, but it fails to close properly.

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            ((Microsoft.Office.Interop.Word._Application)wordObject).Quit(WdSaveOptions.wdDoNotSaveChanges);
        }


I've tried the code above, and the code below, but both fail and leave the file open in memory causing a memory leak.

docs.Close(WdSaveOptions.wdDoNotSaveChanges,

So, my question is: How does one successfully close a file after it was opened using Microsoft.Office.Interop so it colses completely and does not hang in memory?


Thank you,
Fulano
Mr_FulanoAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

anarki_jimbelSenior DeveloperCommented:
After closing and quitting - try to release objects:

    if wordObject != null)
        System.Runtime.InteropServices.Marshal.ReleaseComObject(wordObject);
    if (docs != null)
        System.Runtime.InteropServices.Marshal.ReleaseComObject(docs);

Open in new window

Jacques Bourgeois (James Burger)PresidentCommented:
Just a little explanation about anarki code.

Note that he does not cast wordObject as you do. Usually, when you reference an Office application and instantiate it through an interop, you do not have to cast it when you use is. Thus, anarki uses the variable directly.

Office applications are COM/ActiveX applications, the kind of programs that we worked with before .NET. COM and .NET both handled the memory differently. When you mix them together, things do not always work as they should.

Depending on many factors, mostly on what you do in the COM application, using standard VBA commands from .NET to get rid of a COM object might or might not be enough. When it does not, you need to go one step further and implicitely tell .NET to release the reference to the COM objects. Otherwise COM thinks that something is still using the objects and waits to remove them from memory. This is what Anarki does.

I see a possible problem with his code, but once again, not always. When you have many objects to release and there is a parent/children relationship, such as the Word Application that contains a Word Document, it is recommended to first release the child, and then the parent. In my experience, this is most important in Excel, less in Word. But I would release the Document before I release the Application.

I see one possible problem with
anarki_jimbelSenior DeveloperCommented:
But I would release the Document before I release the Application.

Of course! My fault :).
Introduction to Web Design

Develop a strong foundation and understanding of web design by learning HTML, CSS, and additional tools to help you develop your own website.

Mr_FulanoAuthor Commented:
OK...I think I understand what each of you are saying, but understanding does not always translate to code...so this is what I tried, which I suspected would fail

try{code}
catch{code}
finally
           {
             if (docs != null)
             System.Runtime.InteropServices.Marshal.ReleaseComObject(docs);
             if (wordObject != null)
             System.Runtime.InteropServices.Marshal.ReleaseComObject(wordObject);
             ((Microsoft.Office.Interop.Word._Application)wordObject).Quit(WdSaveOptions.wdDoNotSaveChanges);
    
           }

Open in new window

What am I doing wrong...? - I suspect that "System.Runtime.InteropServices.Marshal." and "Microsoft.Office.Interop.Word._Application)wordObject)" don't play well together...

Any suggestions...?

Thanks,
Fulano
Mr_FulanoAuthor Commented:
OK...I think I've made some progress (maybe not...). After a bit of Internet research I learned that I needed to close my "docs" object and quit my "wordObject" object in the same thread that I had opened them, which I was not doing. So, after a bit of code juggling, I came up with this, which eliminated having to manually close the MS Word document, but it DID NOT eliminate the memory leak. I still have an instance of WINWORD.EXE *32 in my running processes on my machine (as per Windows Task Manager) for each time I run my application, which accesses one Word document each time.

This is a BIG problem, because eventually this application will iterate over a folder with hundreds of MS Word documents and access them all one-by-one. So, I would have hundreds of instances of WINWORD.EXE *32 running at that point, which would crash the machine's memory.

Besides the memory leak, I also get the following warning as shown below AND I'm also getting a green squiggly line under the word "Close" in the docs.Close(...etc.

Warning      1   Ambiguity between method 'Microsoft.Office.Interop.Word._Document.Close(ref object, ref object, ref object)' and non-method 'Microsoft.Office.Interop.Word.DocumentEvents2_Event.Close'.

if (docs != null)
                docs.Close(WdSaveOptions.wdDoNotSaveChanges);
                System.Runtime.InteropServices.Marshal.ReleaseComObject(docs);
            if (wordObject != null)
                System.Runtime.InteropServices.Marshal.ReleaseComObject(wordObject);
                System.Runtime.InteropServices.Marshal.FinalReleaseComObject(wordObject);

Open in new window

The question now become twofold:

1). How do I solve the "Ambiguity" that the warning is referencing?
2). How do I get rid of the memory leak? (i.e. the instances of WINWORD.EXE *32 in Task Manager?

Thanks,
Fulano
Jacques Bourgeois (James Burger)PresidentCommented:
For the ambiguity, I cannot say. It says that the compiler does not know if it should call the Close method or the Close event on your docs object. Normally, the event should not be visible from were you are, so there should not be any ambiguity. Since you get the thing as a warning instead of an error, you might disregard it. To check, be sure that the application is visible. Run the code in the debugger up to the Close command, execute it, and visually check to see if the document closes in the application. If it does, then you can disregard the warning, the correct Close command was called.

I do not see your command to Quit the application. This should be done before you call ReleaseComObject.

I will be in the training all day, so I won't be able to be back here for a few hours. Hope anarki will be able to help you during that time.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Mr_FulanoAuthor Commented:
Hi James...very good analysis. I added the QUIT command as you suggested and it worked...memory leak gone. I also added a message box to watch the WINWORD.EXE*32 instance drop off and it does just before the message box pops up.

Thank you!!!
Fulano
Mr_FulanoAuthor Commented:
Excellent, both contributor worked together to produce a final solution that worked perfectly. Great work gentlemen!
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.