как закрыть работающий экземпляр документа Word? (С#)

Я мог видеть много очень похожих тем вокруг, но ничто, похоже, не дало мне решения, которое должно быть очень простым.

Из моего приложения winforms мне нужно закрыть работающий экземпляр документа Word (открытого из самого приложения). Когда я открываю документ Word из приложения, я отслеживаю его в списке. Теперь, как я могу закрыть тот же документ?

Вот что я пробовал:

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;
    }
}

Я получаю много методов для объекта документа, но только .Close() для закрытия, который имеет такие аргументы: ref object SaveChanges, ref object OriginalFormat, ref object RouteDocument, которые я не понимаю.

Каков идеальный способ? Спасибо..

Редактировать:

  1. Я не могу закрыть все приложение Word (WinWord), так как у пользователей могут быть открыты другие файлы Word.

  2. Мне нужно просто завершить экземпляр слова (что-то вроде Process.Kill()) без каких-либо запросов пользователю сохранить или нет и т. д.


person nawfal    schedule 16.09.2011    source источник


Ответы (4)


Это решение взято из здесь.

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;
person nawfal    schedule 16.09.2011
comment
@nawfal: у меня та же проблема, когда я запускаю программу и открывается другой документ с таким же именем (на самом деле он был закрыт без удаления (в какой-то ситуации)), этот код не работает, я имею в виду, что я получаю сообщение об ошибке, что запущен другой экземпляр. И, как вы сказали, я не могу закрыть весь WinWord.exe, потому что у пользователей могут быть открыты другие файлы слов. Это сводит меня с ума, я надеюсь, что вы можете мне помочь. - person mahboub_mo; 25.08.2012
comment
@nawfa: ошибка, о которой я сказал: Word не может сохранить этот файл, потому что он уже открыт в другом месте. - person mahboub_mo; 25.08.2012
comment
@raha, сделай еще один вопрос и пролей на него больше света. отсюда трудно дать решение. Все, что я могу сказать, это то, что вы должны использовать некоторые умные коды для удаления существующих экземпляров слова. Пожалуйста, найдите утилизацию экземпляра слова или около того. На SO много тем - person nawfal; 25.08.2012
comment
@ nawfal :спасибо, но я уже задал другой вопрос и искал в Интернете целый день, но не смог найти никакого решения, все равно спасибо. - person mahboub_mo; 25.08.2012

Как насчет использования чего-то вроде:

Изменено с: 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;
}
person Chuck Savage    schedule 16.09.2011
comment
Чак, этот метод ищет процессы по их именам. Например, мой файл Word может иметь имя (аргумент, который я передаю) C:\doc.doc, в то время как имя процесса WINWORD не совпадает. Следовательно, .Kill() никогда не срабатывает. - person nawfal; 16.09.2011

Я знаю, что уже слишком поздно, но я нашел эту тему, потому что у меня была такая же проблема.

И мое решение может помочь другим людям.

Приведенное выше решение не сработало, потому что оно убило все запущенные экземпляры Word, хотя оно было открыто не программой С#, а пользователем.

Так что это было не так удобно.

Мой код проверяет процессы до/после создания объекта Word.Application в С# и записывает идентификаторы WINWORD процессов в List<int>, а затем сравнивает значения в обоих List<int>. Когда processID не найден ни в одном из List<int>, процесс с этим идентификатором уничтожается.

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;
}

Запустите это дважды (один раз перед созданием Word.Application и один раз после).

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

Затем запустите 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();
        }
    }
 }
person jAC    schedule 14.11.2012
comment
Такой подход точно не следует использовать, так как в нем нет никакой безопасности. Между вызовами может быть запущено любое количество процессов... - person GEEF; 31.01.2015
comment
Нет, если вы вызываете второй метод сразу после создания объекта приложения Word и запуска процесса. Ну да, есть временной разрыв, может быть, в секунду, но за это время почти ни один пользователь не откроет другой экземпляр Word. - person jAC; 31.01.2015
comment
Я все еще думаю, что это ненадежное решение. Он отлично работает для небольших проектов, которые вы делаете дома, но не должен использоваться ни в каких промышленных условиях, и ваше второе предложение ясно объясняет, почему. - person GEEF; 03.02.2015

Если вы хотите закрыть приложение всего слова, вы можете просто позвонить:

Word.Application app = (Word.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Word.Application");
if (app == null)
    return true;
app.Quit(false);
person Jiří Herník    schedule 11.11.2016