我使用以下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
尝试这样的事情。 显然,我必须插入一些假设的代码,但这几乎是您应该做的:
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
看起来像一个垃圾收集问题 - CLR 保留了对 word 对象的许多引用,并且在垃圾收集启动之前,word 耗尽了某些资源。第二个函数之所以有效,是因为所有内容都在本地范围内。您可以更改代码以在本地范围内进行操作;另外,对 worddoc 对象调用 dispose 也会有所帮助。
看起来没有处置。正确的方法是调用ReleaseComObject方法
http://msdn.microsoft.com/en-us/library/aa159887(office.11).aspx
我宁愿在循环之前创建一个实例来创建单个文档,并在循环期间使用此应用程序对象,而不是每次创建文档时都创建一个新的 Word 实例 - 这是 dunc 提出的方法。
注意:循环结束后,您可以使用 Marshal.ReleaseCOMObject 释放 COM 对象。我也会在 doc 对象的 CreateDoc 子例程中调用此函数。 请查看有关在办公自动化中释放 COM 对象的讨论。
问题根本不在于垃圾收集过程。我也没有创建太多文档对象。结果发现我的数据库输入包含带双引号的记录,而 MS Word 不允许文件名中使用双引号。