Как организовать печать PDF со стороны сервера 1С: проблемы Session 0 и рабочие решения

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

В этой статье мы подробно разберем одну из самых неочевидных и сложных задач при разработке на платформе 1С: Предприятие — печать документов непосредственно с сервера. Мы проанализируем реальную ситуацию, когда мобильное приложение отправляет POST-запрос в 1С, и сервер должен обработать двоичные данные и распечатать PDF-файл (например, чек или этикетку) на сетевом принтере (в данном случае Brother QL-810W).

Мы рассмотрим, почему стандартные методы, работающие на клиенте, отказывают на сервере, разберем причины возникновения ошибок при использовании COM-объектов и предложим несколько проверенных архитектурных решений.

Суть проблемы: Почему не печатает сервер?

Многие разработчики сталкиваются с ситуацией, описанной автором: код, который идеально работает при запуске из клиентского приложения (Толстый или Тонкий клиент), перестает работать при переносе в серверный модуль, HTTP-сервис или регламентное задание.

Давайте проанализируем код, который использовал автор, пытаясь запустить Adobe Acrobat через COM-объект WScript.Shell:


ИмяПринтера = """Brother QL-810W"""; 
WshShell = Новый COMОбъект("WScript.Shell"); 
ПутьAdobeReader = WshShell.RegRead("HKCR\Software\Adobe\Acrobat\Exe\"); 
Shell = Новый COMОбъект("Shell.Application"); 
Shell.ShellExecute(ВремФайл, "", "", "print", 0); 

Почему это не работает на сервере?

Сервер 1С:Предприятия запускается как служба Windows. Начиная с Windows Vista / Server 2008, службы работают в так называемой Сессии 0 (Session 0). Эта сессия полностью изолирована от пользовательского интерфейса.

  1. Изоляция интерфейса: Программы вроде Adobe Acrobat или MS Word, запускаемые через OLE/COM, часто пытаются инициализировать графический интерфейс (даже если вы его скрываете). В Сессии 0 это запрещено, что приводит к зависанию процесса или ошибке.
  2. Отсутствие профиля: Служба сервера 1С (обычно запускаемая под пользователем USR1CV8) может не иметь доступа к установленным принтерам, так как они часто устанавливаются в профиль конкретного пользователя, а не глобально для системы.

Рассмотрим рабочие методы решения этой задачи, от простых к профессиональным.

Решение 1: Использование "Робота" (Выделенный клиентский сеанс)

Один из самых надежных способов, упомянутых в обсуждении, — отказ от печати непосредственно сервером 1С. Вместо этого мы используем схему с промежуточной очередью, задействовав конвейер обработки задач.

Как это работает:

  1. На сервере (в HTTP-сервисе) мы не печатаем документ, а сохраняем его или создаем запись в специальном регистре сведений (или используем интеграцию с Kafka или RabbitMQ).
  2. На компьютере, к которому подключен принтер (или на сервере, где залогинен служебный пользователь), запускается отдельный сеанс 1С.
  3. В этом сеансе запущена обработка с подключенным Обработчиком Ожидания.
  4. Обработка раз в несколько секунд проверяет регистр ОчередьПечати. Если есть новые задания — она забирает их и печатает стандартным методом ТабличныйДокумент.Напечатать() или через локальные приложения.

Плюсы метода:

Решение 2: Печать через командную строку (Без COM-объектов)

Если архитектура требует печати именно с сервера без участия запущенных клиентских сеансов, нам необходимо использовать программное обеспечение, поддерживающее работу в режиме командной строки (CLI) без вызова графического интерфейса.

Важно: Adobe Acrobat Reader плохо подходит для серверной печати, так как он тяжеловесный и склонен "зависать" в памяти в сессии службы. Рассмотрим альтернативы.

Вариант А: Использование Foxit Reader

В обсуждении справедливо заметили, что Foxit Reader стабильнее. Для печати можно использовать метод ЗапуститьПриложение. Обратите внимание, мы не используем COMОбъект, мы просто запускаем команду.


// Примерная команда для Foxit Reader
// /t    
Команда = """C:\Path\To\FoxitReader.exe"" /t """ + ПутьКФайлуPDF + """ """ + ИмяПринтера + """";
ЗапуститьПриложение(Команда, , Истина); // Истина = ждать завершения

Вариант Б: Использование GhostScript (GS)

Это наиболее профессиональное решение для Windows-серверов. GhostScript — это интерпретатор PostScript и PDF, который не имеет GUI и идеально подходит для фоновых задач. Он позволяет растрировать PDF и отправлять его прямо в спулер печати Windows.

Пример кода 1С для запуска GhostScript:


// Путь к исполняемому файлу gswin64c.exe
ПутьGS = "C:\Program Files\gs\gs9.53.3\bin\gswin64c.exe";

// Параметры для печати на конкретный принтер Windows
// -sDEVICE=mswinpr2 — использование драйвера принтера Windows
// -sOutputFile="%printer%Имя_Принтера" — указание принтера
Параметры = " -dPrinted -dBATCH -dNOPAUSE -dNOSAFER -q -dNumCopies=1 -sDEVICE=mswinpr2 -sOutputFile=""%printer%" + ИмяПринтера + """ """ + ПутьКФайлуPDF + """";

ЗапуститьПриложение(ПутьGS + Параметры, , Истина);

Этот метод решает проблему "зависания" процессов, так как GS отрабатывает и сразу закрывается.

Решение 3: Скрипт мониторинга папки (Folder Watcher)

Автор темы предложил вариант с использованием VBScript, который "слушает" папку. Это рабочий вариант, если вы не хотите давать права пользователю USR1CV8 на принтеры.

Алгоритм действий:

  1. Сервер 1С сохраняет PDF файл в специальную папку (например, G:\NEO\doc_print\).
  2. Независимый скрипт (VBS, PowerShell или Python), запущенный в сеансе пользователя (не службы!), сканирует эту папку.
  3. При появлении файла скрипт отправляет его на печать и затем удаляет (или перемещает в архив).

Давайте посмотрим на скрипт, приведенный автором, и улучшим понимание его работы. Скрипт использует Shell.Application для вызова команды контекстного меню "Print".


' VBScript для мониторинга папки
Set wssh = CreateObject("WScript.Shell")
Set objFS = CreateObject("Scripting.FileSystemObject")
Set objPath = objFS.GetFolder("G:\NEO\doc_print\") 

Do 
    PrintDelInFolder objPath 
    WScript.Sleep 1000 ' Пауза 1 секунда
Loop

Sub PrintDelInFolder(objFolder)
    For Each objItem In objFolder.Files
        ' Проверяем расширение PDF
        If StrComp(objFS.GetExtensionName(objItem.Name), ".pdf", vbTextCompare) = 0 Then
            ' Отправка на печать через Shell.Execute (InvokeVerb "print")
            Set objShell = CreateObject("Shell.Application")
            ' Важно: это сработает только если для PDF назначена программа по умолчанию, умеющая печатать
            objShell.ShellExecute objItem.Path, "", "", "print", 0 
            
            ' Пауза, чтобы файл успел уйти в спулер перед удалением
            WScript.Sleep 5000 
            objFS.DeleteFile objItem.Path, true
        End If
    Next
End Sub

Недостаток этого метода: Трудно управлять выбором принтера. Команда print обычно отправляет файл на принтер, установленный в системе "по умолчанию". Для термопринтера Brother это может быть критично, если на сервере есть и другие принтеры.

Особенности работы с термопринтерами (Brother QL-810W)

В теме упоминается специфический принтер — Brother QL-810W. Это принтер этикеток. При печати PDF на таких устройствах часто возникают проблемы с масштабированием (драйвер пытается вписать лист А4 в размер этикетки 62мм).

Рекомендации для настройки:

  1. Убедитесь, что в настройках 1С ТабличныйДокумент имеет правильные поля и размер страницы, соответствующий размеру этикетки.
  2. Если вы используете GhostScript или Foxit, в настройках принтера в Windows (под пользователем, от которого идет печать) должны быть жестко заданы размеры бумаги по умолчанию.
  3. Рассмотрите вариант сохранения табличного документа не в PDF, а в картинку (JPG/PNG). Многие термопринтеры печатают картинки корректнее и быстрее, чем PDF через сложные драйверы.

Решение 4: Linux и CUPS (Для справки)

В обсуждении также упоминался вариант использования отдельного сервера на Linux (Debian) с системой печати CUPS. Скрипт на сервере Linux принимает файл и выполняет команду lpr -P printer_name file.pdf. Это очень надежное решение для высоконагруженных систем ("фабрик печати"), но оно требует администрирования дополнительной ОС.

Итог

Для стабильной печати с сервера 1С рекомендуем:

  1. Избегать COM-объектов (Word, Excel, Acrobat) в серверном коде из-за изоляции сессий.
  2. Использовать утилиты командной строки: GhostScript (предпочтительно) или специализированные легкие PDF-принтеры (PDFtoPrinter).
  3. Если важна визуальная точность и работа с драйверами торгового оборудования — использовать схему с отдельным клиентским сеансом-роботом, который забирает задачи из очереди.
← На главную