Weird exception when trying to automate MS Word from vb.net
I use the following vb.net function to purely save Word documents (no text input whatsoever, I'm only interested in mass creation of empty word documents at the moment):
Sub createDoc(ByVal cname As String, ByVal acctype As String)
counter += 1
wordDoc = wordApp.Documents.Add
wordDoc.SaveAs(OFDD.SelectedPath & "\" & cname & "_" & acctype & ".docx")
wordDoc.Close()
End Sub
The OFDD variable is the name of a folder browser vb component, and its SelectedPath property combined with the cname and acctype parameters provide me with the name of the Word document I want to create and save. Here are the declarations of the counter, wordDoc and wordApp variables:
Private Shared counter As Integer = 0
Private wordApp As New Word.Application
Private wordDoc As Word.Document
The wordDoc variable is assigned to a Document object by use of the second line of code in the subroutine createDoc. However, it appears that at the 83rd time that I'm trying to retrieve a document object and assign it to wordDoc I receive an exception stating that "Command failed" . I can tell that it's the 83rd time I enter the function because in my catchblock I print the value of counter in a message box, right after printing details about the received exception and right before I release my used resources and end the process.
Worried about whether my system has limitations related to MS Word automation, I created another Visual Studio project (a Console project, this time), referenced the Microsoft.Interop.Office.Word namespace and wrote the following simple module:
Imports Word = Microsoft.Office.Interop.Word
Module Module1
Sub Main()
Dim wordApp As New Word.Application
Try
For i As Integer = 0 To 150
Dim document As Word.Document = wordApp.Documents.Add()
document.SaveAs("C:\WordTester\" & i & ".docx")
document.Close()
Next
Catch
wordApp.Quit()
End Try
Console.WriteLine("Document objects left in memory: " & _
wordApp.Documents.Count) ' ze开发者_运维百科ro
Console.Read()
wordApp.Quit()
End Sub
End Module
Which works perfectly. Checking my filesystem, I see 150 word files created in "C:\WordTester". Given all these efforts of mine, I'm really baffled as to why the first code I've written gets stuck at the 83rd effort to create and save a document, and any help would be immensely appreciated.
Thank you for your time,
Jason
Edit: Here is the edited version of createDoc which I reference in a comment below:
Sub createDoc(ByVal cname As String, ByVal acctype As String)
counter += 1
wordApp = New Word.Application
wordDoc = New Word.Document
wordDoc = wordApp.Documents.Add
wordDoc.SaveAs(OFDD.SelectedPath & "\" & cname & "_" & acctype & ".docx")
wordDoc.Close()
wordApp.Quit()
End Sub
Try something like this. Obviously I've had to insert a bit of assumed code, but this is pretty much what you should be doing:
Imports Word = Microsoft.Office.Interop.Word
Public Class Class1
Private pWordApp As Word.Application
Private pintCounter As Integer = 0
Public Sub CreateWordDocuments()
'--instanciate word:
pWordApp = New Word.Application
Dim dt As DataTable = GetYourDataEtc 'replace with however you get the data you loop around
Dim OFDD As Object = GetYourFolderPathEtc 'replace Object and folder path call and
Try
For Each dr In dt.Rows
Dim cName As String = dr("cname") 'for example
Dim acctype As String = dr("acctype") #for example
CreateDoc(OFDD, cName, acctype)
Next
Catch ex As Exception
'--some error code
Finally
pWordApp.Quit()
System.Runtime.InteropServices.Marshal.ReleaseComObject(pWordApp)
End Try
End Sub
Private Sub CreateDoc(ByVal OFDD As Object, ByVal cname As String, ByVal accType As String)
Dim document As Word.Document = pWordApp.Documents.Add()
document.SaveAs(OFDD.SelectedPath & "\" & cname & "_" & accType & ".docx")
document.Close()
End Sub
End Class
Looks like a garbage collection problem - the CLR is holding to many references to the word object and is word running out of some resource before garbage collection kicks in. The second function works because everything is scoped locally. You can change the code to scope things locally; also, calling dispose on the worddoc object will help.
Looks like there's no dispose. The proper way is to call the ReleaseComObject method
http://msdn.microsoft.com/en-us/library/aa159887(office.11).aspx
Instead of creating a new instance of Word each time you create a document, I'd rather create ONE instance before the loop for single document creation and using this application object during the loop - this is the approach dunc has proposed.
NOTE: After the loop you release the COM object with Marshal.ReleaseCOMObject. I'd call this function also in the CreateDoc subroutine for the doc object. Please have a look at this discussion about releasing COM objects in Office automation.
After looking into it for the better part of a day at work, I finally found out that the problem didn't lie within the garbage collection process at all. Nor was I creating too many document objects. It just turns out that my database input contained records with double quotes and MS Word does not allow for double quotes in file names.
Thank you for your time and interest.
精彩评论