释放 Microsoft.Office.Interop.Word.Application

Disposing of Microsoft.Office.Interop.Word.Application

提问人:Maxim Gershkovich 提问时间:7/21/2011 最后编辑:CommunityMaxim Gershkovich 更新时间:11/8/2019 访问量:78681

问:

(该帖子的后续内容(仍未回复):https://stackoverflow.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:我正在使用 Microsoft.Office.Interop 库的版本 14。

C# 互操作 自动化 Office-Interop

评论


答:

46赞 Nick 7/21/2011 #1

也许可以尝试设置和调用doc = nullGC.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!
}

评论

14赞 Maxim Gershkovich 7/21/2011
绝对的立法。App.Quit() 是关键...谢谢!
1赞 Nick 7/21/2011
@gangelo,我意识到这一点,但它仍然是 Office Interop,所以我发布了它,希望它能引导他找到答案,它做到了。
0赞 Lukas Huzen 2/22/2012
以使用 GC。收集不是那么好主意,它会用 GC 进行彻底清理。气相色谱。Collect(3) 对 GC 会更好。收集功能。但我同意@Maxim应用程序。Quit() 更好
4赞 Yandros 6/15/2012
气相色谱。Collect() 就像参宿四一样:你必须调用它三次才能让它以任何可观察的方式做出响应。
3赞 11/28/2015
如果您关闭文档并退出应用程序,则无需GC.Collect()Marshal.ReleaseComObject()
1赞 gangelo 7/21/2011 #2

我关闭文档,然后关闭对我有用的应用程序,然后强制垃圾回收。

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

评论

1赞 11/28/2015
如果您关闭文档并退出应用程序,则无需GC.Collect()Marshal.ReleaseComObject()
54赞 Enigmativity 7/21/2011 #3

你不需要打电话吗?Quit

app.Quit();

评论

0赞 Matias Masso 8/29/2019
我收到错误BC30456:“退出”不是“应用程序”的成员
0赞 Enigmativity 8/29/2019
@MatiasMasso - 代码正确。您没有 .Application
3赞 a1ashiish 12/12/2013 #4

您需要调用才能关闭应用程序。我使用了下面的代码,它对我来说就像一个魅力 -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();
}

评论

3赞 Unnie 1/20/2015
奇怪的是它是如何为您工作的,因为您的代码应该给出构建错误,因为 doc 和 wordApp 是在 try 中创建的,并且最终将不可用。
0赞 11/28/2015
如果您关闭文档并退出应用程序,则无需GC.Collect()Marshal.ReleaseComObject()
5赞 T Bass 8/25/2015 #5

最好的解决方案..最后:

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);
}
1赞 Asiri Jayaweera 3/14/2018 #6

试试这个..

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();
6赞 Charlie 8/16/2018 #7

我认为似乎没有人注意到的主要问题是,如果 Word 已经打开,您首先不应该创建新的 Application 对象。 我们这些从 COM 和/或 VB6 时代就开始编码的人会记得 GetActiveObject。幸运的是,.Net 只需要 ProgID。

建议的执行方法如下:

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

评论

1赞 Anton K 1/5/2020
仍然有知识的守护者。
0赞 Ricardo Saracino 3/24/2020
那么我会在什么情况下做一个新词。应用
2赞 Jordan Ryder 11/8/2019 #8

同意其他海报,并且不需要。如果该进程在运行后仍然存在,则可能是因为您正在不可见地运行应用程序,并且存在阻止应用程序关闭的提示,例如“文档恢复”对话框。如果是这种情况,则需要在创建应用程序时添加此内容。GC.Collect()Marshal.ReleaseComObject()app.Quit(false)

app.DisplayAlerts = false;