开发者

Weird exception when trying to automate MS Word from vb.net

开发者 https://www.devze.com 2023-03-02 17:57 出处:网络
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):

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消