Разработка внешних печатных форм (ВПФ) с использованием Microsoft Word — это классическая задача, с которой сталкиваются многие программисты 1С. Однако часто возникает ситуация, когда обработка прекрасно работает при запуске через Файл — Открыть, но выдает ошибку сразу после регистрации в справочнике Дополнительные отчеты и обработки. Проанализируем ситуацию, выясним причину такого поведения и разберем по шагам правильную архитектуру печатной формы.
Основная причина кроется в особенностях работы системы «1С:Предприятие» в клиент-серверном варианте и механизмах Библиотеки стандартных подсистем (БСП). Рассмотрим подробнее, что происходит:
ВызовСерверногоМетода).COMОбъект("Word.Application") на сервере, система либо возвращает ошибку «Метод объекта не обнаружен», либо процесс WINWORD.EXE «зависает» в памяти, не имея возможности отобразить окно пользователю.Для решения этой проблемы нам необходимо перенести ту часть кода, которая взаимодействует с Word, на сторону клиента, оставив подготовку данных на сервере.
Первым делом проанализируем функцию СведенияОВнешнейОбработке в модуле объекта. Чтобы иметь возможность взаимодействовать с приложением на компьютере пользователя, нам нужно изменить тип запуска команды. Вместо стандартного серверного вызова мы должны указать клиентский.
Найдем в таблице команд настройку поля Использование. Вместо ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовСерверногоМетода() необходимо прописать использование клиентского метода:
НоваяКоманда = ТаблицаКоманд.Добавить();
НоваяКоманда.Представление = "Печать договора в Word";
НоваяКоманда.Идентификатор = "ПечатьВорд"; // Имя процедуры в модуле формы
НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода();
НоваяКоманда.ПоказыватьОповещение = Истина;
НоваяКоманда.Модификатор = "ПечатьMXL";
Рассмотрим стратегию «наименьшего сопротивления»: мы будем подготавливать макет и заполнять его данными на сервере, превращать его в двоичные данные и передавать на клиент. В модуле объекта создадим функцию, которая будет возвращать адрес во временном хранилище.
Разберем пример функции ПечатьМакета:
Функция ПечатьМакета(ОбъектыНазначенияМассив, ОбъектыПечати) Экспорт
// Получаем макет из обработки (макет должен быть типа "Двоичные данные")
Макет = ПолучитьМакет("ДоговорШаблон");
// Создаем временный файл на сервере для манипуляций
ИмяВременногоФайла = ПолучитьИмяВременногоФайла(".docx");
Макет.Записать(ИмяВременногоФайла);
// Здесь может быть логика заполнения документа на сервере,
// если используются средства без COM (например, замена текста в XML)
// Но в нашем случае мы просто передаем заполненный или исходный файл на клиент
ДвоичныеДанные = Новый ДвоичныеДанные(ИмяВременногоФайла);
АдресВХранилище = ПоместитьВоВременноеХранилище(ДвоичныеДанные);
Попытка
УдалитьФайлы(ИмяВременногоФайла);
Исключение
// Файл может быть занят, это не критично для сервера
КонецПопытки;
Возврат АдресВХранилище;
КонецФункции
Теперь выясним, как правильно принять эти данные в форме и открыть Word. В модуле формы должна быть экспортная процедура Печать (или с тем идентификатором, который вы указали при регистрации). Она будет выступать «дирижером» процесса.
Проанализируем структуру кода в модуле формы:
&НаКлиенте
Процедура Печать(ИдентификаторКоманды, ОбъектыНазначенияМассив) Экспорт
// 1. Вызываем серверную функцию для подготовки файла
РезультатПечати = ПодготовитьФайлНаСервере(ОбъектыНазначенияМассив);
Если РезультатПечати = Неопределено Тогда
Возврат;
КонецЕсли;
// 2. Получаем данные из хранилища на клиент
ДвоичныеДанные = ПолучитьИзВременногоХранилища(РезультатПечати);
ИмяФайлаНаКлиенте = ПолучитьИмяВременногоФайла(".docx");
ДвоичныеДанные.Записать(ИмяФайлаНаКлиенте);
// 3. Работаем с COM-объектом непосредственно на клиенте
Попытка
WordПриложение = Новый COMОбъект("Word.Application");
Документы = WordПриложение.Documents;
// Открываем файл
НовыйДокумент = Документы.Open(ИмяФайлаНаКлиенте);
// Делаем Word видимым
WordПриложение.Visible = Истина;
WordПриложение.Activate();
// Пример заполнения закладок (Bookmarks) на клиенте
Если НовыйДокумент.Bookmarks.Exists("НомерДоговора") Тогда
НовыйДокумент.Bookmarks("НомерДоговора").Select();
WordПриложение.Selection.TypeText("№123-БП");
КонецЕсли;
Исключение
Сообщить("Ошибка при работе с Microsoft Word: " + ОписаниеОшибки());
Если WordПриложение <> Неопределено Тогда
WordПриложение.Quit();
КонецЕсли;
КонецПопытки;
КонецПроцедуры
&НаСервере
Функция ПодготовитьФайлНаСервере(ОбъектыНазначенияМассив)
ОбъектОбработка = РеквизитФормыВЗначение("Объект");
ОбъектыПечати = Новый СписокЗначений;
Возврат ОбъектОбработка.ПечатьМакета(ОбъектыНазначенияМассив, ОбъектыПечати);
КонецФункции
Рассмотрим ситуацию с «двойным открытием» Word, о которой часто упоминают пользователи. Это происходит, когда команда Word.Visible = Истина вызывается несколько раз или когда и на сервере, и на клиенте пытаются инициализировать приложение. Чтобы этого избежать, никогда не используйте COMОбъект внутри серверных процедур модуля объекта в контексте ВПФ. Вся визуализация должна происходить только в конце клиентской процедуры Печать.
Также важно обратить внимание на тип макета. В современных версиях 1С рекомендуется хранить шаблоны Word как Двоичные данные. Это позволяет избежать проблем с попыткой 1С автоматически интерпретировать файл как Active Document в момент получения макета на сервере, что часто приводит к ошибкам прав доступа или несовместимости разрядности (32/64 бит).
Полезный совет: Для более стабильной работы используйте замену параметров в тексте документа через поиск и замену, а не через закладки, если структура документа сложная. Это менее чувствительно к случайному удалению закладок пользователем при редактировании шаблона.
Подводя итог, мы проанализировали основные ошибки и выработали надежный алгоритм работы:
ТипКомандыВызовКлиентскогоМетода в сведениях о ВПФ.&НаКлиенте.Попытка...Исключение), чтобы в случае ошибки процесс Word не оставался «висеть» в диспетчере задач.Следуя этой структуре, вы обеспечите стабильную работу печатных форм в любых вариантах развертывания 1С, будь то файловая база или мощный кластер серверов.