Утилизация Microsoft.Office.Interop.Word.Application

(Отчасти продолжение этого поста (который остается без ответа): https://stackru.com/q/6197829/314661)

Используя следующий код

Application app = new Application();
_Document doc = app.Documents.Open("myDocPath.docx", false, false, false);
doc.PrintOut(false);
doc.Close();

Я пытаюсь открыть и распечатать файл программно.

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

Класс приложения, похоже, не содержит метода dispose/close или аналогичного метода.

После небольшого исследования я (понял) и изменил код на следующий.

 Application app = new Application();
 _Document doc = app.Documents.Open(fullFilePath + ".doc", false, false, false);
 doc.PrintOut(false);
 doc.Close();
 int res = System.Runtime.InteropServices.Marshal.ReleaseComObject(doc);
 int res1 = System.Runtime.InteropServices.Marshal.ReleaseComObject(app);

И я вижу, что счетчик оставшихся ссылок равен нулю, но процессы остаются?

PS: я использую версию 14 библиотеки Microsoft.Office.Interop.

7 ответов

Решение

Возможно, попробуйте настройку doc = null и звонит GC.Collect()

Редактировать, не совсем мой собственный код, я забыл, где я его взял, но это то, что я использую, чтобы избавиться от Excel, и он выполняет свою работу, может быть, вы можете что-то почерпнуть из этого:

public void DisposeExcelInstance()
{
    app.DisplayAlerts = false;
    workBook.Close(null, null, null);
    app.Workbooks.Close();
    app.Quit();
    if (workSheet != null)
        System.Runtime.InteropServices.Marshal.ReleaseComObject(workSheet);
    if (workBook != null)
        System.Runtime.InteropServices.Marshal.ReleaseComObject(workBook);
    if (app != null)
        System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
    workSheet = null;
    workBook = null;
    app = null;
    GC.Collect(); // force final cleanup!
}

Вам не нужно звонить Quit?

app.Quit();

Я думаю, что главная проблема, которую, похоже, никто не заметил, заключается в том, что вам не следует создавать новый объект Application, если Word уже открыт. Те из нас, кто занимался кодированием со времен COM и / или VB6, будут помнить GetActiveObject. К счастью.Net требует только ProgID.

Рекомендуемый способ сделать это следующим образом:

try
{
    wordApp = (word.Application) Marshal.GetActiveObject("Word.Application");
}
catch(COMException ex) when (ex.HResult == -2147221021)
{
    wordApp = new word.Application();
}

Лучшее решение.. последнее:

try {

    Microsoft.Office.Interop.Word.Application appWord = new Microsoft.Office.Interop.Word.Application();
    appWord.Visible = false;
    Microsoft.Office.Interop.Word.Document doc = null;
    wordDocument = appWord.Documents.Open((INP), ReadOnly: true);

    wordDocument.ExportAsFixedFormat(OUTP, Microsoft.Office.Interop.Word.WdExportFormat.wdExportFormatPDF);

    // doc.Close(false); // Close the Word Document.
    appWord.Quit(false); // Close Word Application.
} catch (Exception ex) {
    Console.WriteLine(ex.Message + "     " + ex.InnerException);
}

Вам нужно звонить app.Quit() закрыть приложение. Я использовал приведенный ниже код, и он работал для меня как шарм -

try
{
   Microsoft.Office.Interop.Word.Application wordApp = new Microsoft.Office.Interop.Word.Application();
   wordApp.Visible = false;
   Microsoft.Office.Interop.Word.Document doc = null;

   //Your code here...

   doc.Close(false); // Close the Word Document.
   wordApp.Quit(false); // Close Word Application.
}
catch (Exception ex)
{
   MessageBox.Show(ex.Message + "     " + ex.InnerException);
}
finally
{
   // Release all Interop objects.
   if (doc != null)
      System.Runtime.InteropServices.Marshal.ReleaseComObject(doc);
   if (wordApp != null)
      System.Runtime.InteropServices.Marshal.ReleaseComObject(wordApp);
   doc = null;
   wordApp = null;
   GC.Collect();
}

Согласен с другими плакатами, GC.Collect() а также Marshal.ReleaseComObject()не нужен. Если процесс все еще существует после запускаapp.Quit(false), это может быть связано с тем, что вы запускаете приложение в невидимом состоянии, и есть приглашение, не позволяющее закрыть приложение, например диалоговое окно восстановления документа. В этом случае вам нужно добавить это при создании вашего приложения.

app.DisplayAlerts = false;

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

// Document
object saveOptionsObject = saveDocument ? Word.WdSaveOptions.wdSaveChanges : Word.WdSaveOptions.wdDoNotSaveChanges;
this.WordDocument.Close(ref saveOptionsObject, ref Missing.Value, ref Missing.Value);

// Application
object saveOptionsObject = Word.WdSaveOptions.wdDoNotSaveChanges;
this.WordApplication.Quit(ref saveOptionsObject, ref Missing.Value, ref Missing.Value); 

GC.Collect();
GC.WaitForPendingFinalizers();

Попробуй это..

doc.Close(false);
app.Quit(false);
if (doc != null)
    System.Runtime.InteropServices.Marshal.ReleaseComObject(doc);
if (app != null)
    System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
doc = null;
app = null;
GC.Collect();
Другие вопросы по тегам