Почему функция Вопрос() не работает в общем модуле и как исправить ошибку «Процедура или функция не определена»

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

При разработке в системе «1С:Предприятие 8» программисты часто сталкиваются с ситуацией, когда код, написанный в одном месте, отказывается работать в другом. Типичный пример: вызов интерактивного диалога через функцию Вопрос(). Вроде бы код написан правильно, синтаксическая проверка не выдает ошибок, но при запуске системы программа «вылетает» с системной ошибкой: «Процедура или функция с указанным именем не определена (Вопрос)». Особенно часто это происходит при попытке вынести логику проверки во внешний общий модуль, вызываемый из процедуры ПриНачалеРаботыСистемы.

В данной статье мы подробно разберем, почему возникает эта проблема, как работает механизм компиляции в 1С и какими способами можно обеспечить корректную работу интерактивных функций в общих модулях.

Разберем причину: конфликт контекстов исполнения

Главная причина возникновения ошибки — разделение контекстов исполнения кода. Платформа 1С четко разделяет код, который выполняется на стороне клиента (там, где есть графический интерфейс, монитор и мышь пользователя), и код, который выполняется на стороне сервера (где нет интерфейса, а есть только база данных и вычислительные мощности).

Функция Вопрос() является интерактивной. Она требует взаимодействия с пользователем: отрисовки окна, ожидания клика по кнопке. Следовательно, эта функция физически существует только в клиентском приложении. На сервере этой функции нет, сервер «не знает», как рисовать окна и ждать ответа человека. Если платформа пытается скомпилировать или выполнить код с функцией Вопрос() в контексте сервера, она сообщает, что такая функция не определена.

Шаг 1. Анализ свойств общего модуля

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

Обратите внимание на следующие флажки в палитре свойств:

Если у вас одновременно стоят галочки «Клиент» и «Сервер», платформа пытается скомпилировать этот модуль для обоих контекстов. В момент компиляции «для сервера» интерпретатор натыкается на слово Вопрос() и выдает ошибку, так как для серверной части это «незнакомое слово».

Шаг 2. Использование директив препроцессора

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

Рассмотрим, как правильно оформить вызов диалога в общем модуле, чтобы избежать ошибки:


#Если Клиент Тогда
    // Этот блок кода будет виден только на стороне клиента
    Режим = РежимДиалогаВопрос.ДаНет;
    ТекстВопроса = "Вы уверены, что хотите продолжить проверку ХУ?";
    Ответ = Вопрос(ТекстВопроса, Режим);
    
    Если Ответ = КодВозвратаДиалога.Нет Тогда
        Возврат;
    КонецЕсли;
#КонецЕсли

Используя конструкцию #Если Клиент Тогда ... #КонецЕсли, мы гарантируем, что серверная часть платформы просто «пропустит» эти строки при компиляции, и ошибка «Процедура или функция не определена» исчезнет.

Шаг 3. Особенности процедуры ПриНачалеРаботыСистемы

Проанализируем ситуацию, описанную в теме: вызов идет из модуля обычного приложения из события ПриНачалеРаботыСистемы(). Само это событие всегда выполняется на клиенте. Однако, если процедура ПроверкаХУ() расположена в модуле с установленным флагом «Сервер», ошибка все равно может возникнуть в момент инициализации модуля.

Важный совет: Старайтесь разделять логику. Если процедура предполагает интерактивное общение с пользователем (вопросы, предупреждения), лучше размещать её в модулях, предназначенных только для клиента, либо жестко ограничивать интерфейсные вызовы директивами препроцессора. Размещение Вопрос() в серверном модуле без директив считается грубым нарушением стандартов разработки фирмы «1С».

Шаг 4. Внешнее соединение и фоновые задания

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

Аналогично обстоит дело с фоновыми заданиями. Они всегда выполняются на сервере. Если ваша процедура ПроверкаХУ() будет вызвана из регламентного задания ночью, когда никакого пользователя за компьютером нет, функция Вопрос() приведет к немедленной остановке выполнения задания с ошибкой.

Шаг 5. Современный подход: Асинхронность и отказ от модальности

Если вы планируете в будущем переходить на управляемые формы или обновлять платформу до актуальных версий (8.3.3 и выше), следует помнить о свойстве конфигурации «Режим использования модальности». В режиме «Не использовать» классическая функция Вопрос() перестает работать даже на клиенте!

Вместо неё рекомендуется использовать асинхронный метод ПоказатьВопрос(). Рассмотрим пример:


// Пример для управляемого приложения или режима без модальности
ОписаниеОповещения = Новый ОписаниеОповещения("ПослеЗакрытияВопроса", ЭтотОбъект);
ПоказатьВопрос(ОписаниеОповещения, "Продолжить выполнение операции?", РежимДиалогаВопрос.ДаНет);

// Отдельная процедура для обработки ответа
&НаКлиенте
Процедура ПослеЗакрытияВопроса(Результат, ДополнительныеПараметры) Экспорт
    Если Результат = КодВозвратаДиалога.Да Тогда
        // Продолжаем логику
    КонецЕсли;
КонецПроцедуры

Хотя в обычном приложении (о котором шла речь в исходном вопросе) модальность чаще всего разрешена, использование правильных контекстных проверок и понимание того, где «живет» Вопрос(), поможет вам писать стабильный и качественный код.

Подведем итоги

Для решения проблемы выполните следующие действия:

  1. Проверьте свойства общего модуля. Если там стоит галочка «Сервер», убедитесь, что вызовы Вопрос(), Предупреждение() или Сообщить() (в некоторых случаях) корректно обрамлены препроцессором.
  2. Если модуль предназначен только для клиентских действий в обычном приложении, снимите флаг «Сервер» и оставьте только «Клиент (обычное приложение)».
  3. Всегда помните: сервер не может спрашивать. Если серверу нужны данные от пользователя, их нужно получить на клиенте до вызова серверной процедуры и передать в неё в качестве параметров.
← На главную