Ошибка автоматизации Word на сервере, но Dev Station отлично работает - PullRequest
1 голос
/ 05 октября 2019

Я автоматизирую часто используемую бумажную форму, запрашивая пользователя на веб-странице, затем изменяя базовый документ Word и передавая этот измененный файл doc в браузер пользователя для передачи в Word.

Код - Visual Basic, и я использую модуль Microsoft.Office.Interop для манипулирования документом с помощью Word. Прекрасно работает в системе разработки (Visual Studio 2015), но не на рабочем сервере (IIS 8.5).

Сбой при вызове Documents.Open () и вызова doc.SaveAs () с помощью команды Message = "Ошибка "Source =" Microsoft Word "HResult = 0x800A1066

То, что я пробовал:

  • Добавлена ​​отладка whazoo: одноступенчатый не вариант напроизводственной машины, поэтому я точно определил проблемные строки с помощью отладочной информации.

  • Гуглил и обнаружил, что об этой проблеме сообщалось еще в 2007 году, но не было найдено жизнеспособных решений.

  • На нескольких сайтах упоминались проблемы с синхронизацией, поэтому я добавил несколько пауз и повторов - ни один не помог.
  • Некоторые упоминали о привилегиях, поэтому я попытался изменить права доступа к файлам и пользователей пула приложений - ни один не помог.

  • Улучшены мои отчеты по обработке исключений, чтобы показать больше деталей ивключите все внутренние исключения. Это дало волшебный номер 800A1066, который привел к большему количеству посещений Google, но не дал ответов.

  • Добавлен запасной код: если вы не можете открыть основной документ, создайте простой. Именно тогда я обнаружил, что вызов SaveAs () также не удался.

  • Несколько раз возвращался в систему разработки, чтобы подтвердить, что да, код все еще работает правильно в правильной среде.

Пример сильно сжатого кода не включает в себя запасную логику. В моем документе 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, но внесение нескольких изменений в существующий код гораздо предпочтительнее, чем выбор нового инструмента. и начать заново с нуля.

1 Ответ

2 голосов
/ 14 октября 2019

К сожалению, Лекс Ли был абсолютно прав, и, конечно же, ссылка на причину, по которой моя компания размещает информацию на сайте, который считается недопустимым, таким образом, никогда не обнаруживалась в моих поисках в Google до кодирования.

Ни один из инструментов, которые я пробовал, также не смог обработать форму, которую я пытался автоматизировать - мне нужно было заполнить именованные поля и поставить / снять флажки, способности, которые казались мне более (или ужасно сложными) инструментами, которые я оценивал. ..

В конце концов я сам копался в формате document.xml;Я разработал функцию изменения XML для проверки именованного флажка и манипулировал необработанным document.xml, чтобы заменить текстовые поля именами * -delimited токенов. Это уменьшило все необходимые изменения до простой манипуляции со строками - все остальное было тривиально.

Инструмент на 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
...