Vb.net Word自动化在服务器上失败,但dev station运行良好

Vb.net Word自动化在服务器上失败,但dev station运行良好,vb.net,ms-word,iis-8.5,Vb.net,Ms Word,Iis 8.5,我正在通过在网页上查询用户,然后修改一个基本Word文档,并将修改后的文档文件输入到用户的浏览器,以便转交给Word,从而自动化一个经常使用的纸质表单 代码是Visual Basic,我正在使用Microsoft.Office.Interop模块通过操纵Word来操纵文档。在开发系统(Visual Studio 2015)上工作正常,但在生产服务器(IIS 8.5)上工作不正常 Documents.Open()调用和doc.SaveAs()调用都失败,消息为Message=“Command fa

我正在通过在网页上查询用户,然后修改一个基本Word文档,并将修改后的文档文件输入到用户的浏览器,以便转交给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

我尝试过的事情:

  • 增加了对Whatzoo的调试:单步执行在生产机器上不是一个选项,所以我用调试输出找出了问题行

  • 谷歌搜索发现这个问题早在2007年就有报道,但没有报道可行的解决方案

  • 有几个网站提到了时间问题,所以我添加了几次暂停和重试,但没有任何帮助
  • 有些人提到了特权,所以我尝试更改文件权限和应用程序池用户,但都没有帮助

  • 增强了我的异常处理报告,以显示更多详细信息并包括所有内部异常。这就产生了神奇的数字800A1066,这导致了更多的谷歌点击,但没有答案

  • 添加了回退代码:如果无法打开主文档,请创建一个简单的文档。这时我发现SaveAs()调用也失败了

  • 多次返回到开发系统以确认是的,代码在正确的环境中仍然正常工作

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

Dim oWord作为Word.Application
作为Word.Document的Dim oDoc
oWord=CreateObject(“Word.Application”)
oWord.Visible=True
oDoc=oWord.Documents.Open(docName)
将ev变暗为字符串
对于i=0,保存字段。长度为-1
尝试
ev=dataXD.Elements(存储字段(i))(0).Value
抓住
ev=无
结束尝试
如果ev不是什么,那么
尝试
Dim字段=oDoc.FormFields(保存字段(i))
如果字段不是空的,那么
如果field.Type=Word.WdFieldType.wdFieldFormTextInput,则
字段。结果=ev
如果结束
如果结束
捕获e作为例外
ErrorOut(“捕获异常!”&e.Message)
结束尝试
如果结束
下一个
...
oDoc.SaveAs2(localDir和文件名)
奥多克关闭()
oWord.Quit(0,0,0)
代码应生成一个修改后的表单(填写参数数据的字段);相反,它无法打开,并且回退代码无法保存新文档

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


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

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

我尝试的工具中没有一个能够处理我试图自动化的表单——我需要填写命名字段并选中/取消选中复选框,这些功能似乎超出了我评估的工具的范围(或非常复杂)

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

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

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

这是我最接近一个复杂的部分。如果给定条件为true,此函数将从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
私有共享函数markCheckbox(xmlString作为字符串,cbName作为字符串,checkValue作为布尔值)作为字符串
markCheckbox=xmlString
如果需要选中“checkValue Then”复选框,请继续
Dim pos As Integer=markCheckbox.IndexOf(“”)
如果pos>-1,则“我们有一个复选框
Dim endPos As Integer=markCheckbox.IndexOf(“,pos+1)
Dim cbEnd As Integer=markCheckbox.IndexOf(“”,位置+1)
如果endPos>cbEnd和ALSO cbEnd>-1,则“已找到适当的w:ffData元素(pos->endPos)和包含的插入点(cbEnd)
markCheckbox=markCheckbox.Substring(0,cbEnd)&“&markCheckbox.Substring(cbEnd)
如果结束
'任何其他逻辑条件,返回未混合的原始XML字符串。
如果结束
如果结束
端函数

微软根本不支持