【问题标题】:How to properly close/terminate WINWORD.EXE/Word interop?如何正确关闭/终止 WINWORD.EXE/Word 互操作?
【发布时间】:2019-11-09 18:26:08
【问题描述】:

我有一个使用 Word 文件模板生成报告的应用程序。应用程序将使用用户数据库记录提供的详细信息填充模板。我正在使用远程桌面将我的应用程序运行到另一台服务器。

我的问题是WINWORD.EXE进程无法终止,报告生成完成后仍留在任务管理器中(将报告保存到数据库并删除生成的文件)。

登录服务帐户后,WINWORD.EXE 进程正常终止,并从任务管理器列表中删除。注销时,WINWORD.EXE 仍保留在列表中。当多个 Word 进程未终止时,这可能会导致 Out-of-Memory-Exception。

Word 报告是使用 Microsoft.Office.Interop.Word 生成的,版本=12.0.0.0。

以下是保存新文件、关闭 Word 应用程序、保存报表和删除生成文件的代码:

Marshal.releaseComObject(rng)

Dim strFileName As String = comm.GenerateFileName(strUser_id, strVPN) & ".docx"

' Save the document.
Dim filename As Object = Path.GetFullPath(strNewFilePath & strFileName)
newDoc.SaveAs(FileName:=filename)

' Close.
Dim save_changes As Object = False
newDoc.Close(save_changes)
WordApp.Quit(save_changes)

Marshal.ReleaseComObject(newDoc)
Marshal.ReleaseComObject(WordApp)

rng= Nothing
newDoc = Nothing
WordApp = Nothing

' Let GC know about it
GC.Collect()

' Save the file to database
SaveFormat(Filename, strUser_Id, strFamilyId, strVPN, DateTime.Now.ToString(), "application/vnd.ms-word", br_id, "doc")

If File.Exists(filename) then
      File.Delete(filename)
End If

我仍在研究这里的不同工作。

在 Excel 中,我们通过使用 HWND 属性和 GetProcessById 类获取打开的 Excel 实例的进程 ID 来获得解决方案。

我在某处读到 Word 2013 及更高版本具有 Application.HWND 属性。 这是真的吗? Word 是否有 HWND 属性?

【问题讨论】:

标签: .net vb.net ms-word interop office-interop


【解决方案1】:

使用垃圾收集器 (GC) 的清理代码如下所示:

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

通常,当正确清除所有引用时,Word 会清除(有一些延迟),但如果您想强制清除(仍然在确保清除所有引用之后)将使用上面的代码。

它看起来有点奇怪,但如果你想知道来龙去脉,请从我的脑海中找到第二章中 Andrew Whitechapel(前任办公室 PM)https://www.amazon.com/Microsoft%C2%AE-Development-Microsoft-Developer-Reference/dp/0735621322 的书。

【讨论】:

    【解决方案2】:

    这段代码是我一直使用的基于codeSiddharth Rout's 位,应该给你你想要的:

    Private Sub ReleaseObject(ByVal obj As Object)
        Try
            Dim intRel As Integer = 0
            Do
                intRel = System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
            Loop While intRel > 0
            obj = Nothing
        Catch ex As Exception
            obj = Nothing
        Finally
            GC.Collect()
        End Try
    End Sub
    

    将上述方法添加到您的应用程序中。然后,您可以在想要关闭 Word 时调用它。

    同样值得注意的是,正确排序也很重要。这似乎总是 Interop 的问题。

    我会做的是,替换这段代码:

    newDoc.Close(save_changes)
    WordApp.Quit(save_changes)
    
    Marshal.ReleaseComObject(newDoc)
    Marshal.ReleaseComObject(WordApp)
    
    rng= Nothing
    newDoc = Nothing
    WordApp = Nothing
    

    与:

    newDoc.Close(False)
    ReleaseObject(newDoc)
    WordApp.Quit(False)
    ReleaseObject(WordApp)
    

    我还可以看到您正在尝试处置您的 rng 变量。我会更改:Marshal.releaseComObject(rng) 并使用新方法 ReleaseObject(rng)

    总体而言,您的代码如下所示:

    Dim strFileName As String = comm.GenerateFileName(strUser_id, strVPN) & ".docx"
    
    ' Save the document.
    Dim filename As Object = Path.GetFullPath(strNewFilePath & strFileName)
    newDoc.SaveAs(FileName:=filename)
    
    ReleaseObject(rng)
    newDoc.Close(False)
    ReleaseObject(newDoc)
    WordApp.Quit(False)
    ReleaseObject(WordApp)
    
    ' Save the file to database
    SaveFormat(Filename, strUser_Id, strFamilyId, strVPN, DateTime.Now.ToString(), "application/vnd.ms-word", br_id, "doc")
    
    If File.Exists(filename) then
          File.Delete(filename)
    End If
    

    您提到您使用GetProcessById 方法然后终止您的Excel 进程。这真的不需要,使用上述方法ReleaseObject 应该没问题。正如我所说,很多时候是顺序导致了问题。

    看看我的answer

    Dim app As New Excel.Application()
    app.Visible = False
    app.DisplayAlerts = False
    
    Dim wbs As Excel.Workbooks = app.Workbooks
    Dim wb As Excel.Workbook = wbs.Add()
    Dim ws As Excel.Worksheet = CType(wb.Sheets(1), Excel.Worksheet)
    
    ReleaseObject(ws)
    wb.Close()
    ReleaseObject(wb)
    ReleaseObject(wbs)
    app.Quit()
    ReleaseObject(app)
    

    【讨论】:

      【解决方案3】:

      当我必须编写 Word 文档时,我总是打开文档,在 Try[...]Catch 中使用它,然后再关闭它:

      Private Sub doSomethingWithWord()
          Dim oWord As Word.Application
      
          'Create document
          Dim oDoc As Word.Document
          oWord = CreateObject("word.Application")
          oDoc = oWord.Documents.Add
      
          Try
              'Do something
              Dim oPara1 As Word.Paragraph
              oPara1 = oDoc.Content.Paragraphs.Add
              oPara1.Range.Text = "Hello world"
              oPara1.Range.Font.Bold = True
              oPara1.Format.SpaceAfter = 24
              oPara1.Range.InsertParagraphAfter()
      
              'Everything is OK, then save!
              oDoc.Save()
          Catch ex As Exception
              MsgBox("Error")
          End Try
      
          'Whatever happens always finishes closing word
          oDoc.Close()
          oWord.Quit()
      
      End Sub
      

      【讨论】:

        【解决方案4】:

        我找到了非常简单的解决方案。 Application 对象具有 Quit() 方法,该方法正确关闭 MS Word 应用并释放所有相关资源(并退出 WINWORD.EXE 进程)。

        Application wordApp = new Application();
        wordApp.Visible = false; // Show / hide MS Word app window
        wordApp.ScreenUpdating = false; // Enable / disable screen updates after each change
        
        try
        {
            Document document = wordApp.Documents.Open("example.docx");
        
            // TODO: process the document here ...
        
        }
        finally
        {
            wordApp.Quit(false);
        }
        

        【讨论】:

          猜你喜欢
          • 2012-10-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-12-28
          • 1970-01-01
          • 2014-06-17
          相关资源
          最近更新 更多