Каждый администратор или разработчик 1С хотя бы раз сталкивался с ситуацией, когда программа внезапно «схлопывается» без видимых причин и сообщений об ошибках. Особенно неприятно, когда это происходит посреди рабочего дня во время массовой печати первичных документов или сертификатов качества. Программа просто закрывается, а в журнале регистрации 1С не остается никаких следов.
Если заглянуть в системный просмотрщик событий Windows (Event Viewer), там обнаруживается запись об ошибке приложения 1cv8.exe со сбойным модулем cairo.dll и кодом исключения 0xc0000005 (нарушение прав доступа/Access Violation). В этой статье мы подробно разберем, почему возникает эта ошибка, как она связана с архитектурными изменениями платформы 1С, и какими способами можно навсегда решить эту проблему.
Для того чтобы понять природу сбоя, нам необходимо обратиться к истории развития технологической платформы «1С:Предприятие». Начиная с версии 8.3.16, фирма «1С» осуществила глобальный переход графической подсистемы клиентских приложений (за исключением веб-клиента) на кроссплатформенную библиотеку Cairo. До этого момента в операционных системах семейства Windows для отрисовки интерфейса, масштабирования картинок и подготовки документов к печати использовались встроенные системные интерфейсы GDI и GDI+.
Внедрение библиотеки Cairo позволило унифицировать код платформы для Windows, macOS и Linux, обеспечив одинаковое отображение элементов интерфейса и печатных форм на всех поддерживаемых ОС. Однако у этого решения обнаружилась и обратная сторона: Cairo оказалась крайне чувствительной к качеству исходных графических файлов и объему доступной оперативной памяти.
Выделим ключевые причины, из-за которых библиотека cairo.dll аварийно завершает работу процесса 1С с кодом 0xc0000005:
АвтоМасштаб = Истина, библиотека Cairo вынуждена применять сложные математические алгоритмы интерполяции (сжатия или растяжения) исходных изображений, чтобы они вписались в границы печатного листа. На больших разрешениях это создает колоссальную нагрузку на процессор и оперативную память.Довольно часто системные администраторы замечают странную закономерность: в журнале приложений фиксируется ошибка `Application Error 1000` со сбойным модулем cairo.dll, и в эту же секунду в журнале безопасности появляются две записи:
NT AUTHORITY\SYSTEM (Тип входа 5 — служба).На первый взгляд может показаться, что система подверглась вирусной атаке или происходит несанкционированная попытка повышения привилегий сторонним процессом. На самом деле это следствие работы диспетчера печати Windows (Print Spooler, процесс spoolsv.exe).
Когда мы вызываем метод ТабДок.Напечатать(), 1С передает сформированный графический поток службе печати операционной системы. Если в этот момент библиотека cairo.dll падает, процесс 1cv8.exe аварийно завершается, прерывая передачу данных. Служба печати Windows, работающая под системной учетной записью SYSTEM, мгновенно реагирует на прерывание транзакции, инициализирует процедуру очистки очереди печати и пытается записать минидамп падения. Именно эти действия операционной системы и регистрируются в журнале безопасности как авторизация службы с повышенными правами. Это следствие краха 1С, а не его первопричина.
Поскольку корень проблемы кроется в дефиците оперативной памяти и фрагментации адресного пространства 32-битного процесса, самым надежным и фундаментальным решением является переход на использование 64-разрядной версии тонкого или толстого клиента 1С.
В 64-битном приложении виртуальное адресное пространство практически неограниченно (достигает нескольких терабайт). Даже если при печати партии из 100 сертификатов библиотека Cairo временно выделит под распаковку тяжелых сканов 3-4 ГБ памяти, операционная система успешно выделит этот объем, печать завершится корректно, а после закрытия формы память вернется в операционную систему без каких-либо сбоев.
Рассмотрим по шагам, как выполнить переход:
C:\Program Files\1cv8\ (в отличие от 32-битного, который по умолчанию находится в C:\Program Files (x86)\1cv8\).1cestart.exe, убедитесь, что в свойствах информационной базы в поле «Разрядность» установлено значение «64 (x64)» или «Авто» (при условии, что на компьютере удалена старая 32-битная платформа).Практика показывает, что после перехода на x64-платформу утечки памяти в Cairo перестают приводить к аварийному завершению работы 1С, так как процесс больше не упирается в двухгигабайтный лимит.
Если по каким-то причинам вы не можете оперативно перевести всех пользователей на 64-битные клиенты (например, из-за ограничений старого оборудования или использования специфических 32-битных внешних компонент торгового оборудования), проблему можно решить оптимизацией самих печатных форм и изображений.
Проанализируем структуру макетов. Зачастую пользователи сканируют сертификаты с разрешением 300 или даже 600 DPI в формате без сжатия (TIFF/BMP). В результате один файл сертификата может весить 5–15 МБ. При выводе такого изображения на печать в масштабе листа А4 принтеру и графической системе Cairo не требуется такое гигантское разрешение. Достаточно 150 DPI, при котором размер файла уменьшается в десятки раз.
Выполним оптимизацию картинок непосредственно перед выводом их в табличный документ. Нам необходимо принудительно перевести картинку в стандартный формат RGB JPEG и уменьшить ее физический размер.
Ниже приведен пример кода, демонстрирующий, как можно оптимизировать изображение, хранящееся в базе данных, перед выводом на печать:
Функция ОптимизироватьКартинкуДляПечати(ИсходнаяКартинка) Экспорт
// Проверим, заполнена ли картинка
Если ИсходнаяКартинка = Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
// Получаем двоичные данные картинки
ДвоичныеДанные = ИсходнаяКартинка.ПолучитьДвоичныеДанные();
Если ДвоичныеДанные = Неопределено Тогда
Возврат ИсходнаяКартинка;
КонецЕсли;
// Если размер картинки меньше 300 Кб, пропускаем оптимизацию
РазмерВКб = ДвоичныеДанные.Размер() / 1024;
Если РазмерВКб < 300 Тогда
Возврат ИсходнаяКартинка;
КонецЕсли;
// Используем объект "ОбработкаКартинок" для сжатия и нормализации формата
Попытка
ОбрабатываемаяКартинка = Новый Картинка(ДвоичныеДанные);
// Преобразуем изображение в формат JPEG со сжатием
// Это автоматически переведет CMYK в RGB и уберет прогрессивное сжатие
НовыеДвоичныеДанные = ОбрабатываемаяКартинка.Преобразовать(ФорматКартинки.JPEG);
Возврат Новый Картинка(НовыеДвоичныеДанные);
Исключение
// Если объект "ОбработкаКартинок" недоступен на данной платформе,
// возвращаем исходную картинку во избежание прерывания работы
Возврат ИсходнаяКартинка;
КонецПопытки;
КонецФункции
Также рекомендуется в свойствах ячейки табличного документа, куда выводится картинка, или в самом объекте РисунокТабличногоДокумента отключить автоматическое масштабирование и установить фиксированный размер. Для этого установите свойство РазмерКартинки в значение Пропорционально или РеальныйРазмер, предварительно подогнав размеры самого рисунка под параметры страницы.
В коде формирования печатной формы отключим свойство автоматического масштабирования печатного листа:
ТабДок = Новый ТабличныйДокумент;
// Настройки параметров страницы
ТабДок.АвтоМасштаб = Ложь; // Отключаем сложный ресэмплинг Cairo
ТабДок.ОриентацияСтраницы = ОриентацияСтраницы.Портрет;
Бывают ситуации, когда конфигурация закрыта для редактирования макетов, обновить платформу на x64 невозможно, а документы печатать нужно прямо сейчас. В этом случае мы можем применить изящный обходной путь (Workaround), который успешно опробован многими практикующими специалистами 1С.
Суть метода заключается в том, чтобы не заставлять нестабильную библиотеку cairo.dll обрабатывать тяжелую графику. Вместо этого мы программно сохраняем картинки сертификатов во временный каталог на жестком диске и отправляем их на печать в фоновом режиме с помощью легковесной и крайне надежной бесплатной утилиты IrfanView через командную строку.
Разберем по шагам реализацию этого механизма:
C:\Program Files\IrfanView\i_view64.exe).Посмотрим на пример кода, реализующий этот алгоритм:
Процедура НапечататьСертификатВнешнейУтилитой(СсылкаНаСертификат, ИмяПринтера = "")
// Получаем картинку из реквизита или присоединенного файла
КартинкаСертификата = СсылкаНаСертификат.ФайлКартинки.Получить();
Если КартинкаСертификата = Неопределено Тогда
Возврат;
КонецЕсли;
ДвоичныеДанные = КартинкаСертификата.ПолучитьДвоичныеДанные();
Если ДвоичныеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
// Формируем имя временного файла на диске
ИмяФайлаИзображения = КаталогВременныхФайлов() + "cert_" + Строка(Новый УникальныйИдентификатор) + ".jpg";
ДвоичныеДанные.Записать(ИмяФайлаИзображения);
// Путь к исполняемому файлу IrfanView
ПутьКИрфан = "C:\Program Files\IrfanView\i_view64.exe";
// Проверим наличие установленной утилиты
ФайлУтилиты = Новый Файл(ПутьКИрфан);
Если Не ФайлУтилиты.Существует() Тогда
ВызватьИсключение "Не найдена утилита IrfanView по пути: " + ПутьКИрфан;
КонецЕсли;
// Формируем параметры запуска командной строки
// Ключ /print инициализирует отправку файла на принтер по умолчанию
// Если нужно напечатать на конкретный принтер, используем ключ /print="ИмяПринтера"
ПараметрыЗапуска = """" + ИмяФайлаИзображения + """";
Если ЗначениеЗаполнено(ИмяПринтера) Тогда
ПараметрыЗапуска = ПараметрыЗапуска + " /print=""" + ИмяПринтера + """";
Иначе
ПараметрыЗапуска = ПараметрыЗапуска + " /print";
КонецЕсли;
// Запускаем приложение в фоновом режиме без ожидания
ЗапуститьПриложение(ПутьКИрфан + " " + ПараметрыЗапуска, , Ложь);
// Важно: так как запуск происходит асинхронно, удалять временный файл сразу нельзя.
// ОС сама очистит временную папку позже, либо можно реализовать пул удаления.
КонецПроцедуры
Этот способ полностью исключает 1С из процесса рендеринга графики. Платформа просто выгружает файл на диск и отдает команду операционной системе. IrfanView славится своей «всеядностью» к графическим форматам — он без проблем справляется с CMYK, Progressive JPEG, поврежденными метаданными и не падает при нехватке памяти.
Иногда сбой библиотеки cairo.dll провоцируется некорректным поведением драйверов печати конкретного принтера. Особенно часто это происходит при использовании универсальных драйверов (Universal Print Driver - UPD) от HP, Xerox или Kyocera.
Проанализируем и выполним следующие системные настройки на компьютере пользователя:
RAW на NT EMF или наоборот. Это изменит способ формирования промежуточного файла spool-очереди Windows.cairo.dll является динамически подключаемой C++ библиотекой, стабильность её работы зависит от системных библиотек выполнения. Установите на компьютер актуальные пакеты Microsoft Visual C++ Redistributable (как x86, так и x64 версий) за все годы, начиная с 2015 по настоящее время.Мы подробно проанализировали проблему падения платформы 1С с ошибкой в модуле cairo.dll при печати документов с изображениями. Подведем итоги и составим оптимальный план действий для устранения этой неполадки:
АвтоМасштаб для тяжелых макетов, чтобы разгрузить математический аппарат Cairo.Применяя эти методы системно, вы сможете гарантировать стабильную работу пользователей и бесперебойную массовую печать документов любого объема и сложности.