I am working on a utility to find and update DOC VARIABLES in Word. I have a section of code to loop through the documents and present a Message Box with the variable name, but I'm receiving an error when it tries to open the next document. The error is:
System.Runtime.InteropServices.COMException: 'The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
I'm confused because my code does not access any network. I think what might be happening is the Word is closing when the document closes, but I cannot find a solution to prevent that.
Other things I've tried:
Confirmed Registry Values for RPC and DCOM are correct
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
The RPC error appears when a "pointer" to a COM object is not correctly released from memory before code tries to re-use it. This is a common enough problem when automating Office applications from outside the application, itself. Especially when working from .NET great care must be used.
Another very important thing to note is that the New
keyword should never be used with any Office object except Application
. Although the APIs allow it, never use New Document
with Word as this creates a Document
object that can't be correctly released.
For reasons of efficiency, starting the Word application once should be sufficient - it's not necessary to repeat that within a loop, as long as the COM objects it uses are correctly released (set to Nothing
and garbage collected).
I would write the code in the question as follows:
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
'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
The updated code worked when I moved oWord into the loop. Now it creates a new object and quits for each document. I'm not sure if there's a better way.
User contributions licensed under CC BY-SA 3.0