Подтвердить что ты не робот

WinWord.exe не выйдет после вызова Word.Documents.Add - Word.NET Interop

Я столкнулся с классическим сценарием, когда при создании объектов 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 хороша в других отношениях, это просто надоедливые Documents.Add, что вызывает у меня печаль. Есть ли другой объект, который создается в этом процессе, который мне нужно ссылаться и распоряжаться? Есть ли другой шаг по избавлению, которому я должен следовать? Что-то другое? Ваша помощь очень ценится:)

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

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

4b9b3361

Ответ 1

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

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

Dim doc As Word.Document = documents.Add(Шаблон: = CObj (templatePath))

с:

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

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

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

Ответ 2

(Весь мой совет адаптирован из этого о взаимодействии Excel.)

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

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

Хорошо

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

BAD

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

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

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

Вот полный пример того, что FINALLY работал у меня в одном проекте после многого плача и скрежещения зубов:

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

Ответ 3

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

oWord.Visible = False

к

oWord.Visible = True

?

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

Ответ 4

Я только сделал автоматизацию Excel, но столкнулся с подобными проблемами. Обращаясь к некоторому старому коду, заключительный этап закрытия имеет строку GC.Collect()

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

Ответ 5

Попробуйте позвонить 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.

Ответ 6

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

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

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

Ответ 7

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

то, что я использовал,

Word.NormalTemplate.Saved = true;

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

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

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

У меня потрясающий день, и все будет хорошо.

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

Ответ 8

Есть ли у "oDocuments" метод .Dispose() или .Close()? вы избавляетесь от других 2, но не от этого.

Ответ 9

Хотя это С#, но, возможно, это поможет вам. Я использую этот метод для объединения нескольких документов в один. Я передаю все документы в Arraylist, и Word, кажется, правильно закрывается, когда это делается.

 public static void documentsMerge(object fileName, ArrayList arrayList) {
        // object fileName = Path.Combine(Environment.CurrentDirectory, @"NewDocument.doc");
        File.Delete(fileName.ToString());
        try {
            wordApplication = new ApplicationClass();
            var doc = wordApplication.Documents.Add(ref missing, ref missing, ref missing, ref missing);
            try {
                doc.Activate();
                int count = 0;
                foreach (var alItem in arrayList) {
                    addDocument(alItem, doc, count == 0);
                    count++;
                }
               // addDocument(@"D:\Projects\WordTests\ConsoleApplication1\Documents\Doc1.doc", doc ) ; //, false);
               // addDocument(@"D:\Projects\WordTests\ConsoleApplication1\Documents\Doc2.doc", doc ) ; //, true);
                doc.SaveAs(ref fileName, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
            } finally {
                doc.Close(ref missing, ref missing, ref missing);
            }
        } finally {
            wordApplication.Quit(ref missing, ref missing, ref missing);
        }
    }

Блок finally полезен для cleaning up любых ресурсов, выделенных в блоке try, а также для запуска любого кода, который должен выполняться, даже если есть исключение. Контроль всегда передается блоку finally независимо от того, как выйдет блок try.

Итак, попробуйте поместить ваш код в блок try/finally и посмотреть, как он себя ведет тогда?

Для VB.NET

Try
' Statement which can cause an exception.
Catch x As Type
' Statements for handling the exception
Finally
End Try 'Any cleanup code

Ответ 11

oWord.Visible = True

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

_wordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;

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

Ответ 12

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

объект objFalse = false;

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

Ответ 13

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

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