Почему зависает печать PDF при вызове из веб-сервиса 1С и как это исправить?

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

При реализации интеграционных механизмов в 1С:Предприятии нередко возникает задача автоматической отправки внешних файлов (например, накладных, этикеток или актов в формате PDF) на физический принтер прямо из веб-сервиса или HTTP-сервиса. Однако разработчики часто сталкиваются с ситуацией, когда при интерактивном тестировании в сеансе пользователя печать проходит успешно, а при вызове через веб-сервис выполнение потока намертво зависает.

Разберем причины такого поведения платформы и операционной системы, а также рассмотрим по шагам, как настроить надежную печать документов из серверного контекста.

Анализ проблемы: почему зависает метод ЗапуститьПриложение

Посмотрим на типовой пример кода, с помощью которого разработчики пытаются отправить PDF на печать через вызов стороннего ридера:


ЗапуститьПриложение("""C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe"" /N /T ""E:\TEMP\123.pdf"" HPIT",,ИСТИНА);

При выполнении этого кода из контекста веб-сервиса возникают две ключевые проблемы, приводящие к блокировке потока:

  1. Некорректная контекстная компиляция общего модуля: если процедура запуска находится в общем модуле, у которого одновременно выставлены флаги Клиент (управляемое приложение), Сервер и Внешнее соединение, то веб-сервис при инициализации окружения может некорректно обрабатывать контекст вызова платформенных методов.
  2. Особенности работы внешних программ в Session 0 (изоляция сессий Windows): веб-сервисы выполняются рабочими процессами сервера 1С (rphost), работающими от имени системной службы в неинтерактивной нулевой сессии. Adobe Acrobat Reader при запуске с флагом /T отправляет задание в спулер печати, но зачастую не завершает свой процесс самостоятельно, продолжая ожидать пользовательского ввода или оставаясь в памяти. Параметр ожидания ДождатьсяЗавершения = Истина заставляет сервер 1С бесконечно ждать завершения процесса, которого не происходит.

Шаг 1. Корректная настройка свойств общего модуля

Выясним, как правильно разместить логику отправки на печать внутри конфигурации:

  1. Создадим отдельный общий модуль (например, ПечатьСервер) или откроем существующий служебный модуль.
  2. В свойствах модуля снимем флаги Клиент (управляемое приложение) и Клиент (обычное приложение).
  3. Оставим установленным только флаг Сервер (при необходимости также Вызов сервера, если модуль планируется вызывать из клиентского контекста).

Изоляция чисто серверного кода гарантирует, что при обращении веб-сервиса к процедурам модуля платформа не будет пытаться инициализировать клиентские зависимости и синтаксические контексты.

Шаг 2. Проверка доступности принтера на сервере

Служба сервера 1С запускается под специальной сервисной учетной записью (по умолчанию usr1cv8). Сетевые принтеры, подключенные в профиле конкретного пользователя Windows, служба сервера 1С не увидит. Принтер должен быть либо установлен локально через TCP/IP-порт, либо доступен для всех пользователей системы.

Рассмотрим функцию на 1С, которая с помощью интерфейса WMI позволяет проверить наличие необходимого принтера в операционной системе перед отправкой файла на печать:


Функция ПринтерНайден(ИмяПринтера)
    Попытка
        Locator = Новый COMОбъект("WbemScripting.SWbemLocator");
        Сервисы = Locator.ConnectServer(".");
        Объекты = Сервисы.InstancesOf("Win32_Printer");
        
        Для Каждого Принтер Из Объекты Цикл
            Если ВРег(СокрЛП(ИмяПринтера)) = ВРег(СокрЛП(Принтер.Name)) Тогда
                Возврат Истина;            
            КонецЕсли;
        КонецЦикла;
        
        Возврат Ложь;
    Исключение
        Возврат Ложь;
    КонецПопытки;
КонецФункции

Шаг 3. Использование специализированных утилит для тихой серверной печати

Использование Adobe Reader для серверной печати крайне не рекомендуется из-за диалоговых окон, песочницы (Protected Mode) и зависания процессов. Для надежной работы из фоновых заданий и веб-сервисов лучше применять консольные утилиты, предназначенные для автоматической фоновой печати.

Вариант 1. Печать через SumatraPDF

SumatraPDF корректно отрабатывает в фоновом режиме и завершает процесс сразу после передачи файла в очередь печати:


ПутьКУтилите = "C:\Tools\SumatraPDF\SumatraPDF.exe";
ПутьКФайлу  = "E:\TEMP\123.pdf";
ИмяПринтера = "HPIT";

Команда = СтрШаблон("""%1"" -print-to ""%2"" -silent ""%3""", ПутьКУтилите, ИмяПринтера, ПутьКФайлу);
ЗапуститьПриложение(Команда, , Истина);

Вариант 2. Печать через PDFtoPrinter

Специализированная утилита PDFtoPrinter не требует графического интерфейса и специально оптимизирована для скриптовой печати на сетевые и локальные принтеры Windows:


ПутьКУтилите = "C:\Tools\PDFtoPrinter.exe";
ПутьКФайлу  = "E:\TEMP\123.pdf";
ИмяПринтера = "HPIT";

Команда = СтрШаблон("""%1"" ""%2"" ""%3""", ПутьКУтилите, ПутьКФайлу, ИмяПринтера);
ЗапуститьПриложение(Команда, , Истина);

Вариант 3. Печать через Ghostscript

Если требуется полный контроль над драйвером Windows и параметрами страницы, можно использовать Ghostscript:


ПутьКУтилите = "C:\Program Files\gs\gs10.00.0\bin\gswin64c.exe";
ПутьКФайлу  = "E:\TEMP\123.pdf";
ИмяПринтера = "HPIT";

ПараметрыПечати = "-dPrinted -dBATCH -dNOPAUSE -dNOSAFER -q -sDEVICE=mswinpr2";
Команда = СтрШаблон("""%1"" %2 -sOutputFile=""%%printer%%%3"" ""%4""", ПутьКУтилите, ПараметрыПечати, ИмяПринтера, ПутьКФайлу);
ЗапуститьПриложение(Команда, , Истина);

Альтернатива: штатная прямая печать из 1С

Если документ формируется непосредственно средствами конфигурации 1С в виде объекта ТабличныйДокумент, сторонние утилиты не требуются. Печать можно выполнить стандартным серверным методом без вызова внешних приложений:


ТабДок = Новый ТабличныйДокумент;
// ... заполнение табличного документа ...

ТабДок.ИмяПринтера = "HPIT";
ТабДок.Напечатать(РежимИспользованияДиалогаПечати.НеИспользовать);

Важно: для работы метода ТабличныйДокумент.Напечатать на сервере принтер также должен быть доступен под учетной записью службы сервера 1С.

← На главную