how to close a running instance of Word document? (C#)
Asked Answered
G

4

8

I could see a lot of very similar threads all around, but nothing seem to give me a solution which ought to be very basic.

From my winforms application, I need to close a running instance of a word document (opened from the application itself). When I open the word document from the application, I keep a track of it in a list. Now how can I close the same doc?

Here is what I tried:

private bool CloseWord(string osPath) //here I pass the fully qualified path of the file
{
    try
    {
        Word.Application app = (Word.Application)Marshal.GetActiveObject("Word.Application");
        if (app == null)
            return true;

        foreach (Word.Document d in app.Documents)
        {
            if (d.FullName.ToLower() == osPath.ToLower())
            {
               d.What? //How to close here?
               return true;
            }
        }
        return true;
    }
    catch
    {
        return true;
    }
}

I get a lot of methods for the document object, but only a .Close() to close which has arguments like this: ref object SaveChanges, ref object OriginalFormat, ref object RouteDocument which I dont understand.

What is the ideal way? Thanks..

Edit:

  1. I can not close the entire Word application (WinWord) as users might have other word files opened.

  2. I need to just terminate the word instance (something like Process.Kill()) without any prompt for user to save or not etc.

Gesticulate answered 16/9, 2011 at 13:58 Comment(0)
G
18

This solution got from here solves.

Word.Application app = (Word.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Word.Application");
if (app == null)
    return true;

foreach (Word.Document d in app.Documents)
{
    if (d.FullName.ToLower() == osPath.ToLower())
    {
        object saveOption = Word.WdSaveOptions.wdDoNotSaveChanges;
        object originalFormat = Word.WdOriginalFormat.wdOriginalDocumentFormat;
        object routeDocument = false;
        d.Close(ref saveOption, ref originalFormat, ref routeDocument);
        return true;
    }
}
return true;
Gesticulate answered 16/9, 2011 at 15:1 Comment(4)
@nawfal: i have the same problem,when i run the program and another document with the same name is open,(in the fact it have been closed without disposing(in some situation)),this code dose not work,i mean i get the error that another instance is running.and as you said,i can't close the entire WinWord.exe,cause users might have other word files opened.it makes me crazy,i hope you can give me some help.Chet
@nawfa : the error that i said is:Word cannot save this file because it is already open elsewhere.Chet
@raha, make it another question, and shed more light there. its hard to give a solution from here. All I can say is, you should use some smart codes to dispose the existing instances of word. Please search "disposing off word instance" or so. Plenty of threads are there on SOGesticulate
@ nawfal :thanks,but i've made another question already, and searched on the internet for a whole day,but couldn't find any solution,thank you anyway.Chet
B
2

How about using something like:

Modified From: http://www.dreamincode.net/code/snippet1541.htm

public static bool KillProcess(string name)
{
    //here we're going to get a list of all running processes on
    //the computer
    foreach (Process clsProcess in Process.GetProcesses())
    {
        if (Process.GetCurrentProcess().Id == clsProcess.Id)
            continue;
        //now we're going to see if any of the running processes
        //match the currently running processes. Be sure to not
        //add the .exe to the name you provide, i.e: NOTEPAD,
        //not NOTEPAD.EXE or false is always returned even if
        //notepad is running.
        //Remember, if you have the process running more than once, 
        //say IE open 4 times the loop thr way it is now will close all 4,
        //if you want it to just close the first one it finds
        //then add a return; after the Kill
        if (clsProcess.ProcessName.Contains(name))
        {
            clsProcess.Kill();
            return true;
        }
    }
    //otherwise we return a false
    return false;
}
Bechuana answered 16/9, 2011 at 14:22 Comment(1)
Chuck, this method searches for processes by their names. For instance, my word file can have the name (the argument I pass) "C:\doc.doc" while the process's name is WINWORD which doesnt match. Hence .Kill() is never hit.Gesticulate
H
1

I know it is too late, but I found this topic because I had the same problem.

And my solution may help other people.

The solution above didnt work well because it killed every running instance of Word, though it wasn't opened by the c# program but the user.

So this was not that userfriendly.

My code checks the processes before/after the creation of the Word.Application Object in c# and writes the IDs of the WINWORD Processes in List<int> then it compares the values in both List<int>. When a processID is not found in both List<int> it kills the process with this ID.

public List<int> getRunningProcesses()
{
    List<int> ProcessIDs = new List<int>();
    //here we're going to get a list of all running processes on
    //the computer
    foreach (Process clsProcess in Process.GetProcesses())
    {
        if (Process.GetCurrentProcess().Id == clsProcess.Id)
            continue;             
        if (clsProcess.ProcessName.Contains("WINWORD"))
        {
            ProcessIDs.Add(clsProcess.Id);
        }
    }
    return ProcessIDs;
}

Run this twice (one time before the creation of the Word.Application and once after).

 List<int> processesbeforegen = getRunningProcesses();
 // APP CREATION/ DOCUMENT CREATION HERE...
 List<int> processesaftergen = getRunningProcesses();

Then run killProcesses(processesbeforegen, processesaftergen);

 private void killProcesses(List<int> processesbeforegen, List<int> processesaftergen)
 {
    foreach (int pidafter in processesaftergen)
    {
        bool processfound = false;
        foreach (int pidbefore in processesbeforegen)
        {
            if (pidafter == pidbefore)
            {
                processfound = true;
            }
        }

        if (processfound == false)
        {
            Process clsProcess = Process.GetProcessById(pidafter);
            clsProcess.Kill();
        }
    }
 }
Hobo answered 14/11, 2012 at 8:53 Comment(3)
This approach should definitely not be used, as there is no safety in it. Any number of processes could be started between the calls...Bilharziasis
Not if you call the second method right after creating the Word Application object and starting the process. Well yes, there's a time gap of maybe a second, but in that time nearly no user will open another Word instance.Hobo
I still think this is an unreliable solution. It works fine for small projects you do at home, but should not be used in any kind of industrial setting, and your second sentence clearly states why.Bilharziasis
A
1

If you want to close whole word application, you can just call:

Word.Application app = (Word.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Word.Application");
if (app == null)
    return true;
app.Quit(false);
Autoharp answered 11/11, 2016 at 8:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.