Как запустить процедуру НаКлиенте из модуля объекта и сформировать Word во внешней печатной форме?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке внешних печатных форм (ВПФ) программисты часто сталкиваются с архитектурным ограничением платформы «1С:Предприятие 8.3»: необходимо сформировать документ MS Word на стороне клиента (так как на сервере Word не установлен), но стандартный механизм печати инициируется в модуле объекта, который всегда выполняется на сервере. Попытка вызвать клиентский метод из серверного контекста или передать объект с сервера на клиент напрямую приводит к ошибкам передачи данных. Рассмотрим подробно, как правильно организовать этот процесс, используя возможности Библиотеки стандартных подсистем (БСП) и принципы разделения контекстов.

Почему возникает ошибка при передаче объекта между сервером и клиентом?

Разберем ситуацию, описанную в начале темы. Автор пытается использовать функцию РеквизитФормыВЗначение("Объект") на сервере, получает объект внешней обработки и пытается вернуть его на клиент. Проблема заключается в том, что прикладные объекты (СправочникОбъект, ДокументОбъект, ОбработкаОбъект) существуют только на сервере. Они не могут быть переданы на клиент в «чистом» виде. На клиенте мы работаем только с данными формы (ДанныеФормыСтруктура), которые являются лишь легкой проекцией объекта.

Кроме того, директива &НаКлиенте в модуле объекта не работает. Весь код модуля объекта априори считается серверным. Если вам нужно вызвать Word через COM-соединение, а Word установлен только на рабочих станциях пользователей, вам критически важно оказаться в контексте клиентской процедуры модуля формы или общего модуля с признаком «Клиент».

Решение через механизм БСП: Вызов клиентского метода

Если вы разрабатываете внешнюю печатную форму для конфигурации на базе БСП, самым правильным решением будет использование варианта запуска ВызовКлиентскогоМетода. Это позволяет системе при нажатии кнопки «Печать» обращаться не к модулю объекта, а сразу к модулю формы вашей обработки.

Рассмотрим по шагам, как это реализовать:

Шаг 1. Настройка функции СведенияОВнешнейОбработке

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


Функция СведенияОВнешнейОбработке() Экспорт
    ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.2.2.1");
    
    НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
    НоваяКоманда.Представление = "Печать в MS Word";
    НоваяКоманда.Идентификатор = "ПечатьWordНаКлиенте";
    // Важнейший момент: указываем тип запуска
    НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода();
    НоваяКоманда.ПоказыватьОповещение = Истина;
    
    Возврат ПараметрыРегистрации;
КонецФункции

Шаг 2. Создание процедуры в модуле формы

Так как мы указали ВызовКлиентскогоМетода, система будет искать в модуле формы вашей внешней обработки экспортную процедуру Печать. Важно соблюдать точную сигнатуру метода:


&НаКлиенте
Процедура Печать(ИдентификаторКоманды, ОбъектыНазначения) Экспорт
    
    // 1. Собираем данные на сервере
    ДанныеДляПечати = ПодготовитьДанныеНаСервере(ОбъектыНазначения);
    
    // 2. Получаем макет (двоичные данные) с сервера
    ДвоичныеДанныеМакета = ПолучитьМакетНаСервере();
    
    // 3. Запускаем формирование Word на клиенте
    СформироватьДокументWord(ДанныеДляПечати, ДвоичныеДанныеМакета);
    
КонецПроцедуры

Как эффективно передавать данные между сервером и клиентом?

Поскольку мы не можем передать объект, мы должны подготовить все необходимые данные для заполнения шаблона Word (реквизиты шапки, строки табличных частей) и упаковать их в универсальную структуру или массив структур. Выясним, как это выглядит на практике:


&НаСервере
Функция ПодготовитьДанныеНаСервере(ОбъектыНазначения)
    Результат = Новый Массив;
    Для Каждого СсылкаИзСписка Из ОбъектыНазначения Цикл
        СтруктураДанных = Новый Структура;
        СтруктураДанных.Вставить("Номер", СсылкаИзСписка.Номер);
        СтруктураДанных.Вставить("Дата", Формат(СсылкаИзСписка.Дата, "ДЛФ=DD"));
        СтруктураДанных.Вставить("Контрагент", СокрЛП(СсылкаИзСписка.Контрагент));
        // Добавляем другие необходимые поля...
        Результат.Добавить(СтруктураДанных);
    КонецЦикла;
    Возврат Результат;
КонецФункции

Работа с макетом и COM-объектом Word на клиенте

Когда данные и двоичные данные макета (файла .doc/.docx) получены на клиенте, мы можем приступить к генерации. Разберем пошагово алгоритм взаимодействия с MS Word:

  1. Создаем временный файл во временном каталоге пользователя и записываем туда двоичные данные макета.
  2. Инициализируем COMОбъект("Word.Application").
  3. Открываем созданный временный файл.
  4. Используем метод Find.Execute для поиска и замены параметров в тексте (например, заменяем "[НомерДокумента]" на реальное значение).
  5. Делаем приложение видимым для пользователя или сохраняем результат.

Пример клиентского кода для работы с Word:


&НаКлиенте
Процедура СформироватьДокументWord(ДанныеДляПечати, ДвоичныеДанныеМакета)
    
    Попытка
        WordApp = Новый COMОбъект("Word.Application");
    Исключение
        Сообщить("MS Word не установлен на данном компьютере!");
        Возврат;
    КонецПопытки;
    
    ИмяФайлаШаблона = ПолучитьИмяВременногоФайла("docx");
    ДвоичныеДанныеМакета.Записать(ИмяФайлаШаблона);
    
    Для Каждого ДанныеОбъекта Из ДанныеДляПечати Цикл
        Документ = WordApp.Documents.Open(ИмяФайлаШаблона);
        WordApp.Visible = Ложь;
        
        // Пример замены текста
        ReplaceText = Документ.Content.Find;
        ReplaceText.Execute("[Номер]", , , , , , , , , ДанныеОбъекта.Номер, 2);
        ReplaceText.Execute("[Дата]", , , , , , , , , ДанныеОбъекта.Дата, 2);
        
        WordApp.Visible = Истина;
        Документ.Activate();
    КонецЦикла;
    
КонецПроцедуры

Важные нюансы и безопасность

Проанализируем несколько критических моментов, которые могут помешать работе кода:

Таким образом, для запуска клиентской процедуры из внешней печатной формы мы отказываемся от прямого вызова из модуля объекта и переносим логику в модуль формы, используя штатный механизм БСП ВызовКлиентскогоМетода. Это позволяет соблюсти архитектурные требования платформы и успешно работать с локальными офисными приложениями.

← На главную