При реализации интеграционных механизмов в 1С:Предприятии нередко возникает задача автоматической отправки внешних файлов (например, накладных, этикеток или актов в формате PDF) на физический принтер прямо из веб-сервиса или HTTP-сервиса. Однако разработчики часто сталкиваются с ситуацией, когда при интерактивном тестировании в сеансе пользователя печать проходит успешно, а при вызове через веб-сервис выполнение потока намертво зависает.
Разберем причины такого поведения платформы и операционной системы, а также рассмотрим по шагам, как настроить надежную печать документов из серверного контекста.
Посмотрим на типовой пример кода, с помощью которого разработчики пытаются отправить PDF на печать через вызов стороннего ридера:
ЗапуститьПриложение("""C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe"" /N /T ""E:\TEMP\123.pdf"" HPIT",,ИСТИНА);
При выполнении этого кода из контекста веб-сервиса возникают две ключевые проблемы, приводящие к блокировке потока:
rphost), работающими от имени системной службы в неинтерактивной нулевой сессии. Adobe Acrobat Reader при запуске с флагом /T отправляет задание в спулер печати, но зачастую не завершает свой процесс самостоятельно, продолжая ожидать пользовательского ввода или оставаясь в памяти. Параметр ожидания ДождатьсяЗавершения = Истина заставляет сервер 1С бесконечно ждать завершения процесса, которого не происходит.Выясним, как правильно разместить логику отправки на печать внутри конфигурации:
ПечатьСервер) или откроем существующий служебный модуль.Изоляция чисто серверного кода гарантирует, что при обращении веб-сервиса к процедурам модуля платформа не будет пытаться инициализировать клиентские зависимости и синтаксические контексты.
Служба сервера 1С запускается под специальной сервисной учетной записью (по умолчанию usr1cv8). Сетевые принтеры, подключенные в профиле конкретного пользователя Windows, служба сервера 1С не увидит. Принтер должен быть либо установлен локально через TCP/IP-порт, либо доступен для всех пользователей системы.
Рассмотрим функцию на 1С, которая с помощью интерфейса WMI позволяет проверить наличие необходимого принтера в операционной системе перед отправкой файла на печать:
Функция ПринтерНайден(ИмяПринтера)
Попытка
Locator = Новый COMОбъект("WbemScripting.SWbemLocator");
Сервисы = Locator.ConnectServer(".");
Объекты = Сервисы.InstancesOf("Win32_Printer");
Для Каждого Принтер Из Объекты Цикл
Если ВРег(СокрЛП(ИмяПринтера)) = ВРег(СокрЛП(Принтер.Name)) Тогда
Возврат Истина;
КонецЕсли;
КонецЦикла;
Возврат Ложь;
Исключение
Возврат Ложь;
КонецПопытки;
КонецФункции
Использование 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С в виде объекта ТабличныйДокумент, сторонние утилиты не требуются. Печать можно выполнить стандартным серверным методом без вызова внешних приложений:
ТабДок = Новый ТабличныйДокумент;
// ... заполнение табличного документа ...
ТабДок.ИмяПринтера = "HPIT";
ТабДок.Напечатать(РежимИспользованияДиалогаПечати.НеИспользовать);
Важно: для работы метода ТабличныйДокумент.Напечатать на сервере принтер также должен быть доступен под учетной записью службы сервера 1С.