it-swarm.com.ru

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

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

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

20
Keith

Я понял, что виновато использование 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
Keith

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

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

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

Хорошо

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

ПЛОХО

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

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

oWord.Visible = False

в

oWord.Visible = True

?

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

4
Jim L

Я получил ту же проблему, когда я делал это:

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

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

3
heringer

Попробуйте вызвать 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
Ahmad Mageed

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

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

2
Ehz

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

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

Word.NormalTemplate.Saved = true;

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

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

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

Удачного дня, и будь здоров.

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

1
Celebrating Octopus Emoji

Вы не должны отбрасывать объект документа, созданный в Word.Documents.Add . Сохраните и вызовите Marshal.ReleaseComObject для каждого COM-объекта, который вы получаете из автоматизации, когда вы закончите, то есть если вы нигде не кэшируете объекты .

0
Sheng Jiang 蒋晟

Хотя это C #, но, возможно, это поможет вам. Я использую этот метод для объединения нескольких документов в один. Я передаю все документы в 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
0
MadBoy

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

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

0
user5535483

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

объект objFalse = false;

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

0
Abdul Kader Jilani

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

0
gehsekky
oWord.Visible = True

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

_wordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;

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

0
John Clegg