WinWord.exe не будет закрываться после вызова Word.Documents.Add - Word .NET Interop - PullRequest
20 голосов
/ 25 марта 2010

Я сталкиваюсь с классическим сценарием, в котором при создании объектов Word COM в .NET (с помощью сборки Microsoft.Office.Interop.Word) процесс WinWord не завершается, даже если я правильно закрытие и отпускание объектов .

Я сузил его до использования метода Word.Documents.Add (). Я могу работать с Word другими способами без проблем (открытие документов, изменение содержимого и т. Д.), И WinWord.exe завершает работу, когда я говорю об этом. Когда я использую метод Add () (и только при добавлении шаблона ), процесс остается запущенным.

Вот простой пример, который воспроизводит проблему:

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

Как видите, я правильно создаю и удаляю объекты, даже делая дополнительный шаг, чтобы зациклить Marsha.ReleaseComObject, пока он не вернет правильный код. Работа с объектами Word хороша в других отношениях, это просто противные Документы. Добавлю, что вызывает у меня горе. Есть ли еще один объект, который создается в этом процессе, на который мне нужно ссылаться и распоряжаться? Есть ли еще один шаг по утилизации, которому я должен следовать? Что-то другое? Ваша помощь очень ценится:)

Update: Я попробовал GC.Collect в конце этапа утилизации, но все равно не повезло.

Update 2: Я сузил проблему до использования пользовательских шаблонов. Когда я вызываю Documents.Add (...), я указываю пользовательский шаблон для нового документа. Если я не сделаю этого и вместо этого вызову Add () без параметров, проблема не произойдет.

Ответы [ 13 ]

11 голосов
/ 07 июля 2010

(все мои советы взяты из этого ответа о взаимодействии Excel.)

Здесь есть несколько важных вещей:

1) Никогда не используйте 2 точки на одной линии. Также рассмотрим индексатор как точку

Good

Word.Documents d = wordApp.Documents;
Word.Document aDoc = d.Open(/*...*/);

BAD

Word.Document aDoc = wordApp.Documents.Open(/*...*/);

2) Отпустите все ваши указатели.

3) Нет, вернитесь и отпустите все ваши указатели, вы где-то пропустили один (или, по крайней мере, я всегда так делаю).

Вот полный пример того, как НАКОНЕЦ работал для меня над одним проектом после долгих воплей и скрежета зубов:

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);
4 голосов
/ 25 марта 2010

Вы пытались изменить

oWord.Visible = False

до

oWord.Visible = True

Я спрашиваю, потому что Word может попросить вас сделать что-то, что связано с этим шаблоном, который вы пытаетесь использовать. Если он думает, что есть диалог, он обычно не закрывается. IIRC, есть способ сделать Quit так, чтобы он заставлял Quit и не ждал ни одного диалога. Но это было какое-то время.

3 голосов
/ 05 апреля 2010

У меня возникла такая же проблема, когда я делал это:

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

Я решил так:

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

Не спрашивайте меня, почему автоматизация офиса - это приключение:)

2 голосов
/ 26 марта 2010

Я понял, что виновато использование Documents.Add () при использовании пользовательского шаблона . Я не могу объяснить, почему это привело бы к зависанию WinWord.exe. Однако существуют другие способы создания документов из шаблонов, которые не приводят к той же проблеме.

Итак, я заменил:

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

с:

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

Использование AttachedTemplate для указания шаблона работает для меня и не оставляет WinWord.exe зависшим.

(Однако возникла одна новая проблема ... Изображение в нижнем колонтитуле шаблона не копируется в документ при использовании AttachedTemplate / UpdateStyles. Я рассматриваю это как отдельную проблему. Но так как этот метод решает мой оригинальный проблема, я доволен. Спасибо всем, кто предложил ответы!)

2 голосов
/ 25 марта 2010

Попробуйте позвонить GC.WaitForPendingFinalizers() и использовать Marshal.FinalReleaseComObject вместо Marshal.ReleaseComObject. Это избавляет от необходимости зацикливать его.

Обновите ваш код до этого и попробуйте его (GC-вызовы начинаются специально):

GC.Collect()
GC.WaitForPendingFinalizers()

oDoc.Close()
Marshal.FinalReleaseComObject(oDoc)

Marshal.FinalReleaseComObject(oDocuments)

oWord.Quit()
Marshal.FinalReleaseComObject(oWord)

Возможно, вы также захотите проверить этот связанный вопрос , обсуждая проблему для Excel.

2 голосов
/ 25 марта 2010

Я только автоматизировал Excel, но столкнулся с похожими проблемами. Ссылаясь на некоторый старый код, последний шаг закрытия имеет строку GC.Collect ()

Эта статья также упоминает об этом: http://support.microsoft.com/kb/317109

1 голос
/ 10 августа 2015

Я наткнулся на ваш пост из-за аналогичной проблемы с шаблоном. Я получал сообщение с предложением сохранить файл .dotm всякий раз, когда я пытался закрыть слово в моей программе. Я не смог использовать ваш принятый ответ, потому что у меня нет точного пути к шаблону, я просто открываю любой документ, который получает программа.

я использовал

Word.NormalTemplate.Saved = true;

когда я использовал этот код перед удалением приложения, оно больше не вызывало диалоговое окно с сообщением о том, что я не сохранил шаблон, и запускало удаление, не оставляя ненужного " winWord.exe"процесс запущен.

Я получил подсказку "NormalTemplate.Saved" от пользователя " NeedSomeAnswers " на форумах Visual Basic здесь . По его словам, «[он] на самом деле не сохраняет в Normal, он просто говорит Word, что Normal уже был сохранен, поэтому ему не нужно его сохранять».

Я думаю, это второй ответ на ту же проблему. Я надеюсь, что это помогает.

Хорошего дня и будь здоров.

- в любой день, когда ваш код работает, это хороший день для празднования-

0 голосов
/ 07 ноября 2015

Я пытался автоматизировать создание документа в слове с vb.net, но winword.exe все еще работал, даже после того, как я закрыл документ. Я наткнулся на решение этой проблемы; Я переместил тусклый объект слова внутрь подпрограммы, которую использовал для редактирования документа, в отличие от определения его размеров независимо от подпрограммы (мой первоначальный метод).

Надеюсь, это поможет.

0 голосов
/ 03 октября 2014

это идеальное решение, у меня была та же проблема, я просто следовал этой, и она отлично работает.

объект objFalse = false;

wordApplication.Quit (ref objFalse, ref objFalse, ref objFalse);

0 голосов
/ 21 марта 2013
oWord.Visible = True

Решил проблему для меня. Основной проблемой было восстановление документов. Диалог появлялся несмотря на наличие строки:

_wordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;

Я использовал все показанные здесь уловки, но до тех пор, пока список восстановления документов не был очищен, каждый раз при запуске приложения оставался текстовый процесс «зомби».

...