Nano Hash - криптовалюты, майнинг, программирование

Странное исключение при попытке автоматизировать MS Word с vb.net

Я использую следующую функцию 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

Переменная wordDoc присваивается объекту Document с помощью второй строки кода в подпрограмме createDoc. Однако похоже, что на 83-й раз, когда я пытаюсь получить объект документа и назначить его wordDoc, я получаю исключение, указывающее, что «команда не выполнена». Я могу сказать, что это 83-й раз, когда я вхожу в функцию, потому что в моем блоке перехвата я печатаю значение счетчика в окне сообщения сразу после вывода сведений о полученном исключении и прямо перед тем, как я освобождаю использованные ресурсы и завершаю процесс.

Обеспокоенный тем, есть ли в моей системе ограничения, связанные с автоматизацией 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

Который отлично работает. Проверяя свою файловую систему, я вижу файлы размером 150 слов, созданные в «C:\WordTester». Учитывая все эти мои усилия, я действительно озадачен тем, почему первый код, который я написал, застревает на 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
03.05.2011

Ответы:


1

Попробуйте что-нибудь вроде этого. Очевидно, мне пришлось вставить немного предполагаемого кода, но это в значительной степени то, что вы должны делать:

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
03.05.2011
  • Да, это всегда в 83-й раз. Мой ввод берется из запроса базы данных SQL Server с примерно 250 записями, поэтому я проверил, могут ли вводные данные вокруг строки 83 иметь поля NULL; это не тот случай. Мой существующий блок catch имеет следующие выходные данные Message Box: MsgBox("Error : " & Err.Description & " from method: " & Err.Source & " in line " & Err.Erl & ".", vbCritical) MsgBox("Document Objects in memory: " & wordApp.Documents.Count) MsgBox("Counter variable value : " & counter) , что, я думаю, будет достаточно словесным, возможно? 03.05.2011
  • Я имел в виду поместить еще один блок try catch в реальную подпрограмму CreateDoc и сломать ошибку. Затем опросите объект слова, чтобы увидеть, что случилось. 03.05.2011
  • Booji Boy прав в том, что он говорит. Однако ваша отредактированная процедура CreateDoc не является хорошей идеей, поскольку вы начинаете и закрываете слово для каждого документа. Почему бы просто не скопировать рабочий код консоли в класс. Создать ссылку на слово вверху, обработать каждый документ закрытым словом и удалить? 03.05.2011

  • 2

    Похоже на проблему со сборкой мусора - CLR удерживает множество ссылок на объект слова, и слово исчерпает какой-то ресурс до того, как начнется сборка мусора. Вторая функция работает, потому что все ограничено локально. Вы можете изменить код для локального охвата; также может помочь вызов dispose для объекта worddoc.

    Похоже, что распоряжения нет. Правильный способ - вызвать метод ReleaseComObject

    http://msdn.microsoft.com/en-us/library/aa159887(office.11).aspx

    03.05.2011
  • Хм, боюсь, я не совсем понимаю, что вы подразумеваете под локальным охватом. На что мне следует изменить характер моего кода, чтобы убедиться, что сборка мусора не испортит ситуацию? 03.05.2011
  • Кроме того, что касается вызова Dispose() для объекта worddoc, я получаю исключение, в котором говорится, что «Открытый член Dispose() для типа DocumentClass не найден». 03.05.2011
  • и wordapp, и word doc объявлены в подсистеме (локальной области), поэтому оба они попадают в кучу, а не в стек. Стек будет очищен после того, как подпрограмма завершит работу. Первый код имеет wordapp и worddoc, объявленные в модуле и, следовательно, (глобальная область) и попадет в кучу, и сборщику мусора потребуется больше времени, чтобы очистить его. 03.05.2011
  • Однако не этого ли я хочу? Я имею в виду, что я хочу, чтобы объекты очищались как можно позже, чтобы мои объекты wordDoc и wordApp не начали вести себя неправильно, как сейчас. Также следует отметить, что иерархия первого кода выглядит следующим образом: class->sub main->central для цикла, который вызывает sub createDoc(), если выполняются некоторые требования. 03.05.2011
  • Да, объявить все локально будет медленнее, но это поможет с очисткой мусора. может помочь что-то вроде простого изменения объявления wordapp на Dim wordApp As Word.Application и создания экземпляра wordApp = New Word.Application в конструкторе. также установите worddoc = ничего после вызова close 03.05.2011
  • Я изменил createDoc на то, что показано в редактировании моего исходного сообщения, но все еще сталкиваюсь с той же ошибкой. Следует также отметить, что до того, как я это сделал, я пробовал System.GC.KeepAlive(wordApp) и System.GC.KeepAlive(wordDoc) после того, как были сделаны все вызовы этой подпрограммы. Проблема осталась. 03.05.2011

  • 3

    Вместо создания нового экземпляра Word каждый раз, когда вы создаете документ, я бы предпочел создать ОДИН экземпляр перед циклом для создания одного документа и использовать этот объект приложения во время цикла - это подход, предложенный Dunc.

    ПРИМЕЧАНИЕ. После цикла вы освобождаете COM-объект с помощью Marshal.ReleaseCOMObject. Я бы также вызвал эту функцию в подпрограмме CreateDoc для объекта документа. Пожалуйста, взгляните на это обсуждение об освобождении COM-объектов в автоматизации Office.

    04.05.2011

    4

    Изучив его большую часть дня на работе, я наконец обнаружил, что проблема вовсе не в процессе сборки мусора. Я также не создавал слишком много объектов документа. Просто оказалось, что мои входные данные базы данных содержали записи с двойными кавычками, а MS Word не допускает двойных кавычек в именах файлов.

    Спасибо за ваше время и интерес.

    04.05.2011
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

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

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..