服务器上的 Word 自动化失败,但开发站运行良好

Word automation failing on server, but dev station works great

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

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

Documents.Open() 调用和 doc.SaveAs() 调用均失败,消息 ="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 and/or DocX,但对现有代码进行一些更改比选择新工具更可取,并且从头开始。

不幸的是,Lex Li 完全正确,当然,link 原因发布在我公司认为禁止访问的网站上,因此从未出现在我的 google 搜索中在编码之前。

None 我尝试过的工具能够处理我试图自动化的表单——我需要填写命名字段和 check/uncheck 复选框,这些功能似乎超出了(或非常复杂)我评估的工具...

最终我自己研究了 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