Ошибка "Процедура или функция не определена" при COM-соединении и использовании расширений: причины и решение

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При интеграции информационных баз 1С через COM-соединение (V83.COMConnector) разработчики часто сталкиваются с неочевидными ошибками. Одна из самых коварных ситуаций — когда код отлично работает в режиме Предприятия (Тонкий/Толстый клиент), но падает с ошибкой при вызове через внешнее соединение, даже если визуально все необходимые галочки в свойствах модулей установлены. Рассмотрим подробно проблему, когда при вызове экспортной функции общего модуля возникает ошибка обращения к внутренней (неэкспортной) функции, и разберем, почему расширение конфигурации может не помогать в "лоб".

Суть проблемы

Представим ситуацию: у нас есть внешняя обработка или скрипт, который подключается к базе 1С через COM-соединение для создания документов. В процессе работы вызывается экспортная процедура из общего модуля.

Структура общего модуля в основной конфигурации выглядит следующим образом:


// Общий модуль: РаботаСДокументами (Галочки: Сервер, Внешнее соединение)

Функция СоздатьДокумент() Экспорт    
   // Вызов внутренней служебной функции
   Возврат ПолучитьДанныеДляДокумента();
КонецФункции

&НаСервере
Функция ПолучитьДанныеДляДокумента()
   // Логика получения данных
   Возврат Результат;
КонецФункции

При попытке выполнить метод СоздатьДокумент() через COM-соединение платформа возвращает ошибку:

Ошибка: Процедура или функция с указанным именем не определена (ПолучитьДанныеДляДокумента)

Разработчик пытается исправить ситуацию, создав расширение конфигурации и переопределив методы, но ошибка сохраняется. Давайте разберем, почему это происходит и как это исправить.

Анализ контекста компиляции

Чтобы понять причину ошибки, нам нужно вспомнить, как платформа компилирует модули в разных режимах запуска.

  1. Контекст COM-соединения: Это сеанс, который инициируется через V83.COMConnector. Для платформы это режим "Внешнее соединение".
  2. Свойства общего модуля: Для того чтобы модуль был виден в COM, у него должен быть установлен флаг "Внешнее соединение".
  3. Директивы компиляции: Внутри модуля могут использоваться директивы (аннотации) перед методами, такие как &НаСервере, &НаКлиенте и т.д.

В нашем примере у внутренней функции ПолучитьДанныеДляДокумента стоит директива &НаСервере.

В чем подвох?
Директива &НаСервере указывает платформе, что данный метод должен быть скомпилирован и доступен в контексте сервера (когда работает сервер 1С предприятия для тонкого/толстого клиента). Однако контекст Внешнего соединения отличается от контекста Сервера.

Когда платформа выполняет синтаксический контроль модуля в режиме внешнего соединения, она видит директиву &НаСервере и, в зависимости от настроек платформы и версии, может "вырезать" этот метод из компилируемого образа модуля для внешнего соединения, так как считает, что этот метод предназначен только для классического серверного вызова.

В итоге получается ситуация: 1. Экспортная функция СоздатьДокумент компилируется (так как она "общая" и доступна в контексте модуля). 2. Внутренняя функция ПолучитьДанныеДляДокумента исключается из контекста из-за директивы &НаСервере. 3. При попытке вызова первая функция не находит вторую. Происходит ошибка компиляции модуля или ошибка времени выполнения.

Почему не помогает расширение?

Частая попытка решения — сделать расширение и переопределить методы через аннотацию &Вместо, добавив Экспорт или убрав директивы.

Однако, если основной модуль конфигурации не проходит синтаксический контроль в контексте текущего соединения (в нашем случае COM), платформа может вообще не загрузить этот модуль или не применить к нему расширение корректно. Платформа сначала пытается "собрать" основной модуль. Если в нем есть логическая дыра (вызов несуществующей для данного контекста функции), то расширение, которое пытается перехватить этот вызов, просто не сработает, потому что базовый код уже "сломан".

Решение 1: Использование директив препроцессора (Рекомендуемое)

Самый надежный способ решить проблему, не меняя глобально логику работы конфигурации — использовать инструкции препроцессора. Нам нужно явно указать платформе, какой код должен выполняться в режиме внешнего соединения.

Если вы не можете менять основную конфигурацию, но можете использовать расширение, вам нужно изолировать вызов проблемной функции.

В расширении:

Мы можем перехватить вызов экспортной функции и написать свою реализацию, которая будет работать корректно в COM-соединении.


&Вместо("СоздатьДокумент")
Функция Расш_СоздатьДокумент() Экспорт
    
    #Если ВнешнееСоединение Тогда
        // Здесь пишем код специально для COM, избегая вызова 
        // функций с директивой &НаСервере, если они недоступны.
        // Либо дублируем логику получения данных.
        Возврат СвояФункцияПолученияДанных();
    #Иначе
        // В обычном режиме продолжаем вызывать стандартный метод
        Возврат ПродолжитьВызов(); 
    #КонецЕсли

КонецФункции

Решение 2: Исправление основной конфигурации

Если у вас есть возможность вносить изменения в основную конфигурацию (или вы разрабатываете её сами), то правильным подходом будет корректная расстановка директив.

Для методов, которые должны работать и на Сервере (в сеансе пользователя), и во Внешнем соединении (COM), не следует ставить директиву &НаСервере, если у самого общего модуля уже стоят галочки "Сервер" и "Внешнее соединение". Методы без директив внутри такого модуля автоматически становятся доступными во всех контекстах, отмеченных в свойствах модуля.

Правильный код общего модуля:


// Свойства модуля: [x] Сервер, [x] Внешнее соединение

Функция СоздатьДокумент() Экспорт    
   Возврат ПолучитьДанныеДляДокумента();
КонецФункции

// Убираем директиву &НаСервере, так как она ограничивает видимость
// Функция теперь доступна и на Сервере, и во Внешнем соединении
Функция ПолучитьДанныеДляДокумента()
   Возврат Результат;
КонецФункции

Решение 3: Проверка Безопасного режима расширения

Иногда проблема кроется не в коде, а в правах расширения. Если расширение подключено, но методы не подменяются в COM-соединении, проверьте флаг Безопасный режим.

  1. Откройте конфигуратор или режим Предприятия (Все функции -> Стандартные -> Управление расширениями конфигурации).
  2. Найдите ваше расширение.
  3. Убедитесь, что галочка "Безопасный режим" снята.

В безопасном режиме расширениям часто запрещено выполнение серверного кода или переопределение определенных методов, что критично для COM-соединения.

Выводы и рекомендации

Подведем итог, как избежать подобных проблем в будущем:

  1. Если вы пишете код для COM-соединения, всегда помните, что контекст ExternalConnection отличается от контекста Server.
  2. Избегайте использования директивы &НаСервере внутри общих модулей, у которых установлена галочка "Внешнее соединение", для функций, которые должны вызываться через COM. Оставляйте такие функции без аннотаций.
  3. При разработке расширений для COM используйте директивы препроцессора #Если ВнешнееСоединение Тогда, чтобы отделить логику интеграции от логики интерактивной работы.
  4. Всегда проверяйте синтаксис модуля (Ctrl+F7) с включенной проверкой для режима "Внешнее соединение". Это поможет выявить "невидимые" процедуры до того, как вы столкнетесь с ошибкой в runtime.
← На главную