Как получить имя принтера при печати из 1С 7.7

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

В платформе 1С:Предприятие 7.7 существует давняя техническая проблема: стандартный метод Таблица.Напечатать(1) открывает системное диалоговое окно Windows, но после того как пользователь нажимает кнопку «ОК», программа не возвращает никакой информации о том, какой именно принтер был выбран. Это происходит из-за того, что структура данных PRINTDLG, используемая операционной системой, не обрабатывается встроенным языком 1С. В этой статье мы разберем несколько способов, как обойти это ограничение и программно определить целевое устройство печати.

Причина сложности реализации

Проанализируем ситуацию: когда мы вызываем окно печати, управление временно передается операционной системе. Пользователь может изменить принтер по умолчанию или выбрать сетевое устройство «на лету». Как только печать подтверждена, задание уходит в спулер Windows, а 1С получает лишь сигнал о завершении процесса, теряя контекст настроек. Поэтому нам придется использовать либо внешние компоненты, либо возможности системного администрирования Windows через COM-объекты.

Способ 1. Использование WMI для мониторинга очереди печати

Один из самых надежных способов узнать имя принтера — это «спросить» саму операционную систему о последнем созданном задании печати сразу после выполнения команды в 1С. Для этого мы можем использовать инструментарий управления Windows (WMI). Рассмотрим пример логики, которую можно адаптировать под 7.7.

Суть метода заключается в обращении к классу Win32_PrintJob. Мы можем сопоставить время отправки документа и имя пользователя, чтобы найти нужное задание в очереди. Посмотрим на пример кода, использующий WbemScripting.SWbemLocator:


// Создаем объект для доступа к WMI
Locator = СоздатьОбъект("WbemScripting.SWbemLocator");
ServicesSet = Locator.ConnectServer(".");
// Запрашиваем активные задания печати
ObjectSet = ServicesSet.ExecQuery("SELECT * FROM Win32_PrintJob");

// Перебираем задания, чтобы найти наше
СписокЗаданий = ObjectSet._NewEnum();
Пока СписокЗаданий.Следующий(Элемент) = 1 Цикл
    // Элемент.Name содержит строку вида "ИмяПринтера, НомерЗадания"
    ИмяПринтера = Элемент.Name;
    Сообщить("Документ отправлен на: " + ИмяПринтера);
КонецЦикла;

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

Способ 2. Создание собственного диалога выбора через WScript.Network

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

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

  1. Получаем список всех принтеров, подключенных к системе.
  2. Выводим их в список выбора на форме 1С или в отдельное диалоговое окно.
  3. Запоминаем выбор пользователя в переменную.
  4. Программно назначаем выбранный принтер и отправляем документ на печать без вывода лишних диалогов.

Пример получения списка принтеров:


WshNetwork = СоздатьОбъект("WScript.Network");
Printers = WshNetwork.EnumPrinterConnections();
Для i = 0 По Printers.Count() - 1 Шаг 2 Цикл
    // Printers.Item(i) - порт, Printers.Item(i+1) - имя принтера
    ИмяПринтера = Printers.Item(i+1);
    СписокПринтеров.ДобавитьЗначение(ИмяПринтера);
КонецЦикла;

Способ 3. Использование внешней компоненты FormEx или 1С++

Если в вашей конфигурации используются расширения FormEx или 1С++, задача значительно упрощается. Эти компоненты предоставляют доступ к низкоуровневым функциям Windows API. В частности, через них можно вызвать функцию EnumPrinters или перехватить события принтера.

Проанализируем возможности FormEx: данная компонента позволяет управлять параметрами печати более гибко. С её помощью можно заранее определить «принтер по умолчанию» для конкретной формы документа. Если вы жестко задаете принтер через Сервис.Принтер (в контексте FormEx), то вы всегда будете точно знать, куда ушел документ, так как выбор контролируется кодом.

Способ 4. Анализ системного реестра

1С 7.7 сохраняет настройки печати для каждого пользователя и каждого вида отчета в реестре Windows. Путь к ветке выглядит следующим образом: HKEY_CURRENT_USER\Software\1C\1Cv7\7.7\<ИмяБазы>\V7\<ИмяПользователя>\Selection.

Внутри этой ветки создаются подразделы для печатных форм. Параметр DefaultPrinter хранит имя принтера, который использовался в последний раз. Рассмотрим алгоритм работы с этим методом:

Обратите внимание: этот метод имеет задержку, так как 1С не всегда мгновенно записывает данные в реестр в процессе работы сессии, часто это происходит только при закрытии объекта или программы.

Способ 5. Отслеживание через журнал PrintService

В современных операционных системах Windows (7, 10, 11) существует встроенный журнал событий PrintService. При каждой успешной отправке документа на печать фиксируется событие с ID 307. В тексте этого события содержится полная информация: имя документа, имя пользователя и, самое главное, имя принтера.

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

Рекомендация по выбору решения

Выясним, какой метод лучше выбрать в зависимости от задачи:

  1. Если вам нужно просто логировать, кто и куда печатает — используйте WMI или Журнал событий Windows.
  2. Если вам нужно гарантировать, что документ уйдет на конкретный принтер (например, чековый или этикеточный) — используйте WScript.Network для создания собственного выбора принтера и метод ОпцииПечати().
  3. Для глубокой интеграции и работы в терминальном режиме лучше всего подходят внешние компоненты типа 1С++.

При использовании любого из методов помните о сетевых принтерах и принт-серверах: их имена в системе могут содержать полные сетевые пути (например, \\Server\HP_LaserJet), что нужно учитывать при строковом сравнении в коде.

← На главную