При работе в среде «1С:Предприятие» разработчики и системные администраторы часто сталкиваются со следующей проблемой: при попытке вывести на печать, отобразить на экране или сохранить большой массив ценников или этикеток (от нескольких сотен до тысяч штук) сеанс пользователя аварийно завершается. Windows выдает стандартное окно с сообщением «Прекращена работа программы 1cv8», при этом явных утечек оперативной памяти в диспетчере задач может не наблюдаться (процесс завершается на относительно скромных 500–600 МБ).
В этой статье мы подробно разберем, почему возникает эта ошибка, какие системные механизмы лежат в её основе и как полностью решить проблему программными и системными методами.
--- ### Выясняем истинную причину: почему падает 1С?
Многие разработчики ошибочно полагают, что падение связано исключительно с утечкой оперативной памяти (RAM) из-за неоптимального кода. Однако в случае массовой печати этикеток ключевую роль играют совершенно другие факторы:
1CBarCod.dll), каждый сформированный штрихкод регистрируется в системе как отдельный тяжеловесный графический объект. При выводе более 500–1000 этикеток лимит в 10 000 дескрипторов мгновенно исчерпывается, что приводит к немедленному падению платформы.1cv8.exe ограничен 2 ГБ адресного пространства. Постоянное создание и уничтожение тысяч COM-объектов ActiveX дробит память. Когда метод Записать() пытается сохранить итоговый табличный документ в формате XLSX или PDF, платформе требуется выделить один большой непрерывный блок памяти. Из-за сильной фрагментации ОС отвечает отказом, вызывая аварийное завершение программы.--- ### Способ 1. Переход на шрифтовую печать штрихкодов (Оптимальный и быстрый метод)
Самый надежный способ раз и навсегда победить лимит GDI-объектов и ускорить печать этикеток в десятки раз — отказаться от использования ActiveX-компоненты 1CBarCod.dll в пользу специализированных шрифтов (например, EanGnivc или Barcode Font).
При таком подходе штрихкод выводится в ячейку табличного документа как обычная текстовая строка. Отрисовкой линий занимается сам графический движок операционной системы на уровне шрифта, что вообще не создает дополнительных GDI-дескрипторов.
Рассмотрим по шагам, как реализовать этот механизм для популярного формата EAN-13:
Скачайте и установите шрифт EanGnivc на сервере терминалов (если работа идет в RDP) или на локальных компьютерах пользователей.
Просто применить шрифт к обычным цифрам штрихкода нельзя — сканер его не прочитает. Штрихкод содержит контрольные символы и стартовые/стоповые маркеры. Разберем и применим функцию, которая преобразует цифровую последовательность штрихкода в специальный набор символов для шрифта EanGnivc:
Функция СформироватьСтрокуEanGnivc(ШтрихкодСтрокойСимволов) Экспорт
Попытка
Тест = Число(ШтрихкодСтрокойСимволов);
Исключение
ВызватьИсключение "Штрихкод должен содержать только цифры";
КонецПопытки;
СимволыСпособовКодирования = "#$%&'()*+,";
ЛевыйЗащитныйШаблон = "!";
СреднийЗащитныйШаблон = "-";
ПравыйЗащитныйШаблон = "!";
СимволыШрифтаПоТипамКодов = Новый Соответствие;
СимволыШрифтаПоТипамКодов.Вставить("L", "0123456789");
СимволыШрифтаПоТипамКодов.Вставить("G", "ABCDEFGHIJ");
СимволыШрифтаПоТипамКодов.Вставить("R", "abcdefghij");
СпособыКодированияЛевойЧасти = Новый Массив;
СпособыКодированияЛевойЧасти.Добавить("LLLLLL");
СпособыКодированияЛевойЧасти.Добавить("LLGLGG");
СпособыКодированияЛевойЧасти.Добавить("LLGGLG");
СпособыКодированияЛевойЧасти.Добавить("LLGGGL");
СпособыКодированияЛевойЧасти.Добавить("LGLLGG");
СпособыКодированияЛевойЧасти.Добавить("LGGLLG");
СпособыКодированияЛевойЧасти.Добавить("LGGGLL");
СпособыКодированияЛевойЧасти.Добавить("LGLGLG");
СпособыКодированияЛевойЧасти.Добавить("LGLGGL");
СпособыКодированияЛевойЧасти.Добавить("LGGLGL");
СпособКодированияПравойЧасти = "RRRRRR";
Если СтрДлина(ШтрихкодСтрокойСимволов) = 13 Тогда
КоличествоСимволовВГруппе = 6;
ИначеЕсли СтрДлина(ШтрихкодСтрокойСимволов) = 8 Тогда
КоличествоСимволовВГруппе = 4;
СимволыСпособовКодирования = "";
ШтрихкодСтрокойСимволов = "0" + ШтрихкодСтрокойСимволов;
Иначе
ВызватьИсключение "Поддерживаются только штрихкоды длиной 13 и 8 символов";
КонецЕсли;
ИндексСпособаКодирования = Число(Лев(ШтрихкодСтрокойСимволов, 1));
ЛеваяЧастьКода = "";
ПраваяЧастьКода = "";
Для ИндексСимвола = 1 По КоличествоСимволовВГруппе Цикл
ЛеваяЧастьКода = ЛеваяЧастьКода
+ Сред(СимволыШрифтаПоТипамКодов[Сред(СпособыКодированияЛевойЧасти[ИндексСпособаКодирования], ИндексСимвола, 1)]
, Число(Сред(ШтрихкодСтрокойСимволов, (ИндексСимвола + 1), 1)) + 1
, 1);
ПраваяЧастьКода = ПраваяЧастьКода
+ Сред(СимволыШрифтаПоТипамКодов[Сред(СпособКодированияПравойЧасти, ИндексСимвола, 1)]
, Число(Сред(ШтрихкодСтрокойСимволов, (ИндексСимвола + КоличествоСимволовВГруппе + 1), 1)) + 1
, 1);
КонецЦикла;
Результат = "" + Сред(СимволыСпособовКодирования, ИндексСпособаКодирования + 1, 1)
+ ЛевыйЗащитныйШаблон
+ ЛеваяЧастьКода
+ СреднийЗащитныйШаблон
+ ПраваяЧастьКода
+ ПравыйЗащитныйШаблон;
Возврат Результат;
КонецФункции
В макете вашей обработки печати удалите объект ActiveX «1С:Печать штрихкодов». Вместо него назначьте обычной текстовой ячейке шрифт EanGnivc с необходимым размером (обычно от 26 до 36 пунктов). При заполнении параметров макета передавайте в эту ячейку результат выполнения функции СформироватьСтрокуEanGnivc(Штрихкод).
Важное ограничение: Данный метод безупречно подходит для стандартных линейных кодов (EAN-13, Code128). Однако он не решит проблему, если вам требуется выводить современные двумерные коды маркировки (QR-коды, DataMatrix для «Честного Знака»). Для работы с ними рассмотрите решения ниже.
--- ### Способ 2. Вывод штрихкода в виде картинки (Native-метод)
Если вам необходима поддержка DataMatrix или вы не хотите заниматься установкой сторонних шрифтов на все клиентские машины, проанализируем современный подход, используемый в БСП (Библиотеке стандартных подсистем). Вместо тяжелого контейнера ActiveX штрихкод генерируется во внешней компоненте и помещается в ячейку как обычный плоский рисунок.
Программная вставка рисунка в 1С выглядит следующим образом:
// Создаем или получаем картинку штрихкода из компоненты Native API
КартинкаШтрихкода = ПолучитьКартинкуШтрихкода(ДанныеШтрихкода);
// Добавляем рисунок в область табличного документа
ОбластьМакета = Макет.ПолучитьОбласть("Строка");
Рисунок = ОбластьМакета.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Картинка);
Рисунок.Картинка = КартинкаШтрихкода;
Рисунок.ГраницаСверху = Ложь;
Рисунок.ГраницаСнизу = Ложь;
Рисунок.ГраницаСлева = Ложь;
Рисунок.ГраницаСправа = Ложь;
// Позиционируем рисунок поверх нужных ячеек
Рисунок.Расположить(ОбластьМакета.Область("R1C2:R3C4"));
Обычные картинки, в отличие от элементов управления ActiveX, не захватывают системные дескрипторы окон Windows. Это позволяет беспрепятственно формировать документы, содержащие десятки тысяч штук штрихкодов без утечек памяти и исчерпания лимитов GDI.
--- ### Способ 3. Изменение лимита GDI-объектов в реестре Windows
Если у вас нет возможности оперативно изменить код обработки печати (например, конфигурация находится на жесткой поддержке, а ценники нужно распечатать прямо сейчас), можно применить системный обходной путь. Мы можем принудительно увеличить лимит дескрипторов графических объектов для процессов в операционной системе Windows Server.
Разберем этот процесс по шагам:
regedit и нажмите Enter.HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows
10000.Этот временный «костыль» отодвинет порог аварийного завершения платформы 1С примерно в 1.5–2 раза, что позволит успешно выводить средние объемы документов без переписывания логики программы.
--- ### Способ 4. Пакетная генерация и фоновое объединение документов
Чтобы полностью обезопасить сеанс пользователя от зависаний, лучшим решением со стороны архитектуры будет перевод процесса генерации тяжелых файлов на сторону сервера в фоновые задания с последующим пакетным сбором файлов.
Рассмотрим логику построения такого процесса:
ТабличныйДокумент.ТабДок.Записать(ИмяВременногоФайла, ТипФайлаТабличногоДокумента.PDF);
Используя предложенные методики, вы гарантируете стабильную работу системы даже при пиковых нагрузках во время переоценки товаров и массовой печати ценников.