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 –
Defendant 2 –
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:
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
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.
User contributions licensed under CC BY-SA 3.0