При переходе конфигураций (например, УПП) на платформу 1С:Предприятие 8.3 разработчики часто сталкиваются с неожиданным поведением при сохранении бинарных файлов и внешних компонент. В процессе выполнения метода Записать() отладчик может прерывать выполнение и выдавать сообщение: «Обращение к процедуре объекта как к функции (Записать)». Разберем по шагам, почему возникает эта иллюзия ошибки и как локализовать реальную проблему в коде.
Проанализируем типовую ситуацию: при попытке извлечь и сохранить внешнюю компоненту из регистра сведений используется вызов метода записи двоичных данных на диск:
ДвоичныеДанные = НаборЗаписей[0].ХранилищеФайла.Получить();
ИмяФайла = КаталогПрограммы() + Выборка.ИмяФайла;
ДвоичныеДанные.Записать(ИмяФайла);
Если разработчик пытается проверить выполнение последней строки через окно «Вычислить выражение» (Shift+F9) или добавляет выражение в «Табло», платформа 1С возвращает сообщение: {(1)}: Обращение к процедуре объекта как к функции (Записать).
Выясним причину такого поведения. Окно вычисления выражений и табло отладчика спроектированы исключительно для расчета значений функций или выражений, которые возвращают результат. Метод Записать() у объекта ДвоичныеДанные является процедурой и не возвращает никакого значения. Вычислитель отладчика пытается интерпретировать любое введенное выражение как функцию, что и порождает указанную диагностику. Таким образом, эта ошибка возникает только внутри самого отладчика, а не при штатной работе программного модуля.
Посмотрим на типовой фрагмент кода, где операция записи обрамлена в конструкцию обработки исключений:
Попытка
НаборЗаписей[0].ХранилищеФайла.Получить().Записать(КаталогПрограммы() + Выборка.ИмяФайла);
Файл = Новый Файл(КаталогПрограммы() + Выборка.ИмяФайла);
Файл.УстановитьВремяИзменения(Выборка.ДатаИзмененияФайла);
Исключение
// Пустой блок перехвата
КонецПопытки;
Если в Конфигураторе активирован режим «Отладка -> Останавливаться по ошибке», отладчик прерывает выполнение программы на строке, сгенерировавшей любое исключение, даже если эта строка находится внутри блока Попытка ... Исключение. В этот момент разработчик видит остановку, открывает табло, вводит строку ДвоичныеДанные.Записать(...) и получает сообщение об обращении к процедуре как к функции, ошибочно принимая его за причину сбоя.
Для того чтобы выяснить реальную причину прерывания выполнения, разберем по шагам правильный алгоритм перехвата ошибки:
Исключение, чтобы зафиксировать настоящее системное описание сбоя:
Попытка
ДвДанные = НаборЗаписей[0].ХранилищеФайла.Получить();
ПолноеИмя = КаталогПрограммы() + Выборка.ИмяФайла;
ДвДанные.Записать(ПолноеИмя);
Исключение
Сообщить(ОписаниеОшибки());
ЗаписьЖурналаРегистрации("ВнешниеКомпоненты", УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
КонецПопытки;
Рассмотрим подробнее реальные причины, из-за которых метод Записать() падает в блок Исключение при переходе на платформу 8.3:
КаталогПрограммы() указывает на каталог исполняемых файлов (обычно папка внутри Program Files). В современных версиях Windows запись в эту директорию заблокирована механизмом контроля учетных записей (UAC). Попытка создать там файл вызывает исключение «Ошибка доступа к файлу»..dll) уже была загружена в память текущим процессом или другим пользователем терминального сервера, операционная система запрещает перезапись файла на диске («Ошибка совместного доступа к файлу»).ХранилищеФайла не заполнено, вызов метода Получить() возвращает значение Неопределено. Попытка вызвать метод Записать() у пустого значения завершится ошибкой «Поле объекта не обнаружено».Для гарантированной и стабильной работы механизмов выгрузки внешних файлов применим следующие изменения:
Шаг 1. Перенос пути сохранения в доступную папку. Заменим системный каталог установки 1С на каталог временных файлов сеанса пользователя:
ИмяФайла = КаталогВременныхФайлов() + Выборка.ИмяФайла;
Шаг 2. Проверка типа полученных данных перед вызовом процедуры. Обеспечим проверку наличия бинарных данных перед их сохранением:
ДвоичныеДанные = НаборЗаписей[0].ХранилищеФайла.Получить();
Если ТипЗнч(ДвоичныеДанные) = Тип("ДвоичныеДанные") Тогда
ДвоичныеДанные.Записать(ИмяФайла);
Иначе
ВызватьИсключение "В хранилище отсутствуют корректные двоичные данные файла!";
КонецЕсли;
Шаг 3. Использование современных механизмов подключения компонент. При работе на платформе 8.3 рекомендуется отказаться от прямой записи файлов в исполняемые каталоги и использовать метод ПодключитьВнешнююКомпоненту() с макетами конфигурации, содержащими архив с описанием MANIFEST.XML. Это полностью исключает конфликты прав доступа к файловой системе.