Перенос логики формирования печатных форм из модуля формы в модуль объекта — стандартная задача при разработке внешних печатных форм (ВПФ) для конфигураций на базе БСП (Библиотеки стандартных подсистем). Основная сложность заключается в том, что COMОбъект("Word.Application") требует наличия установленного Microsoft Word на той стороне, где выполняется код. Если код переносится в модуль объекта без учета контекста, он по умолчанию пытается выполниться на сервере, где Word зачастую не установлен.
Рассмотрим подробно, как правильно организовать этот процесс, сохранив возможность печати на стороне клиента, и разберем типичные ошибки, возникающие при переходе на новую архитектуру.
Проанализируем ситуацию, описанную в теме. Изначально код работал в модуле формы с директивой &НаКлиенте. При попытке вызвать метод модуля объекта через РеквизитФормыВЗначение("Объект"), система принудительно переходит на сервер. Тип COM-объект не является сериализуемым, его нельзя просто передать между сервером и клиентом.
Если на сервере Microsoft Word не установлен или не настроен для работы под учетной записью службы 1С, вызов Новый COMОбъект("Word.Application") вернет ошибку. Выясним причину ошибки "Значение не является значением объектного типа (Documents)": она возникает из-за того, что блок Попытка...Исключение подавляет ошибку создания объекта, но выполнение кода продолжается, и попытка обращения к свойству Documents у неопределенной переменной вызывает критический сбой.
Если ваша конфигурация использует БСП, самым правильным способом будет регистрация команды с типом ВызовКлиентскогоМетода. Это позволит коду, написанному в модуле объекта, выполняться в контексте клиентского приложения, имея доступ к локально установленному Microsoft Word.
Разберем по шагам настройку функции СведенияОВнешнейОбработке в модуле объекта:
Использование укажите значение ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода().Печать именно на клиенте.Пример заполнения регистрации команды:
Функция СведенияОВнешнейОбработке() Экспорт
ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.2.2.1");
НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
НоваяКоманда.Представление = НСтр("ru = 'Уведомление о задолженности (Word)'");
НоваяКоманда.Идентификатор = "УведомлениеОЗадолженности";
НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода();
НоваяКоманда.ПоказыватьОповещение = Истина;
Возврат ПараметрыРегистрации;
КонецФункции
При использовании типа команды ВызовКлиентскогоМетода, в модуле объекта должна присутствовать экспортная процедура Печать. Несмотря на то, что она находится в модуле объекта, при таком вызове она будет исполняться на стороне клиента. Проанализируем правильную структуру этой процедуры:
&НаКлиенте
Процедура Печать(ИдентификаторКоманды, ОбъектыНазначения) Экспорт
// Получаем данные для заполнения с сервера
ДанныеДляПечати = ПолучитьДанныеДляПечатиНаСервере(ОбъектыНазначения);
Попытка
ОбъектВорд = Новый COMОбъект("Word.Application");
Исключение
Сообщить("Не удалось запустить Microsoft Word: " + ОписаниеОшибки());
Возврат; // Обязательно выходим, чтобы не получить ошибку 'объектного типа'
КонецПопытки;
Для Каждого СсылкаИзСписка Из ОбъектыНазначения Цикл
// Логика открытия шаблона и заполнения
ШаблонПуть = "\\serv8\ftp\Шаблоны\Уведомление.docx";
ОбъектВорд.Documents.Add(ШаблонПуть);
Док = ОбъектВорд.ActiveDocument;
// Пример заполнения закладок
Попытка
Док.Bookmarks("ФИО").Select();
Док.Application.Selection.TypeText(ДанныеДляПечати[СсылкаИзСписка].ФИО);
Исключение
// Обработка отсутствия закладки
КонецПопытки;
ОбъектВорд.Visible = Истина;
КонецЦикла;
КонецПроцедуры
Обратите внимание: данные для печати (запросы к базе) лучше собирать одним серверным вызовом перед циклом, чтобы избежать многократных обращений Клиент-Сервер внутри цикла по объектам.
Рассмотрим ситуацию, когда разработчик все же решает оставить код на сервере. Это сопряжено с рядом проблем:
rphost.USR1CV8, у которого нет прав на запуск DCOM-компонентов Office и нет доступа к папкам Desktop, необходимым для инициализации Word.Если печать на сервере неизбежна (например, для формирования файлов в регламентном задании), рекомендуется отказаться от COM в пользу работы с XML структурой файла .docx через встроенные средства 1С (распаковка ZIP-архива документа) или использовать библиотеку БСП УправлениеПечатью.СформироватьПечатныеФормы().
Посмотрим на пример из сообщения №23 форума. Автор жалуется, что выводится либо первая, либо последняя строка. Это происходит из-за того, что создание объекта Word и открытие документа вынесены за пределы цикла или внутри цикла не происходит сохранение/отображение каждого нового документа.
Проанализируем правильный алгоритм массовой печати:
COMОбъект("Word.Application").Для Каждого Ссылка Из ОбъектыНазначения.ОбъектВорд.Documents.Add().ОбъектВорд.Visible = Истина), либо сохраняем его в файл и закрываем Док.Close(), чтобы не перегружать память компьютера пользователя.При использовании сетевых путей типа \\serv8\ftp\, помните, что при выполнении НаКлиенте доступ к папке проверяется для текущего пользователя Windows. При выполнении НаСервере — для пользователя, под которым запущен сервер 1С. Чтобы избежать проблем с правами, рекомендуется загружать шаблоны Word в Макеты внешней обработки. В коде извлекайте их во временный файл с помощью ПолучитьМакет() и Макет.Записать() перед открытием в Word.
Таким образом, использование механизма ВызовКлиентскогоМетода в сочетании с грамотным сбором данных на сервере позволяет эффективно перенести печать из форм в модуль объекта, сохраняя стабильность работы приложения и удобство пользователя.