How can I prevent "Application is busy" errors when merging multiple Word documents in VB.net?

0

I am working in Visual Studio (VB.net) and have created an application that queries our database (SQL Server 2008), and then performs effectively a Word mail merge (of my own design) to create one output document containing a series of legal documents, each using a different template (*.dot). The documents have to be kept together by Defendant in the final output document.

So to illustrate, the output file should contain:

Defendant 1 –

  • Document A – page 1
  • Document B – page 2
  • Document C – page 3

Defendant 2 –

  • Document A – page 4
  • Document B – page 5
  • Document C – page 6

And so on.

It does not matter a lot if the documents are ordered A, B, C (though it would be preferred) as long as they are grouped by defendant. Conceptually, I am creating two Word documents: one as a working file where I open the template and merge the data from SQL Server prior to appending, and one as an “output file” which is the final output document.

So the process flow is like this:

  1. Open working file
  2. Add template (*.dot) to working file
  3. Merge SQL Server 2008 data with working file
  4. Save working file
  5. Open output file
  6. Append working file to end of output file
  7. Save and close output file

Each of the document types require its own SQL query as they pull different sets of data, and I’d like this process to run as quickly as possible since it could potentially be drawing a lot of information. Initially I am creating this program to pull documents for only a single case, and then will expand it to permit pulling multiple cases.

To make things go faster, I wanted to get the three queries to run at the same time, and then append the documents in to one at the end of the process. This way we aren’t waiting on one query to return before the other one can begin (slow as molasses!).

I created a list(Of Task) and added the subs that would create each of the documents. Then I used Await Task.WhenAll(tasks) to wait for them all to complete. (Not sure if this the correct/best approach for this type of problem)

The big problem arises when the individual templates are trying to append back in to the Output Doc, and I’m getting messages like “RPC Server is not available”, “Application is busy”, and the like (as shown in my code comments below). From my searches online, it appears there is a solution for this type of issue BUT.... I haven’t found a way to apply it to my situation. I am in need of some guidance and/or examples of how to accomplish this.

I found Geoff Darst’s messages in a few places around the internet, but he does not give any specific examples, and when I looked at his reference link to the IMessageFilter::RetryRejectedCall documentation, the only sample code I could find was in C. I have never written anything in C and don’t know anything about it, so I can’t really translate it to VB.net or apply it to my purposes. Also it didn't seem like it was the answer to this question.

In order to get around this, I was thinking I needed a subroutine that would basically regulate the calls to the Document object and would retry the append operation if the application was busy. As near as I can tell, this is conceptually what Geoff Darst was suggesting, and is the best I could devise given my current experience. My solution feels convoluted (and therefore probably is not the right approach), but I don’t know how else to get the three templates to append in to one document without stepping on each other in the process.

Here is the sub I created (although it still throws errors as shown in the comments) :

Public Sub AppendWordDocument(ByVal WordApp As Word.Application,
                                  ByVal WordDoc As Word.Document,
                                  ByVal FV As FieldValue)

        Dim reentry As String
        Dim findObject As Word.Find
        Dim rng As Word.Range

        findObject = WordApp.Selection.Find
        findObject.Text = FV.Name
        findObject.Replacement.ClearFormatting()
        findObject.Replacement.Text = FV.Value

        'Set error handler
        On Error Resume Next

        'Clear prior searches
RetryClearSearches:
        rng = WordDoc.Content '{"The message filter indicated that the application is busy. (Exception from HRESULT: 0x8001010A (RPC_E_SERVERCALL_RETRYLATER))"}
        If Err.Number <> 0 Then
            reentry = "Search"
            GoTo ErrorHandling
        End If

        rng.Find.ClearFormatting()

        'Execute replacement
        ' Replace 2 = wdReplaceAll (occurrences)  Wrap 1 = Find and continue to search entire document
RetryExecuteReplacement:
        findObject.Execute(FindText:=CStr(findObject.Text), ReplaceWith:=CStr(findObject.Replacement.Text), Replace:=2, Wrap:=1) 'System.Runtime.InteropServices.COMException: 'Command is not available'
        If Err.Number <> 0 Then
            reentry = "Replace"
            GoTo ErrorHandling
        End If

        'Prevent error handling code from running when there are no errors
        Exit Sub
ErrorHandling:

        'Wait one second and return control flow to try again
        Threading.Thread.Sleep(1000)

        'Retry appropriate command
        If reentry = "Search" Then
            GoTo RetryClearSearches
        ElseIf reentry = "Replace" Then
            GoTo RetryExecuteReplacement
        End If
    End Sub

vb.net
ms-word
asked on Stack Overflow Nov 15, 2019 by LegalEagle

1 Answer

0

It was my understanding that the message is coming from Word because it's busy appending one document already when the call to append the next is made.

I unfortunately can't have the document types in separate files because they all have to be grouped together by case as shown above, and I need one final word document as the output.

Surely there's a way to accomplish this.

answered on Stack Overflow Nov 17, 2019 by Isaac A.

User contributions licensed under CC BY-SA 3.0