В процессе разработки внешних обработок или доработки конфигураций на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с ошибкой Метод не обнаружен при попытке вызвать процедуру модуля объекта из формы. Рассмотрим причины возникновения этой проблемы и разберем правильную архитектуру взаимодействия клиента и сервера.
Проанализируем типичную ситуацию. Разработчик создает в модуле объекта процедуру, помечает ее ключевым словом Экспорт, но при попытке вызова из модуля управляемой формы получает отказ системы. Главная причина здесь кроется в контексте выполнения. В управляемом приложении модуль объекта всегда выполняется на сервере. Это фундаментальное правило, которое необходимо запомнить.
Когда мы пишем в модуле объекта директиву &НаКлиенте, платформа игнорирует ее или выдает ошибку компиляции, так как в этом модуле допустим только серверный контекст. Посмотрим на ошибочный код, который часто встречается у новичков:
// В модуле объекта (ОШИБОЧНО)
&НаКлиенте
Процедура РаботаСканПДФ() Экспорт
// Код, пытающийся вызвать диалог выбора файла
КонецПроцедуры
Поскольку модуль объекта — это серверная территория, попытка объявить там клиентский метод бессмысленна. Более того, использование внутри серверного модуля объектов, доступных только на клиенте (например, ДиалогВыбораФайла), приведет к критической ошибке: Тип не определен (ДиалогВыбораФайла). Сервер «не знает», что такое экран пользователя, и не может открыть на нем никакие окна.
Для решения задачи нам необходимо четко разделить ответственность между клиентом (формой) и сервером (модулем объекта). Представим этот процесс по шагам:
Шаг 1. Подготовка процедуры в модуле объекта.
Прежде всего, уберем из модуля объекта любые директивы компиляции (такие как &НаКлиенте). Процедура должна принимать параметры, которые мы получим на клиенте. Например, путь к файлу или адрес во временном хранилище.
// В модуле объекта (ПРАВИЛЬНО)
Процедура РаботаСканПДФ(ПутьКФайлу) Экспорт
// Здесь выполняется только серверная логика
// Например, запуск внешнего приложения через COM-объект или ЗапуститьПриложение()
WshShell = Новый COMОбъект("WScript.Shell");
// ... дальнейшая логика обработки ...
КонецПроцедуры
Шаг 2. Реализация логики в модуле управляемой формы.
На форме нам понадобятся две процедуры: одна клиентская (для диалога) и одна серверная (для связи с объектом).
&НаКлиенте
Процедура Распознать(Команда)
// Работаем на клиенте: выбираем файл
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Диалог.Фильтр = "PDF файлы (*.pdf)|*.pdf";
Если Диалог.Выбрать() Тогда
ПутьКФайлу = Диалог.ПолноеИмяФайла;
// Передаем управление на сервер
РаспознатьНаСервере(ПутьКФайлу);
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура РаспознатьНаСервере(ПутьКФайлу)
// Преобразуем данные формы (Реквизит "Объект") в реальный объект обработки
ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
// Теперь вызываем экспортный метод модуля объекта
ОбработкаОбъект.РаботаСканПДФ(ПутьКФайлу);
// Если нужно сохранить изменения в реквизитах объекта, делаем обратное преобразование
ЗначениеВРеквизитФормы(ОбработкаОбъект, "Объект");
КонецПроцедуры
Важно понимать, что если ваша база работает в клиент-серверном режиме (через сервер приложений 1С), то сервер не имеет прямого доступа к файлам на диске C:\ вашего локального компьютера. В коде выше сервер пытается найти файл по пути, который сообщил клиент. Если сервер 1С установлен на другом физическом компьютере, он выдаст ошибку "Файл не найден".
Проанализируем, как сделать решение универсальным. Правильный подход — передача файла через Временное хранилище:
ПоместитьФайл(). Файл улетает с вашего компьютера в специальную временную папку на сервере.ПолучитьИзВременногоХранилища(Адрес), чтобы получить двоичные данные файла и сохранить их в ПолучитьИмяВременногоФайла() для дальнейшей работы.В примере из обсуждения используется WScript.Shell. Помните, что при выполнении этого кода на сервере:
USR1CV8). У этого пользователя должны быть права на запуск .exe файлов.pdftotext.exe, hstart.exe) должны быть либо прописаны полностью, либо файлы должны быть предварительно извлечены из макетов во временные папки сервера.Сообщить() в модуле объекта на сервере сработает и передаст сообщение пользователю на клиент, но только после завершения серверного вызова.Чтобы успешно вызвать метод модуля объекта, следуйте правилам:
&НаКлиенте в модуле объекта.&НаКлиенте.РеквизитФормыВЗначение("Объект") в серверной процедуре формы.Такой подход не только исправит ошибку Метод не обнаружен, но и сделает вашу обработку стабильной и соответствующей стандартам разработки 1С.