Как распечатать готовые PDF-файлы из 1С без зависания процессов и с контролем параметров?

Программист 1С v8.3 (Обычные формы)
← На главную

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

1. Печать через Adobe Acrobat Reader

Adobe Acrobat Reader является одним из наиболее распространенных бесплатных средств для просмотра и печати PDF. Существует два основных способа взаимодействия с ним из 1С: через командную строку и через COM-объект.

1.1. Печать через командную строку (AcroRd32.exe)

Самый простой способ отправить PDF на печать — это запустить исполняемый файл Adobe Reader с определенными параметрами (используя подключаемые команды БСП) — для этой задачи есть обработка для пакетной печати PDF-комплектов. Для этого используется функция ЗапуститьПриложение. Основные параметры, которые нас интересуют:

Пример базовой команды:


ЗапуститьПриложение("C:\Program Files\Adobe\Reader 10.0\Reader\AcroRd32.exe /N /T " + ИмяФайла);

Возможные проблемы и их решения:

  1. Неуниверсальный путь к 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-файлов невозможна.", СтатусСообщения.Важное);
        Возврат;
    КонецЕсли;
    
  2. Зависающие процессы Adobe Reader: После печати процесс AcroRd32.exe может оставаться висеть в памяти или оставлять открытое, но невидимое окно.

    Решение: Принудительно завершайте процесс после печати с помощью команды taskkill. Для этого нам нужно получить имя исполняемого файла:

    
    // ... (код для запуска печати) ...
    
    // Получаем имя процесса для завершения
    ИмяПроцессаРидера = ПутьAdobeReader;
    НомерСимвола = Найти(ИмяПроцессаРидера, "\");
    Пока НомерСимвола > 0 Цикл
        ИмяПроцессаРидера = Сред(ИмяПроцессаРидера, НомерСимвола + 1);
        НомерСимвола = Найти(ИмяПроцессаРидера, "\");
    КонецЦикла;
    // Убиваем процесс
    WshShell.Run("taskkill /f /im " + ИмяПроцессаРидера, 0);
    
  3. Проблемы с удалением временных файлов и пакетной печатью: Если вы печатаете временный PDF-файл, а затем сразу его удаляете, или выполняете пакетную печать множества файлов, система может не успеть обработать команду печати до удаления файла или до запуска следующего задания — эти сложности решает автоматизация пакетной печати отгрузочных документов. Это может привести к ошибкам "файл не найден" или неполной печати.

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

    
    // ... (после WshShell.Run) ...
    ТекущееВремя = ТекущаяДата;
    Пока ТекущаяДата < ТекущееВремя + 5 Цикл // 5 секунд задержки
        ОбработкаПрерыванияПользователя(); // Позволяет системе не зависать
    КонецЦикла;
    // ... (далее можно удалять файл или запускать следующее задание) ...
    
  4. Проблемы с указанием имени принтера: При использовании параметра /T с именем принтера (например, /T "путь\к\файлу.pdf" "Мой Принтер") могут возникать ошибки, если имя принтера содержит пробелы, специальные символы или слишком длинное. Для сетевых принтеров имя должно включать сервер (например, \\SERVER\PRINTER_NAME).

    Решение: Используйте короткие имена принтеров без пробелов и спецсимволов. Для сетевых принтеров указывайте полный путь с именем сервера.

  5. Ограниченный контроль параметров печати: Командная строка 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);

КонецПроцедуры

1.2. Печать через COM-объект AcroPDF.PDF.1

COM-объект 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

Возможные проблемы и их решения:

  1. Зависающие процессы: Несмотря на вызов методов CloseAllDocs и Exit, процесс Reader может остаться в памяти.

    Решение: Дополнительно можно использовать taskkill, как описано выше для командной строки. Однако, при правильном использовании CloseAllDocs и Exit эта проблема возникает реже.

  2. Ограничения в бесплатных версиях: Некоторые расширенные функции COM-объекта могут быть доступны только в платных версиях Adobe Acrobat Professional.

    Решение: Тестируйте функционал с установленной версией Adobe Reader. Если требуется более тонкий контроль (количество копий, диапазон страниц), возможно, придется искать другие решения.

2. Печать через Shell.Application

Объект Shell.Application предоставляет доступ к функциям оболочки Windows и является универсальным способом взаимодействия с файлами, используя системные ассоциации. Это означает, что 1С не привязывается к конкретному приложению (например, Adobe Reader), а просто просит операционную систему распечатать файл, используя программу, назначенную для PDF по умолчанию.

2.1. Метод 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

2.2. Метод 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:

3. Использование виртуальных PDF-принтеров (Bullzip, PDFCreator, bioPDF)

Виртуальные PDF-принтеры, такие как Bullzip PDF Printer, PDFCreator или bioPDF, изначально созданы для *генерации* PDF-файлов из любых печатаемых документов. Однако многие из них предоставляют COM-интерфейсы, которые позволяют программно управлять их настройками и даже направлять вывод на физический принтер. Для пакетного вывода печатных форм и их экспорта можно использовать обработку для групповой печати документов и сохранения их на диск.

Преимущества:

Недостатки:

3.1. Пример с Bullzip PDF Printer (для генерации PDF, затем печать)

Следующий код показывает, как использовать 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 Цикл
            ОбработкаПрерыванияПользователя();
        КонецЦикла;
    КонецЕсли;

КонецПроцедуры

3.2. Пример с bioPDF PDF Printer (для генерации PDF и прямой печати)

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")
КонецФункции

4. Использование сторонних PDF-читалок (Foxit Reader)

Некоторые сторонние PDF-читалки предлагают более удобные механизмы для тихой печати. Например, Foxit Reader, начиная с версии 9.4, поддерживает "тихий режим" печати.

Особенности Foxit Reader:

Пример команды для Foxit Reader:


// Укажите полный путь к исполняемому файлу FoxitReader.exe
ПутьFoxitReader = """c:\Program Files (x86)\Foxit Software\Foxit Reader\FoxitReader.exe""";
ИмяФайлаPDF = "C:\Путь\К\Вашему\Файлу.pdf";
ИмяПринтера = "МойПринтер"; // Опционально, если не указать, используется принтер по умолчанию

ЗапуститьПриложение(ПутьFoxitReader + " /t " + """" + ИмяФайлаPDF + """" + ?(ЗначениеЗаполнено(ИмяПринтера), " " + """" + ИмяПринтера + """", ""));

// Обязательная задержка для отправки на печать
ТекущееВремя = ТекущаяДата;
Пока ТекущаяДата < ТекущееВремя + 3 Цикл
    ОбработкаПрерыванияПользователя();
КонецЦикла;

Преимущества: Полностью скрытая печать без остающихся окон.

Недостатки: Некоторые версии Foxit Reader могут быть платными, а также требуется предварительная установка и настройка на каждом клиентском компьютере.

5. Современные возможности платформы 1С

В последних релизах платформы 1С (например, 8.3.22.1750 и выше) появились встроенные возможности для работы с PDF.

Решение общих проблем при печати PDF из 1С

  1. Зависающие процессы:

    Используйте команду taskkill /f /im ИмяПроцесса.exe после завершения печати, если процесс не закрывается автоматически. Для COM-объектов применяйте методы CloseAllDocs и Exit.

  2. Универсальность пути к исполняемому файлу:

    Не используйте жестко заданный путь. Получайте путь к Adobe Reader из реестра Windows с помощью WScript.Shell.RegRead("HKCR\Software\Adobe\Acrobat\Exe\").

  3. Задержки при пакетной печати и удалении временных файлов:

    Всегда добавляйте программную задержку (например, 3-10 секунд с использованием цикла Пока ТекущаяДата < ТекущееВремя + N) после отправки файла на печать. Это позволит операционной системе и принтеру обработать задание, прежде чем вы перейдете к следующему файлу или удалите временный PDF.

  4. Настройка количества копий, масштаба и диапазона страниц:

    Это одна из самых сложных задач при автоматической печати готовых PDF.

    • Количество копий: Прямого способа через командную строку или ShellExecute обычно нет. Простейшее решение — это запускать команду печати столько раз, сколько нужно копий, используя цикл.
    • Масштаб и диапазон страниц: Для этих настроек стандартные командные методы почти бесполезны. Можно рассмотреть следующие варианты:
      • ActiveX-компонент: Вставка ActiveX-компонента Adobe PDF Reader на форму 1С позволяет пользователю вручную настроить масштаб и другие параметры перед печатью. Однако эти настройки не сохраняются после закрытия формы или программы.
      • Виртуальные принтеры: Некоторые виртуальные принтеры (например, Bullzip, bioPDF) через свой COM-интерфейс могут предоставлять более детальный контроль над параметрами печати (масштаб, ориентация), особенно если вы генерируете PDF через них. Изучите документацию к выбранному виртуальному принтеру.
      • Специализированные библиотеки: Для максимального контроля над печатью PDF (например, выборочная печать страниц, точный масштаб) могут потребоваться специализированные библиотеки или компоненты для работы с PDF, которые зачастую являются платными.
  5. Проблемы с именами принтеров:

    Используйте короткие имена принтеров без пробелов и специальных символов при передаче их в командной строке или COM-объектам. Для сетевых принтеров указывайте полный путь, например, \\SERVER\PRINTER.

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

← На главную