Как в 1С программно выбрать лоток принтера без открытия диалога печати?

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

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

Разберем, почему стандартные средства платформы 1С и попытки подключения системной библиотеки winspool.drv через COM вызывают сложности, а также рассмотрим рабочие способы решения этой задачи.

Почему не удается подключить winspool.drv через COM-объект?

Проанализируем технические особенности операционной системы Windows и платформы 1С. Попытка инициализировать библиотеку вызовом Новый COMОбъект("winspool.drv") приводит к ошибке. Причина заключается в следующем:

  1. Библиотека winspool.drv является стандартной Win32 DLL, а не COM-сервером. У нее отсутствуют интерфейсы ActiveX/COM, ProgID и CLSID. Вызвать ее функции напрямую через COM-модель 1С невозможно.
  2. Ограничения объекта ТабличныйДокумент. В объектной модели 1С у табличного документа нет штатных свойств для явного указания лотка подачи бумаги (Paper Source / Paper Bin). Свойство ИмяПараметровПечати сохраняет настройки только после интерактивного выбора в диалоге печати.
  3. Механизм управления печатью в Windows. За выбор лотка отвечает поле dmDefaultSource структуры DEVMODE подсистемы GDI. Платформа 1С не предоставляет прямого доступа к модификации этой структуры перед отправкой документа на печать.

Рассмотрим проверенные способы обойти эти ограничения.

Решение 1. Настройка нескольких логических принтеров в ОС (рекомендуемый безкодовый метод)

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

Разберем порядок действий по шагам:

  1. Открываем панель управления Windows и переходим в раздел «Устройства и принтеры».
  2. Добавляем новый принтер, выбрав тот же порт и драйвер, что и у основного устройства.
  3. Задаем понятному экземпляру имя, например: HP_LaserJet_Tray1 и HP_LaserJet_Tray2.
  4. В свойствах каждого созданного принтера на вкладке «Параметры печати» (Printing Preferences) жестко указываем нужный лоток подачи бумаги (например, «Лоток 1» или «Лоток 2»).
  5. В коде 1С передаем имя требуемого принтера напрямую в табличный документ перед печатью.

Посмотрим на пример кода на встроенном языке 1С:


// Пример выбора принтера с предустановленным лотком
ТабДок = Новый ТабличныйДокумент;
// Заполняем табличный документ данными макета...

Если ТребуетсяПлотнаяБумага Тогда
    ТабДок.ИмяПринтера = "HP_LaserJet_Tray1";
Иначе
    ТабДок.ИмяПринтера = "HP_LaserJet_Tray2";
КонецЕсли;

// Отправляем на печать без отображения диалоговых окон
ТабДок.Напечатать(РежимИспользованияДиалогаПечати.НеИспользовать);

Преимущества метода: полная стабильность, отсутствие необходимости регистрировать внешние библиотеки, работа как в толстом, так и в тонком клиенте.

Решение 2. Разработка внешней компоненты по технологии Native API

Если требуется динамически опрашивать принтер, получать реальный список его лотков и передавать их пользователю в интерфейс 1С, потребуется создать внешнюю компоненту на C++ или Rust с использованием Native API 1С.

Выясним, как работает данный механизм на уровне Windows API:

  1. Для получения списка идентификаторов доступных лотков вызывается функция Win32 API DeviceCapabilities с флагом DC_BINS.
  2. Для получения текстовых наименований этих лотков вызывается DeviceCapabilities с флагом DC_BINNAMES.
  3. Для применения выбранного лотка компонента запрашивает структуру DEVMODE принтера через DocumentProperties, устанавливает значение поля dmDefaultSource и передает модифицированный контекст в функцию печати.

Посмотрим, как выполняется подключение такой компоненты в коде 1С без необходимости регистрации в реестре Windows через regsvr32:


// Подключение Native API компоненты из макета конфигурации
УстановитьВнешнююКомпоненту("Макет.ВнешняяКомпонентаПечати");
ПодключитьВнешнююКомпоненту("Макет.ВнешняяКомпонентаПечати", "PrinterExt", ТипВнешнейКомпоненты.Native);

КомпонентаПечати = Новый("AddIn.PrinterExt.TrayManager");
СписокЛотков = КомпонентаПечати.ПолучитьСписокЛотков("HP LaserJet Pro");

// СписокЛотков возвращает массив названий для отображения в форме 1С

Решение 3. Экспорт документа в PDF и печать через консольные утилиты

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

Разберем реализацию этого алгоритма:


// Сохраняем табличный документ во временный PDF-файл
ПутьКФайлу = ПолучитьИмяВременногоФайла("pdf");
ТабДок.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.PDF);

// Формируем команду для внешней утилиты печати с указанием лотка
ИмяПринтера = "HP LaserJet Pro";
НомерЛотка = 2;
СтрокаКоманды = СтрШаблон("PDFtoPrinter.exe ""%1"" ""%2"" tray=%3", ПутьКФайлу, ИмяПринтера, НомерЛотка);

// Запускаем процесс в фоновом режиме с ожиданием завершения
ЗапуститьПриложение(СтрокаКоманды, "", Истина);

// Удаляем временный файл
УдалитьФайлы(ПутьКФайлу);

Сравнение подходов

Подведем итог и выберем оптимальный вариант в зависимости от условий внедрения:

  1. Несколько логических принтеров — оптимальный выбор для большинства типовых задач. Не требует написания системного кода и полностью поддерживается платформой 1С.
  2. Внешняя компонента Native API — необходима в тех случаях, когда лотки должны выбираться динамически из базы данных или пользовательского интерфейса, а список оборудования постоянно меняется.
  3. Экспорт в PDF с консольной печатью — удобный вариант для серверной фоновой печати без привязки к сеансу пользователя.
← На главную