При работе с системой 1С часто возникает задача автоматической печати готовых PDF-файлов, хранящихся, например, в информационной базе — для этого пригодится массовая выгрузка файлов из 1С на диск. Эта задача сопряжена с рядом вызовов: как печатать без открытия лишних окон, как гарантировать завершение процессов (используя конвейер обработки задач), как обеспечить универсальность решения и как контролировать параметры печати, такие как количество копий или масштаб. В данном материале мы рассмотрим различные подходы к решению этой проблемы, основываясь на опыте разработчиков 1С.
Adobe Acrobat Reader является одним из наиболее распространенных бесплатных средств для просмотра и печати PDF. Существует два основных способа взаимодействия с ним из 1С: через командную строку и через COM-объект.
AcroRd32.exe)Самый простой способ отправить PDF на печать — это запустить исполняемый файл Adobe Reader с определенными параметрами (используя подключаемые команды БСП) — для этой задачи есть обработка для пакетной печати PDF-комплектов. Для этого используется функция ЗапуститьПриложение. Основные параметры, которые нас интересуют:
/N: Открывает новый экземпляр Adobe Reader./T "ИмяФайла.pdf" "ИмяПринтера" "ИмяДрайвераПринтера" "ПортПринтера": Печатает указанный файл на заданном принтере и завершает работу Reader. В большинстве случаев достаточно указать только путь к файлу и имя принтера.Пример базовой команды:
ЗапуститьПриложение("C:\Program Files\Adobe\Reader 10.0\Reader\AcroRd32.exe /N /T " + ИмяФайла);
Возможные проблемы и их решения:
AcroRd32.exe: Жестко заданный путь (например, C:\Program Files\Adobe\Reader 10.0\Reader\AcroRd32.exe) может отличаться в разных системах (разные версии Reader, x86/x64 системы).
Решение: Получайте путь к исполняемому файлу из реестра Windows. Для этого можно использовать объект WScript.Shell:
WshShell = Новый COMОбъект("WScript.Shell");
ПутьAdobeReader = WshShell.RegRead("HKCR\Software\Adobe\Acrobat\Exe\");
Если Не ЗначениеЗаполнено(ПутьAdobeReader) Тогда
Сообщить("Не найдена программа Adobe Reader! Печать pdf-файлов невозможна.", СтатусСообщения.Важное);
Возврат;
КонецЕсли;
AcroRd32.exe может оставаться висеть в памяти или оставлять открытое, но невидимое окно.
Решение: Принудительно завершайте процесс после печати с помощью команды taskkill. Для этого нам нужно получить имя исполняемого файла:
// ... (код для запуска печати) ...
// Получаем имя процесса для завершения
ИмяПроцессаРидера = ПутьAdobeReader;
НомерСимвола = Найти(ИмяПроцессаРидера, "\");
Пока НомерСимвола > 0 Цикл
ИмяПроцессаРидера = Сред(ИмяПроцессаРидера, НомерСимвола + 1);
НомерСимвола = Найти(ИмяПроцессаРидера, "\");
КонецЦикла;
// Убиваем процесс
WshShell.Run("taskkill /f /im " + ИмяПроцессаРидера, 0);
Решение: Вставляйте обязательную задержку после каждой команды печати (в это время поможет индикация прогресса выполнения), особенно при работе с временными файлами или в пакетном режиме. Рекомендуется задержка от 3 до 5 секунд.
// ... (после WshShell.Run) ...
ТекущееВремя = ТекущаяДата;
Пока ТекущаяДата < ТекущееВремя + 5 Цикл // 5 секунд задержки
ОбработкаПрерыванияПользователя(); // Позволяет системе не зависать
КонецЦикла;
// ... (далее можно удалять файл или запускать следующее задание) ...
/T с именем принтера (например, /T "путь\к\файлу.pdf" "Мой Принтер") могут возникать ошибки, если имя принтера содержит пробелы, специальные символы или слишком длинное. Для сетевых принтеров имя должно включать сервер (например, \\SERVER\PRINTER_NAME).
Решение: Используйте короткие имена принтеров без пробелов и спецсимволов. Для сетевых принтеров указывайте полный путь с именем сервера.
AcroRd32.exe не позволяет напрямую управлять количеством копий, диапазоном страниц или масштабом.
Решение: Для этих целей приходится либо запускать команду несколько раз (для количества копий), либо использовать более сложные механизмы (например, COM-объекты, если они предоставляют такой функционал, или виртуальные принтеры) — есть готовая обработка формирования PDF-комплектов с логотипом.
Комплексное решение для печати через командную строку Adobe Reader:
// Процедура выполняет попытку напечатать pdf-файлы из списка в фоновом режиме без участия пользователя
// Параметры:
// МассивФайлов - массив элементов типа "Файл", либо массив структур с ключами "ПолноеИмя" и "Имя"
// ИмяПринтера - имя принтера, на который необходимо отправить задание
Процедура ФоноваяПечатьPDFФайлов(МассивФайлов, ИмяПринтера = "") Экспорт
WshShell = Новый COMОбъект("WScript.Shell");
ПутьAdobeReader = WshShell.RegRead("HKCR\Software\Adobe\Acrobat\Exe\");
Если Не ЗначениеЗаполнено(ПутьAdobeReader) Тогда
Сообщить("Не найдена программа Adobe Reader! Печать pdf-файлов невозможна.", СтатусСообщения.Важное);
Возврат;
КонецЕсли;
Для Каждого Файл Из МассивФайлов Цикл
// Запускаем печать
WshShell.Run(ПутьAdobeReader + " /N /T " + """" + Файл.ПолноеИмя + """" + ?(ЗначениеЗаполнено(ИмяПринтера), " " + """" + ИмяПринтера + """", ""), 0);
// Обязательная задержка для корректной обработки печати
// 3-5 секунд обычно достаточно, но может варьироваться
ТекущееВремя = ТекущаяДата;
Пока ТекущаяДата < ТекущееВремя + 5 Цикл
ОбработкаПрерыванияПользователя();
КонецЦикла;
КонецЦикла;
// Получаем имя процесса для завершения
ИмяПроцессаРидера = ПутьAdobeReader;
НомерСимвола = Найти(ИмяПроцессаРидера, "\");
Пока НомерСимвола > 0 Цикл
ИмяПроцессаРидера = Сред(ИмяПроцессаРидера, НомерСимвола + 1);
НомерСимвола = Найти(ИмяПроцессаРидера, "\");
КонецЦикла;
// Убиваем процесс. Это может завершить все открытые экземпляры AcroRd32.exe.
WshShell.Run("taskkill /f /im " + ИмяПроцессаРидера, 0);
КонецПроцедуры
AcroPDF.PDF.1COM-объект AcroPDF.PDF.1 предоставляет программный доступ к функционалу Adobe Reader (или Acrobat Pro). Хотя изначально он часто ассоциируется с Adobe Acrobat Professional, его базовые функции могут быть доступны и через Reader.
Пример использования:
Попытка
Acrobat = Новый COMОбъект("AcroPDF.PDF.1");
Исключение
Сообщить("Не удалось создать COMОбъект AcroPDF.PDF.1. Убедитесь, что Adobe Reader/Acrobat установлен корректно.", СтатусСообщения.Важное);
Возврат;
КонецПопытки;
Acrobat.Visible = false; // Делаем окно невидимым
Acrobat.LoadFile(ПутьКPDFФайлу); // Загружаем PDF-файл
Acrobat.printAll; // Печатает весь документ на принтер по умолчанию
// Или Acrobat.printWithDialog; // Открывает диалог печати для пользователя
// Обязательная задержка, если файл временный и будет удален
ТекущееВремя = ТекущаяДата;
Пока ТекущаяДата < ТекущееВремя + 5 Цикл
ОбработкаПрерыванияПользователя();
КонецЦикла;
Acrobat.CloseAllDocs; // Закрывает все открытые документы в объекте
Acrobat.Exit; // Завершает работу COM-объекта и связанные процессы
Acrobat = Неопределено; // Освобождаем объект COM
Возможные проблемы и их решения:
CloseAllDocs и Exit, процесс Reader может остаться в памяти.
Решение: Дополнительно можно использовать taskkill, как описано выше для командной строки. Однако, при правильном использовании CloseAllDocs и Exit эта проблема возникает реже.
Решение: Тестируйте функционал с установленной версией Adobe Reader. Если требуется более тонкий контроль (количество копий, диапазон страниц), возможно, придется искать другие решения.
Shell.ApplicationОбъект Shell.Application предоставляет доступ к функциям оболочки Windows и является универсальным способом взаимодействия с файлами, используя системные ассоциации. Это означает, что 1С не привязывается к конкретному приложению (например, Adobe Reader), а просто просит операционную систему распечатать файл, используя программу, назначенную для PDF по умолчанию.
InvokeVerbEx("Print")Этот метод подходит для пакетной печати файлов из определенной папки.
Пример использования:
ПапкаСPDF = "C:\МоиДокументы\PDF_для_печати"; // Укажите путь к папке с PDF файлами
Попытка
Shell = Новый COMОбъект("Shell.Application");
Исключение
Сообщить("Не удалось создать COMОбъект Shell.Application.", СтатусСообщения.Важное);
Возврат;
КонецПопытки;
Folder = Shell.Namespace(ПапкаСPDF);
Если Folder = Неопределено Тогда
Сообщить("Указанная папка не найдена: " + ПапкаСPDF, СтатусСообщения.Важное);
Возврат;
КонецЕсли;
colItems = Folder.Items;
Для Каждого Эл Из colItems Цикл
Если СтрНайти(Эл.Name, ".pdf") > 0 Тогда // Проверяем, что это PDF-файл
Эл.InvokeVerbEx("Print");
// Обязательная задержка для корректной обработки печати
ТекущееВремя = ТекущаяДата;
Пока ТекущаяДата < ТекущееВремя + 3 Цикл // 3 секунды задержки
ОбработкаПрерыванияПользователя();
КонецЦикла;
КонецЕсли;
КонецЦикла;
Shell = Неопределено; // Освобождаем объект COM
ShellExecute("print", 0)Этот метод более универсален, так как позволяет напечатать любой файл, для которого в системе зарегистрирован обработчик печати. Параметр 0 в конце указывает на скрытый запуск, что помогает избежать открытия видимых окон.
Пример использования:
Shell = Новый COMОбъект("Shell.Application");
Shell.ShellExecute("D:\1C82\test.pdf", "", "", "print", 0);
// Обязательная задержка после отправки на печать
ТекущееВремя = ТекущаяДата;
Пока ТекущаяДата < ТекущееВремя + 3 Цикл // 3 секунды задержки
ОбработкаПрерыванияПользователя();
КонецЦикла;
Shell = Неопределено; // Освобождаем объект COM
Пакетная печать с ShellExecute:
// Предполагается, что у вас есть функция для поиска PDF-файлов
// Например:
// Функция НайтиФайлы(ПутьКПапке, МаскаФайла, ВключатьВложенныеПапки)
// ... реализуйте поиск файлов ...
// Возврат МассивПолныхПутейКФайлам;
// КонецФункции
Процедура ФоноваяПечатьPDFФайловПросмотрщиком(МассивФайлов) Экспорт
Попытка
Shell = Новый COMОбъект("Shell.Application");
Исключение
Сообщить("Не удалось создать COMОбъект Shell.Application.", СтатусСообщения.Важное);
Возврат;
КонецПопытки;
Для Каждого Файл Из МассивФайлов Цикл
// Передаем полный путь к файлу
Shell.ShellExecute(Файл.ПолноеИмя, "", "", "print", 0);
// Обязательная задержка для избежания проблем с печатью и удалением
ТекущееВремя = ТекущаяДата;
Пока ТекущаяДата < ТекущееВремя + 3 Цикл // 3 секунды задержки
ОбработкаПрерыванияПользователя();
КонецЦикла;
КонецЦикла;
Shell = Неопределено; // Освобождаем объект COM
КонецПроцедуры
Общие недостатки методов Shell.Application:
Виртуальные PDF-принтеры, такие как Bullzip PDF Printer, PDFCreator или bioPDF, изначально созданы для *генерации* PDF-файлов из любых печатаемых документов. Однако многие из них предоставляют COM-интерфейсы, которые позволяют программно управлять их настройками и даже направлять вывод на физический принтер. Для пакетного вывода печатных форм и их экспорта можно использовать обработку для групповой печати документов и сохранения их на диск.
Преимущества:
Недостатки:
Target="printer"), их использование для *печати готовых PDF* может быть менее прямым, чем для *генерации PDF из документов 1С*. Однако, если требуется тонкий контроль над печатью (масштаб, ориентация, количество копий), эти инструменты могут предложить больше возможностей, чем стандартные методы.
Следующий код показывает, как использовать Bullzip для создания PDF из табличного документа 1С. После создания PDF, его можно распечатать любым из описанных выше способов или настроить Bullzip на прямую печать после генерации.
// Упрощенная процедура для формирования ПДФ из табличного документа 1С
// и его последующей печати (через настройки Bullzip или внешне)
Процедура ПолучитьИНапечататьФайлПДФ(ТабДокумент, ИмяФайлаВывода, ИмяФизическогоПринтера = "") Экспорт
Попытка
принтер=Новый ComObject("Bullzip.PDFPrinterSettings");
Исключение
Сообщить("Не удалось подключиться к Bullzip PDF Printer. Убедитесь, что он установлен.", СтатусСообщения.Важное);
Возврат;
КонецПопытки;
принтер.SetValue("output", ИмяФайлаВывода); // Куда сохранять PDF
принтер.SetValue("ShowSaveAS", "never");
принтер.SetValue("ShowProgress", "no");
принтер.SetValue("ShowProgressFinished", "no");
принтер.SetValue("ShowSettings", "never");
принтер.SetValue("ShowPDF", "no");
принтер.SetValue("ConfirmOverwrite","no");
принтер.SetValue("OwnerPassword","Pass4PDF"); // Пример пароля для владельца
принтер.SetValue("Permissions",61636); // Пример разрешений
// Если нужно сразу отправить на физический принтер:
Если ЗначениеЗаполнено(ИмяФизическогоПринтера) Тогда
принтер.SetValue("Target", "printer");
принтер.SetValue("PrinterName", ИмяФизическогоПринтера);
Иначе
принтер.SetValue("Target", "file"); // По умолчанию сохраняем в файл
КонецЕсли;
принтер.WriteSettings; // Применяем настройки
ТабДокумент.Автомасштаб = Истина;
ТабДокумент.ИмяПринтера = "Bullzip PDF Printer"; // Отправляем на виртуальный принтер
// Если мы сохраняем в файл, ждем его появления
Если Не ЗначениеЗаполнено(ИмяФизическогоПринтера) Тогда
PDFФайл = Новый Файл(ИмяФайлаВывода);
Если НЕ PDFФайл.Существует Тогда
ТабДокумент.Напечатать(Истина);
// Ждем, пока PDF-файл будет создан
Пока НЕ PDFФайл.Существует Цикл
ОбработкаПрерыванияПользователя;
ТекущееВремя = ТекущаяДата;
Пока ТекущаяДата < ТекущееВремя + 1 Цикл // Небольшая задержка
ОбработкаПрерыванияПользователя();
КонецЦикла;
КонецЦикла;
КонецЕсли;
Иначе // Если сразу печатаем на физический принтер
ТабДокумент.Напечатать(Истина);
// Дополнительная задержка для отправки на физический принтер
ТекущееВремя = ТекущаяДата;
Пока ТекущаяДата < ТекущееВремя + 5 Цикл
ОбработкаПрерыванияПользователя();
КонецЦикла;
КонецЕсли;
КонецПроцедуры
bioPDF — еще один бесплатный виртуальный принтер с COM-интерфейсом. Этот пример демонстрирует генерацию PDF из табличного документа 1С и последующую прямую печать на физический принтер.
Функция НапечататьФайлPDF_bioPDF(ПечатныйДокумент, ИмяФизическогоПринтера = "") Экспорт
Попытка
ПДФ_принтер = Новый COMОбъект("bioPDF.PDFPrinterSettings");
Исключение
#Если Клиент Тогда
Сообщить("Не удалось подключиться к bioPDF PDF Printer! Обратитесь к администратору для установки.");
#КонецЕсли
Возврат "";
КонецПопытки;
ПДФ_принтер_имя = ПДФ_принтер.GetPrinterName;
ИмяФайлаВывода = ПолучитьИмяВременногоФайла("pdf"); // Будет использоваться как временный файл
ПДФ_принтер.SetValue("output", ИмяФайлаВывода);
ПДФ_принтер.SetValue("ConfirmOverwrite", "yes");
ПДФ_принтер.SetValue("ShowSaveAS", "never");
ПДФ_принтер.SetValue("ShowSettings", "never");
ПДФ_принтер.SetValue("ShowPDF", "no");
ПДФ_принтер.SetValue("Subject", "Report generated at " + ТекущаяДата);
ПДФ_принтер.SetValue("UseThumbs", "yes");
ПДФ_принтер.SetValue("Zoom", "100");
// Если требуется печать на конкретный физический принтер
Если ЗначениеЗаполнено(ИмяФизическогоПринтера) Тогда
ПДФ_принтер.SetValue("Target", "printer");
ПДФ_принтер.SetValue("PrinterName", ИмяФизическогоПринтера);
Иначе
ПДФ_принтер.SetValue("Target", "file"); // По умолчанию сохраняем в файл
КонецЕсли;
// ... можно добавить другие настройки для водяных знаков, поворота и т.д.
// ПДФ_принтер.SetValue("WatermarkFontSize", "10");
// ПДФ_принтер.SetValue("WatermarkTransparency", "50");
// ...
ПДФ_принтер.WriteSettings(True); // Применяем настройки
ПечатныйДокумент.ИмяПринтера = ПДФ_принтер_имя; // Отправляем документ на виртуальный принтер
ПечатныйДокумент.АвтоМасштаб = Истина;
ПечатныйДокумент.Напечатать;
// Пауза, чтобы дать виртуальному принтеру время на обработку и отправку на физический принтер
ТекущееВремя = ТекущаяДата;
Пока ТекущаяДата < ТекущееВремя + 10 Цикл // 10 секунд задержки
ОбработкаПрерыванияПользователя();
КонецЦикла;
ПДФ_принтер = Неопределено; // Освобождаем объект COM
Возврат ИмяФайлаВывода; // Возвращаем имя созданного временного файла (если Target="file")
КонецФункции
Некоторые сторонние PDF-читалки предлагают более удобные механизмы для тихой печати. Например, Foxit Reader, начиная с версии 9.4, поддерживает "тихий режим" печати.
Особенности Foxit Reader:
/t можно отправить документ на печать без открытия видимых окон.
Пример команды для Foxit Reader:
// Укажите полный путь к исполняемому файлу FoxitReader.exe
ПутьFoxitReader = """c:\Program Files (x86)\Foxit Software\Foxit Reader\FoxitReader.exe""";
ИмяФайлаPDF = "C:\Путь\К\Вашему\Файлу.pdf";
ИмяПринтера = "МойПринтер"; // Опционально, если не указать, используется принтер по умолчанию
ЗапуститьПриложение(ПутьFoxitReader + " /t " + """" + ИмяФайлаPDF + """" + ?(ЗначениеЗаполнено(ИмяПринтера), " " + """" + ИмяПринтера + """", ""));
// Обязательная задержка для отправки на печать
ТекущееВремя = ТекущаяДата;
Пока ТекущаяДата < ТекущееВремя + 3 Цикл
ОбработкаПрерыванияПользователя();
КонецЦикла;
Преимущества: Полностью скрытая печать без остающихся окон.
Недостатки: Некоторые версии Foxit Reader могут быть платными, а также требуется предварительная установка и настройка на каждом клиентском компьютере.
В последних релизах платформы 1С (например, 8.3.22.1750 и выше) появились встроенные возможности для работы с PDF.
Используйте команду taskkill /f /im ИмяПроцесса.exe после завершения печати, если процесс не закрывается автоматически. Для COM-объектов применяйте методы CloseAllDocs и Exit.
Не используйте жестко заданный путь. Получайте путь к Adobe Reader из реестра Windows с помощью WScript.Shell.RegRead("HKCR\Software\Adobe\Acrobat\Exe\").
Всегда добавляйте программную задержку (например, 3-10 секунд с использованием цикла Пока ТекущаяДата < ТекущееВремя + N) после отправки файла на печать. Это позволит операционной системе и принтеру обработать задание, прежде чем вы перейдете к следующему файлу или удалите временный PDF.
Это одна из самых сложных задач при автоматической печати готовых PDF.
ShellExecute обычно нет. Простейшее решение — это запускать команду печати столько раз, сколько нужно копий, используя цикл.Используйте короткие имена принтеров без пробелов и специальных символов при передаче их в командной строке или COM-объектам. Для сетевых принтеров указывайте полный путь, например, \\SERVER\PRINTER.
Выбор оптимального метода печати PDF из 1С зависит от конкретных требований вашего проекта: необходим ли вам максимальный контроль над печатью, готовы ли вы устанавливать дополнительное ПО на клиентские машины, и насколько важно полностью скрывать процесс печати от пользователя. Комбинирование различных подходов, таких как получение пути из реестра, использование задержек и принудительное завершение процессов, поможет создать надежное и универсальное решение.