尝试从 vb.net 自动化 MS Word 时出现奇怪的异常

问题描述 投票:0回答:4

我使用以下vb.net函数纯粹保存Word文档(没有任何文本输入,我目前只对批量创建空word文档感兴趣):

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

OFDD 变量是文件夹浏览器 vb 组件的名称,其 SelectedPath 属性与 cname 和 acctype 参数相结合,为我提供了要创建和保存的 Word 文档的名称。以下是 counter、wordDoc 和 wordApp 变量的声明:

 Private Shared counter As Integer = 0
 Private wordApp As New Word.Application
 Private wordDoc As Word.Document

使用子例程 createDoc 中的第二行代码将 wordDoc 变量分配给 Document 对象。但是,似乎在第 83 次尝试检索文档对象并将其分配给 wordDoc 时,我收到一条异常,指出“命令失败”。我可以看出这是我第 83 次进入该函数,因为在我的 catch 块中,我在打印有关收到的异常的详细信息之后、释放我使用的资源并结束进程之前,在消息框中打印了计数器的值。

担心我的系统是否存在与 MS Word 自动化相关的限制,我创建了另一个 Visual Studio 项目(这次是控制台项目),引用了 Microsoft.Interop.Office.Word 命名空间并编写了以下简单模块:

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) ' zero
    Console.Read()
    wordApp.Quit()
End Sub

End Module

效果非常好。检查我的文件系统,我看到在“C:\WordTester”中创建了 150 个单词文件。鉴于我所做的所有这些努力,我真的很困惑为什么我编写的第一个代码在创建和保存文档的第 83 次努力中陷入困境,并且我们将非常感谢任何帮助。

感谢您的宝贵时间,

杰森

编辑:这是 createDoc 的编辑版本,我在下面的评论中引用了它:

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
vb.net ms-word
4个回答
2
投票

尝试这样的事情。 显然,我必须插入一些假设的代码,但这几乎是您应该做的:

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

0
投票

看起来像一个垃圾收集问题 - CLR 保留了对 word 对象的许多引用,并且在垃圾收集启动之前,word 耗尽了某些资源。第二个函数之所以有效,是因为所有内容都在本地范围内。您可以更改代码以在本地范围内进行操作;另外,对 worddoc 对象调用 dispose 也会有所帮助。

看起来没有处置。正确的方法是调用ReleaseComObject方法

http://msdn.microsoft.com/en-us/library/aa159887(office.11).aspx


0
投票

我宁愿在循环之前创建一个实例来创建单个文档,并在循环期间使用此应用程序对象,而不是每次创建文档时都创建一个新的 Word 实例 - 这是 dunc 提出的方法。

注意:循环结束后,您可以使用 Marshal.ReleaseCOMObject 释放 COM 对象。我也会在 doc 对象的 CreateDoc 子例程中调用此函数。 请查看有关在办公自动化中释放 COM 对象的讨论


0
投票

问题根本不在于垃圾收集过程。我也没有创建太多文档对象。结果发现我的数据库输入包含带双引号的记录,而 MS Word 不允许文件名中使用双引号。

© www.soinside.com 2019 - 2024. All rights reserved.