При интеграции сторонних приложений (например, на языке C#) с платформой 1С через механизм COM-соединения (V83.COMConnector) программисты часто сталкиваются с ситуацией, когда код, успешно работающий внутри 1С, внезапно выдает ошибку Метод объекта не обнаружен. Особенно часто это происходит при попытке программного формирования отчетов. Рассмотрим детально, почему это происходит и как правильно настроить конфигурацию для корректной работы.
Когда мы подключаемся к 1С через COM, мы создаем так называемое внешнее соединение. Особенность этого режима заключается в том, что 1С не инициализирует клиентскую часть (формы, диалоги, предупреждения). Если вызываемый метод находится в модуле, который «не виден» для внешнего соединения, или внутри метода используются запрещенные для этого режима конструкции, платформа просто «скрывает» этот метод, сообщая, что он не обнаружен.
В рассматриваемом случае проблема возникает на этапе вызова ОтчетРасчетныеЛисткиОрганизаций.СформироватьОтчет(ТабличныйДокумент). Несмотря на то, что метод в коде 1С помечен как Экспорт, внешнее приложение его не видит.
Прежде всего, проанализируем настройки общего модуля, через который осуществляется вызов. В свойствах каждого общего модуля есть флаги, определяющие его доступность в различных контекстах. Для работы через COM должны быть соблюдены следующие условия:
XXX).ТиповыеОтчеты, у него также должен быть активен флаг Внешнее соединение.Проанализируем ситуацию, когда свойства модуля настроены верно, но ошибка сохраняется. Выясним причину в самом коде. В 1С часто используется препроцессор для разделения кода на клиентский и серверный. Посмотрим на типичную ошибку в начале модуля объекта отчета:
#Если ТолстыйКлиентОбычноеПриложение Тогда
// Код модуля, включая процедуру СформироватьОтчет
Процедура СформироватьОтчет(ТабличныйДокумент) Экспорт
// Логика формирования
КонецПроцедуры
#КонецЕсли
Если в коде стоит такая директива, то при подключении через V83.COMConnector этот блок кода просто не будет скомпилирован. Для системы метода СформироватьОтчет не будет существовать. Нам необходимо расширить доступность кода. Изменим директиву следующим образом:
#Если ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
// Теперь этот код будет доступен и при COM-подключении
Процедура СформироватьОтчет(ТабличныйДокумент) Экспорт
// ...
КонецПроцедуры
#КонецЕсли
Важный нюанс: После этого изменения система может выдать новые ошибки, если внутри процедуры используются методы работы с интерфейсом (например, Предупреждение() или Вопрос()). Их также придется обернуть в проверку #Если Клиент.
Рассмотрим, как выглядит правильная инициализация и вызов функции из C#. Важно правильно передавать параметры и обращаться к свойствам объектов 1С. Проанализируем пример кода:
// Создание COM-соединения
V82Type = Type.GetTypeFromProgID("V83.COMConnector");
_V82Connector = Activator.CreateInstance(V82Type);
V82Base = V82Type.InvokeMember("Connect", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, _V82Connector, new object[] { connectionString });
// Получение общего модуля
object common_module = V82Type.InvokeMember("XXX", BindingFlags.GetProperty, null, V82Base, null);
// Вызов экспортного метода, который внутри себя создает отчет и формирует его
var arg = new object[] { fizioName, date };
string resultBase64 = (string)V82Type.InvokeMember("ОтчетНовый", BindingFlags.InvokeMethod, null, common_module, arg);
В этом сценарии функция ОтчетНовый (или XXX в сообщении 25) должна выглядеть в 1С так:
Функция ОтчетНовый(ФизЛицо, ПериодРегистрации) Экспорт
// Создаем объект отчета программно
ОтчетОбъект = Отчеты.РасчетныеЛисткиОрганизаций.Создать();
// Настраиваем параметры через типовые механизмы
ТиповыеОтчеты.УстановитьПараметр(ОтчетОбъект.КомпоновщикНастроек, "НачалоПериода", НачалоМесяца(ПериодРегистрации));
ТиповыеОтчеты.УстановитьПараметр(ОтчетОбъект.КомпоновщикНастроек, "КонецПериода", КонецМесяца(ПериодРегистрации));
ТабДок = Новый ТабличныйДокумент;
// Вот здесь и происходит падение, если модуль отчета не адаптирован под ВнешнееСоединение
ОтчетОбъект.СформироватьОтчет(ТабДок);
// Сохраняем в файл и возвращаем в виде Base64 для передачи в C#
ТекИмяФайла = КаталогВременныхФайлов() + "report.xls";
ТабДок.Записать(ТекИмяФайла, ТипФайлаТабличногоДокумента.XLS);
ДД_Файла = Новый ДвоичныеДанные(ТекИмяФайла);
СтрокаBase64 = Base64Строка(ДД_Файла);
Возврат СтрокаBase64;
КонецФункции
Рассмотрим еще несколько критических моментов, которые помогут избежать ошибки Метод объекта не обнаружен:
connectionString, должен иметь роль с правом Внешнее соединение. Если права ограничены, многие методы будут недоступны из соображений безопасности.comcntr.dll соответствующей разрядности. Несоответствие разрядности часто приводит к непредсказуемым ошибкам при передаче объектов между процессами.СформироватьОтчет из модуля объекта (который часто перегружен клиентским кодом), попробуйте использовать программный вывод Системы компоновки данных (СКД). Этот метод более надежен для COM-соединений, так как работает напрямую с данными и схемой компоновки, минуя проблемные участки кода модуля объекта.Выясним причину ошибки через проверку конфигурации. В конфигураторе 1С выберите пункт «Сервис» -> «Проверка конфигурации». Обязательно установите галочку Внешнее соединение. Система подсветит все места, где используются недоступные методы или где нарушена логика компиляции для COM-режима. Это самый быстрый способ найти «невидимый» для внешнего мира метод.
Таким образом, решение проблемы кроется в правильном сочетании настроек свойств модулей и корректном использовании директив препроцессора #Если ВнешнееСоединение.