В процессе администрирования и поддержки систем на платформе «1С:Предприятие 8.3» специалисты нередко сталкиваются со сбоями в работе стандартных сервисных механизмов. Одним из таких неприятных сюрпризов является внезапная ошибка при попытке настроить отбор по метаданным в журнале регистрации. Пользователь открывает форму настройки, выбирает необходимые объекты, но вместо ожидаемого результата система выдает критическую ошибку: «Индекс находится за границами массива».
Особенно загадочно эта ситуация выглядит тогда, когда на одном и том же сервере в абсолютно аналогичных базах данных (с той же версией конфигурации и платформы) всё работает корректно, а сбой происходит лишь в какой-то одной конкретной базе. В этой статье мы подробно разберем, почему возникает данная проблема, как устроена архитектура стандартных обработок платформы «1С», как извлечь скрытый программный код для анализа и как исправить ошибку раз и навсегда.
Для начала давайте проанализируем стек ошибки, который обычно видит разработчик в окне подробного описания или в режиме отладки:
{ВнешняяОбработка.StandardEventLog.Форма.PropertyContentsEditor.Форма(260)}: Индекс находится за границами массива
ParentDataPath = ParentDataPath + RealDataStrings[i];
Проанализируем ситуацию. Строка кода пытается обратиться к элементу массива RealDataStrings по индексу i. Ошибка «Индекс находится за границами массива» однозначно указывает на то, что текущее значение переменной-индекса i превышает максимально допустимый индекс в массиве (то есть массив содержит меньше элементов, чем ожидает алгоритм).
Но почему в одной базе массив заполняется корректно, а в другой происходит сбой? Этому есть несколько логических объяснений:
RealDataStrings неверной структуры и меньшей длины.Многие начинающие программисты «1С» при попытке отладить эту ошибку сталкиваются с препятствием: они открывают Конфигуратор, но не находят в дереве метаданных обработку с именем StandardEventLog. Ее там действительно нет.
Дело в том, что журнал регистрации, отчет «Активные пользователи», инструменты поиска ссылок и удаления помеченных объектов встроены непосредственно в саму платформу «1С:Предприятие» в виде скомпилированных внешних обработок. Платформа обращается к ним по специальному внутреннему виртуальному протоколу v8res://.
В частности, обработка журнала регистрации физически расположена по виртуальному адресу: v8res://mngbase/StandardEventLog.epf.
Поскольку код закрыт внутри платформы, мы не можем напрямую открыть форму PropertyContentsEditor в Конфигураторе. Однако существует легальный способ обойти это ограничение.
Для того чтобы получить доступ к исходному коду и формам проблемной обработки, нам необходимо выгрузить файл StandardEventLog.epf из ресурсов платформы на локальный диск компьютера. Сделать это очень просто.
Рассмотрим подробнее процесс выгрузки. Нам понадобится запустить любой программный код в контексте системы. Мы можем воспользоваться внешней обработкой для выполнения произвольного кода или временно прописать команду выгрузки в модуль управляемого приложения нашей базы при начале работы системы. Напишем следующую строку кода:
КопироватьФайл("v8res://mngbase/StandardEventLog.epf", "C:\StandardEventLog.epf");
Выполним этот код. Сразу после этого на диске C:\ появится файл StandardEventLog.epf. Теперь мы можем открыть его через Конфигуратор как обычную внешнюю обработку, увидеть структуру метаданных, макеты и все формы, включая вызывающую ошибку форму PropertyContentsEditor.
Теперь, когда у нас есть физический файл обработки на диске, мы можем легко локализовать проблему с помощью стандартного отладчика «1С»:
C:\StandardEventLog.epf в режиме Конфигуратора.PropertyContentsEditor, найдем строку 260 и установим на нее точку останова.C:\StandardEventLog.epf).RealDataStrings, i, ParentDataPath и понять, на каком именно объекте метаданных спотыкается платформа.Если мы не хотим вмешиваться в логику работы платформенных механизмов, стоит начать с простых шагов по очистке и диагностике базы данных. В подавляющем большинстве случаев это решает проблему, если она вызвана сбоем кэша или расширениями.
Выполним по шагам следующие действия:
srvinfo\reg_1541\ (папки с длинными UUID-именами). После этого запустим службу заново.chdbfl.exe, если используется файловый вариант базы данных.Если диагностика и чистка кэша не привели к успеху (например, если в вашей конфигурации обязательно должны работать расширения, вызывающие этот конфликт, а обновить платформу прямо сейчас нет возможности), мы можем исправить ошибку программно.
Разберем по шагам, как безопасно модифицировать код и заставить систему использовать исправленную версию журнала регистрации.
Шаг 1. Модификация кода обработки. Откроем нашу выгруженную обработку StandardEventLog.epf в Конфигураторе. Перейдем в модуль формы PropertyContentsEditor на строку 260. Заменим проблемный участок кода на безопасную конструкцию, которая предварительно проверяет размерность массива:
Если i < RealDataStrings.Количество() Тогда
ParentDataPath = ParentDataPath + RealDataStrings[i];
Иначе
// Запишем предупреждение в Журнал регистрации или просто пропустим некорректный элемент
ЗаписьЖурналаРегистрации("ОбходОшибкиМетаданных", УровеньЖурналаРегистрации.Предупреждение,,,
"Не удалось определить путь метаданных для индекса: " + Строка(i));
КонецЕсли;
Сохраним изменения в файле StandardEventLog.epf.
Шаг 2. Динамическое подключение исправленной обработки. Платформа «1С» обладает замечательной, хотя и малодокументированной возможностью: мы можем переопределить стандартную обработку нашей собственной прямо в момент запуска системы. Для этого нам не нужно снимать конфигурацию с поддержки.
Откроем модуль управляемого приложения нашей конфигурации (или модуль обычного приложения, в зависимости от используемого режима запуска) и в обработчике события ПриНачалеРаботыСистемы пропишем следующий код:
Процедура ПриНачалеРаботыСистемы()
// Путь к нашей исправленной обработке на сервере или локальном диске
ПутьКФайлу = "C:\Fixes\StandardEventLog.epf";
ФайлОбработки = Новый Файл(ПутьКФайлу);
Если ФайлОбработки.Существует() Тогда
Попытка
ДвоичныеДанные = Новый ДвоичныеДанные(ПутьКФайлу);
АдресХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанные);
// Подключаем нашу внешнюю обработку взамен стандартной платформенной
ВнешниеОбработки.Подключить(АдресХранилища, "StandardEventLog", Ложь);
Исключение
ЗаписьЖурналаРегистрации("ПодменаЖурналаРегистрации", УровеньЖурналаРегистрации.Ошибка,,,
"Ошибка подключения исправленной обработки: " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецПроцедуры
Разберем, как работает этот механизм. Метод ВнешниеОбработки.Подключить регистрирует внешнюю обработку в памяти текущего сеанса. Передав в качестве второго параметра имя "StandardEventLog", мы перекрываем стандартное системное имя. Теперь при любой попытке пользователя открыть стандартный журнал регистрации платформа вместо встроенного в нее ресурса v8res:// автоматически обратится к нашей исправленной обработке из временного хранилища.
Используя этот подход, мы гарантированно избавляемся от ошибки выхода индекса за границы массива, сохраняем работоспособность всех необходимых расширений конфигурации и обеспечиваем пользователям стабильную работу с анализом событий в базе данных.