【问题标题】:'The RPC server is unavailable.' when looping through word documents'RPC 服务器不可用。循环浏览word文档时
【发布时间】:2019-07-12 20:30:45
【问题描述】:

我正在开发一个实用程序来查找和更新 Word 中的 DOC 变量。我有一段代码可以遍历文档并显示带有变量名称的消息框,但是当它尝试打开下一个文档时收到错误消息。错误是:

System.Runtime.InteropServices.COMException: 'RPC 服务器不可用。 (HRESULT 异常:0x800706BA)

我很困惑,因为我的代码没有访问任何网络。我认为可能发生的情况是文档关闭时 Word 正在关闭,但我找不到防止这种情况发生的解决方案。

我尝试过的其他事情:

  1. 已确认 UAC 已禁用
  2. 已确认 RPC 服务正在运行
  3. 已确认 RPC 和 DCOM 的注册表值正确

    Private Sub LoopTemp()
        Dim oDir As New DirectoryInfo(dPath)
        Dim oFileArr As FileInfo() = oDir.GetFiles()
        Dim oFile As FileInfo
        Dim oVar As Variable
        Dim oDoc = New Document()
    
        Dim oWord As Application
        oWord = CreateObject("Word.Application")
        oWord.Visible = False
    
        For Each oFile In oFileArr
           oDoc = oWord.Documents.Open(oFile.FullName)
    
           For Each oVar In oDoc.Variables
               MsgBox(oVar.Name)
           Next
    
           oDoc.Close(SaveChanges:=WdSaveOptions.wdSaveChanges)
    
        Next
        oWord.Quit()
    End Sub
    

【问题讨论】:

  • 你在哪里运行上面列出的代码?是来自asp.net还是service?

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


【解决方案1】:

当一个指向 COM 对象的“指针”在代码尝试重用它之前没有从内存中正确释放时,就会出现 RPC 错误。当从应用程序本身自动化 Office 应用程序时,这是一个很常见的问题。尤其是在使用 .NET 工作时,必须非常小心。

要注意的另一件非常重要的事情是 New 关键字不应与任何 Office 对象一起使用除了 Application。尽管 API 允许这样做,但切勿将 New Document 与 Word 一起使用,因为这会创建一个无法正确释放的 Document 对象。

出于效率的原因,启动 Word 应用程序一次 就足够了 - 只要它使用的 COM 对象被正确释放(设置为 @987654325 @ 和垃圾收集)。

我会在问题中编写如下代码:

Private Sub LoopTemp()
    Dim oDir As New DirectoryInfo(dPath)
    Dim oFileArr As FileInfo() = oDir.GetFiles()
    Dim oFile As FileInfo
    Dim oVar As Variable = Nothing
    Dim oWord As Application = NOthing
    Dim oDoc As Document = Nothing

    oWord = New Word.Application
    oWord.Visible = False

    For Each oFile In oFileArr
        oDoc = oWord.Documents.Open(oFile.FullName)
        For Each oVar In oDoc.Variables
            MsgBox(oVar.Name)
        Next
        oVar = Nothing
        oDoc.Close(SaveChanges:=WdSaveOptions.wdSaveChanges)
        oDoc = Nothing

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

    oWord.Quit()
    oWord = Nothing
    GC.Collect()
    GC.WaitForPendingFinalizers()
    GC.Collect()
    GC.WaitForPendingFinalizers()

End Sub

【讨论】:

  • 如果Application 在循环中消失,GC 如何提供帮助?
  • 应用程序在在我的代码中循环中消失的位置,@EugeneAstafiev?循环中唯一被释放的是循环中创建的对象。
  • 我相信您的代码和海报工作正常。但是根据提到的错误,应用程序变得不可用。 GC 如何帮助解决这个问题?
  • @EugeneAstafiev 如果 any 对象在内存中“挂起”,而不仅仅是应用程序,则会发生错误。 GC 将确保在循环尝试重新分配这些对象之前肯定释放它们。在 VBA 世界中,Set object = Nothing“立即”工作以释放对象;在 .NET 世界中,首先需要对对象进行垃圾回收,除非强制进行 GC,否则这是不确定的。遗憾的是,Andrew Whiteshapel 书中的摘录不再发布在 MS 文档中 - 这很好地解释了问题......
  • 在 .net 世界中,我们处理的是 RCW 对象,而不是真正的 COM 服务器。如果没有设置它并不意味着我们以后可以重新使用它们。所以,我看不出任何可能的解释。
【解决方案2】:
'Loop through .docx files replacing variables
Private Sub LoopTemp()
    Dim oDir As New DirectoryInfo(dPath)
    Dim oFileArr As FileInfo() = oDir.GetFiles()
    Dim oFile As FileInfo
    Dim oVar As Variable
    Dim oWord As Application

    For Each oFile In oFileArr

        oWord = CreateObject("Word.Application")
        oWord.Visible = False

        GC.Collect()
        GC.WaitForPendingFinalizers()

        Dim oDoc = New Document()
        oDoc = oWord.Documents.Open(oFile.FullName)

        For Each oVar In oDoc.Variables
            MsgBox(oVar.Name)
        Next

        oDoc.Close(SaveChanges:=WdSaveOptions.wdSaveChanges)
        Marshal.FinalReleaseComObject(oDoc)

        oWord.Quit()
        Marshal.FinalReleaseComObject(oWord)

    Next

End Sub

当我将 oWord 移到循环中时,更新的代码起作用了。现在它为每个文档创建一个新对象并退出。不知道有没有更好的办法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-22
    相关资源
    最近更新 更多