Автоматическое заполнение печатных форм и договоров в формате Microsoft Word — распространенная задача при разработке на платформе 1С:Предприятие. Однако при использовании механизма COMОбъект("Word.Application") разработчики часто сталкиваются с существенным падением производительности: замена всего нескольких текстовых меток в небольшом документе может занимать от одной до двух минут. Разберем подробно, почему возникает такая задержка, как оптимизировать код работы с COM и какие современные альтернативы существуют.
Проанализируем ключевые факторы, влияющие на скорость выполнения операций с документом Word через интерфейс автоматизации:
Selection и посимвольной вставке) требует передачи данных между процессами 1cv8.exe и WINWORD.EXE с маршалингом типов данных.WINWORD.EXE, блокирующие файл общего шаблона Normal.dotm и оперативную память.Рассмотрим типовой программный код выгрузки макета, создания документа и замены текстовых маркеров с учетом ограничения MS Word на длину строки поиска в 250 символов:
Шаблон = ПолучитьИмяВременногоФайла("dot");
Макет = ПолучитьМакет("паспДанные");
Попытка
Макет.Записать(Шаблон);
Исключение
Предупреждение("Проблема при записи шаблона!");
Возврат;
КонецПопытки;
Word = Новый COMОбъект("Word.Application");
Word.DisplayAlerts = 0; // Отключаем показ предупреждений
Word.Visible = 0;
Word.ScreenUpdating = 0;
Попытка
мФайл = Новый Файл(Шаблон);
Если НЕ мФайл.Существует() Тогда
Сообщить("Файл шаблона MS Word не обнаружен!", СтатусСообщения.Важное);
Возврат;
КонецЕсли;
НовыйДокумент = Word.Documents.Add(Шаблон);
ЗаменаВWord(Word, "#ДатаДоговора#", Формат(СсылкаНаОбъект.Дата, "ДЛФ=DD"));
ЗаменаВWord(Word, "#НомДог#", СокрЛП(СсылкаНаОбъект.Номер));
Word.ScreenUpdating = 1;
Word.Visible = 1;
Word.Activate();
Word.ActiveWindow.WindowState = 1;
Исключение
Сообщить("Ошибка при выводе шаблона документа в Word: " + ОписаниеОшибки(), СтатусСообщения.Важное);
Word.Quit();
Word = Неопределено;
КонецПопытки;
Для процедуры замены текста используем следующий алгоритм обработки длинных строк и поиска по содержимому:
Процедура ЗаменаВWord(Word, СтароеЗначение = "", НовоеЗначение = "") Экспорт
Попытка
Если ЗначениеЗаполнено(НовоеЗначение) Тогда
Если ТипЗнч(НовоеЗначение) = Тип("Строка") И СтрДлина(НовоеЗначение) >= 250 Тогда
Н = Цел(СтрДлина(НовоеЗначение) / 250);
ДлинаСтроки = НовоеЗначение;
Если Word.Selection.Find.Execute(СтароеЗначение, 0, -1, , , , -1, , , "", ) = -1 Тогда
Word.Selection.Select();
Word.Selection.Cut();
Для К = 0 По Н Цикл
Word.Selection.Paste();
Подстрока = СокрЛП(Сред(ДлинаСтроки, К * 250 + 1, 250));
Word.ActiveDocument.Content.Find.Execute(СтароеЗначение, 1, , , , , , , , Подстрока, 2);
КонецЦикла;
КонецЕсли;
Иначе
Word.ActiveDocument.Content.Find.Execute(СтароеЗначение, 1, , , , , , , , НовоеЗначение, 2);
КонецЕсли;
Иначе
Word.ActiveDocument.Content.Find.Execute(СтароеЗначение, 1, , , , , , , , "", 2);
КонецЕсли;
Исключение
Сообщить("Ошибка при замене значения в Word: " + ОписаниеОшибки(), СтатусСообщения.Важное);
КонецПопытки;
КонецПроцедуры
Чтобы ускорить формирование печатной формы в несколько раз, применим следующие программные настройки:
Word.ScreenUpdating = Ложь;
Word.DisplayAlerts = 0; // wdAlertsNone
Word.Options.CheckSpellingAsYouType = Ложь;
Word.Options.CheckGrammarAsYouType = Ложь;
Word.Options.Pagination = Ложь;
Word.ActiveDocument.Bookmarks("ИмяЗакладки").Range.Text = "Текст" работает значительно быстрее, чем последовательный перебор всего содержимого через метод Find.Execute.Документ.Close(0), завершаем процесс через Word.Quit() и очищаем переменную в блоке Исключение, чтобы не оставлять «висячих» процессов в памяти.Разберем технические ограничения, с которыми связано использование COM-соединений:
COMОбъект доступен исключительно в среде Windows. При работе серверов 1С или клиентских рабочих мест на Linux/macOS создание COM-объектов не поддерживается.Для создания масштабируемых и быстрых решений без зависимости от установленного пакета Microsoft Office применяют следующие механизмы:
{v8 ИмяПараметра} позволяет формировать документы на стороне сервера за доли секунды..docx представляет собой архив с XML-документами, можно распаковать его объектом ЧтениеZipФайла, заменить нужные строки в файле word/document.xml и запаковать обратно с помощью ЗаписьZipФайла.ТабличныйДокумент с последующим программным сохранением в DOCX или PDF с помощью метода ТабличныйДокумент.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.DOCX).