Работа с пакетом Microsoft Office в серверном режиме 1С часто сопровождается трудностями. Обычная ситуация: код, который идеально работает на локальном компьютере программиста, при переносе в серверный модуль или на сторону сервера в клиент-серверной базе начинает выдавать «Ошибку команды» или «Ошибку при вызове метода контекста». Это происходит из-за того, что Microsoft Word изначально не предназначен для работы в качестве фонового процесса без графического интерфейса. Рассмотрим подробнее, как решить эти проблемы, проанализируем основные причины сбоев и разберем проверенные алгоритмы формирования документов.
Когда мы запускаем код на сервере, 1С работает от имени специальной системной учетной записи (например, USR1CV8). У этой учетной записи часто нет прав на инициализацию графических оболочек COM-объектов, нет доступа к временным папкам и не настроены права в службе DCOM. Основные причины ошибок ДокументН.SaveAs или Word.Application.Documents.Add заключаются в следующем:
Desktop в профиле пользователя системы для корректной инициализации.Ниже мы разберем два основных пути решения проблемы: «быстрый» (настройка сервера) и «правильный» (изменение архитектуры кода).
Если нам критически важно оставить формирование документа именно на стороне сервера, выполним последовательную настройку операционной системы.
Шаг 1: Создание системных каталогов. Проанализируем файловую структуру сервера. Для корректной работы COM-объекта Word необходимо вручную создать папки Desktop по следующим путям:
C:\Windows\SysWOW64\config\systemprofile\DesktopC:\Windows\System32\config\systemprofile\DesktopБез этих папок Word часто не может инициализировать рабочее пространство, что приводит к отказу при попытке сохранить файл.
Шаг 2: Настройка DCOM. Выясним, как разрешить запуск Word. Для этого воспользуемся оснасткой настройки компонентов:
Win + R, введите dcomcnfg.exe и нажмите Enter.Многие разработчики приходят к выводу, что работа с COM на сервере слишком нестабильна. Рассмотрим более надежный метод: хранение шаблона документа в 1С в виде Двоичных данных и формирование итогового файла на стороне клиента. Это исключает нагрузку на сервер и проблемы с правами.
Инструкция по переделке макета:
Посмотрим на пример кода, который реализует получение макета и его заполнение на клиенте:
// На сервере получаем двоичные данные из макета
Функция ПолучитьМакетНаСервере()
ОбработкаОб = РеквизитФормыВЗначение("Объект");
ДвоичныеДанныеМакета = ОбработкаОб.ПолучитьМакет("МойМакетДвоичныеДанные");
Возврат ПоместитьВоВременноеХранилище(ДвоичныеДанныеМакета);
КонецФункции
// На клиенте работаем с COM-объектом
&НаКлиенте
Процедура СформироватьДокумент()
АдресХранилища = ПолучитьМакетНаСервере();
ДвоичныеДанныеМакета = ПолучитьИзВременногоХранилища(АдресХранилища);
ИмяВременногоФайла = ПолучитьИмяВременногоФайла(".doc");
ДвоичныеДанныеМакета.Записать(ИмяВременногоФайла);
Word = Новый COMОбъект("Word.Application");
Word.Visible = Ложь;
Документ = Word.Documents.Open(ИмяВременногоФайла);
Поиск = Документ.Content.Find;
// Выполняем замену параметров (пример)
Поиск.Execute("[НомерДоговора]", , , , , , , , , "№123-А", 2);
Word.Visible = Истина;
Документ.Activate();
КонецПроцедуры
Разберем ситуацию, когда нам нужно в один файл Word вывести данные по списку объектов (например, несколько договоров подряд). Типичная ошибка — многократное открытие документа в цикле. Вместо этого проанализируем метод с копированием содержимого шаблона и вставкой разделителя страниц.
Рассмотрим пример правильной организации цикла:
&НаКлиенте
Процедура ПечатьМножестваОбъектов(ДанныеДляПечати)
Word = Новый COMОбъект("Word.Application");
// Создаем пустой результирующий документ
ОбщийДокумент = Word.Documents.Add();
ЭтоПервыйВывод = Истина;
Для Каждого СтрокаДанных Из ДанныеДляПечати Цикл
Если Не ЭтоПервыйВывод Тогда
// Вставляем разрыв страницы
Область = ОбщийДокумент.Content;
Область.Collapse(0); // Переход в конец документа (0 - wdCollapseEnd)
Область.InsertBreak(7); // 7 - wdPageBreak
КонецЕсли;
// Здесь логика вставки текста или копирования из шаблона
// Рекомендуется использовать Range.InsertFile(ПутьКФайлуШаблона)
// чтобы избежать проблем с буфером обмена (Clipboard)
Область = ОбщийДокумент.Content;
Область.Collapse(0);
Область.InsertFile(ПутьКВременномуФайлуШаблона);
// Выполняем замену только в последней вставленной секции
// Или работаем с ОбщийДокумент.Content.Find
ЭтоПервыйВывод = Ложь;
КонецЦикла;
Word.Visible = Истина;
КонецПроцедуры
Чтобы избежать «утечек памяти» и зависших процессов WINWORD.EXE в диспетчере задач, всегда придерживайтесь следующих правил:
Попытка...Исключение. В блоке исключения обязательно вызывайте Word.Quit(0).Word.DisplayAlerts = 0; сразу после создания объекта, чтобы Word не пытался задавать вопросы пользователю.Док.GrammarChecked = 0; Док.ShowGrammaticalErrors = 0;), так как это частая причина замедления работы.Selection.Copy() и Selection.Paste(). В серверном режиме буфер обмена является общим ресурсом, и если одновременно запустятся два процесса печати, данные могут перемешаться. Метод Range.InsertFile() гораздо надежнее.Проанализировав вышеописанные методы, можно сделать вывод: для стабильной работы крупных систем наиболее предпочтительным является способ с использованием макетов Двоичные данные и генерацией на клиенте, либо использование современных возможностей платформы (начиная с 8.3.15), таких как объект ЗаписьДокументаWord, который позволяет создавать файлы DOCX напрямую, не требуя установленного Microsoft Office на сервере.