首页 > 解决方案 > 服务器上的 Word 自动化失败,但开发站运行良好

问题描述

我通过在网页上查询用户,然后修改基本 Word 文档并将修改后的 doc 文件提供给用户的浏览器以移交给 Word,从而使经常使用的纸质表单自动化。

代码是 Visual Basic,我使用 Microsoft.Office.Interop 模块通过操纵 Word 来操纵文档。在开发系统 (Visual Studio 2015) 上运行良好,但在生产服务器 (IIS 8.5) 上运行良好。

Documents.Open() 调用和 doc.SaveAs() 调用都失败了 Message="Command failed" Source="Microsoft Word" HResult=0x800A1066

我尝试过的事情:

非常精简的示例代码不包含回退逻辑。我的 Word 文档有许多字段,它们的名称与作为参数传递给此函数的 XML 标记相匹配。saveFields() 是这些名称的数组。

        Dim oWord As Word.Application
        Dim oDoc As Word.Document
        oWord = CreateObject("Word.Application")
        oWord.Visible = True
        oDoc = oWord.Documents.Open(docName)

        Dim ev As String
        For i = 0 To saveFields.Length - 1
            Try
                ev = dataXD.Elements(saveFields(i))(0).Value
            Catch
                ev = Nothing
            End Try
            If ev IsNot Nothing Then
                    Try
                        Dim field = oDoc.FormFields(saveFields(i))
                        If field IsNot Nothing Then
                            If field.Type = Word.WdFieldType.wdFieldFormTextInput Then
                                field.Result = ev
                            End If
                        End If
                    Catch e As Exception
                        ErrorOut("Caught exception! " & e.Message)
                    End Try
            End If
        Next
...
        oDoc.SaveAs2(localDir & filename)
        oDoc.Close()
        oWord.Quit(0, 0, 0)

代码生成修改后的表单(使用参数数据填充的字段);相反,它无法打开,并且后备代码无法保存新文档。

在我的开发系统上,文档得到了应有的修改,如果我在正确的位置中断并更改了正确的变量,则回退代码运行并成功生成备用文档——但在生产服务器上,两条路径都失败并出现相同的错误.

除非这里有更好的答案,否则我接下来的步骤是检查和使用 OpenXML 和/或 DocX,但是对现有代码进行一些更改比选择一个新工具并从头开始要好得多。

标签: vb.netms-wordiis-8.5

解决方案


不幸的是,Lex Li 是绝对正确的,当然,指向原因的链接发布在我公司认为禁止访问的网站上,因此在编码之前从未出现在我的谷歌搜索中。

我尝试过的任何工具都无法处理我试图自动化的表单——我需要填写命名字段并选中/取消选中复选框,这些能力似乎超出了我评估的工具(或非常复杂)......

最终我自己研究了 document.xml 格式;我开发了一个函数来修改 XML 以检查命名复选框,并操作原始 document.xml 以用 * 分隔的标记名称替换文本字段。这减少了对简单字符串操作的所有必要更改——其余的都是微不足道的。

该工具是 100% 本土开发的,不依赖于任何非系统库,并且 100% 适用于这种特定形式。无论如何,这都不是一个通用的解决方案,我怀疑 document.xml 文件在文档被修改时需要手动更改。

但是对于这个特殊的问题——它是一个解决方案。

这是我最接近复杂部分的地方。如果给定条件为真,此函数将检查(但不会取消选中)来自document.xml的命名复选框。

    Private Shared Function markCheckbox(xmlString As String, cbName As String, checkValue As Boolean) As String
        markCheckbox = xmlString
        If checkValue Then ' Checkbox needs to be checked, proceed
            Dim pos As Integer = markCheckbox.IndexOf("<w:ffData><w:name w:val=""" & cbName & """/>")
            If pos > -1 Then ' We have a checkbox
                Dim endPos As Integer = markCheckbox.IndexOf("</w:ffData>", pos+1)
                Dim cbEnd As Integer = markCheckbox.IndexOf("</w:checkBox>", pos+1)
                If endPos > cbEnd AndAlso cbEnd > -1 Then ' Have found the appropriate w:ffData element (pos -> endPos) and the included insert point (cbEnd)
                    markCheckbox = markCheckbox.Substring(0, cbEnd) & "<w:checked/>" & markCheckbox.Substring(cbEnd)
                End If
                ' Any other logic conditions, return the original XML string unmangled.
            End If
        End If
    End Function

推荐阅读