Как вызвать клиентский модуль управляемого приложения из управляемой формы в обычном приложении?

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

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

Суть проблемы и контекст запуска

Рассмотрим сценарий: у нас есть конфигурация, запускаемая в режиме Обычное приложение (Толстый клиент). В свойствах конфигурации установлен флаг, разрешающий использование управляемых форм. Мы создали новую управляемую форму (УФ) и попытались вызвать из нее процедуру экспортного общего модуля.

Пример кода в модуле управляемой формы:


&НаКлиенте
Процедура ТекШтрихкодПриИзменении(Элемент)
    // Попытка вызова функции из общего модуля
    нКлиент.ВоспроизвестиЗвук(3);
КонецПроцедуры

При выполнении этого кода (или даже при синтаксическом контроле) платформа выдает ошибку:

{Документ.Инвентаризация.Форма.ФормаДокумента.Форма(87,2)}: Переменная не определена (нКлиент)

На первый взгляд это кажется странным. Ведь модуль нКлиент существует, процедура в нем помечена как Экспорт, и вызов происходит из процедуры с директивой &НаКлиенте. Почему платформа не «видит» этот модуль?

Причина: Особенности компиляции модулей

Чтобы понять причину, нам нужно разобраться, как платформа 1С:Предприятие загружает контекст приложения.

  1. Когда мы запускаем Толстый клиент (Обычное приложение), платформа компилирует и загружает в оперативную память только те общие модули, которые помечены флагом Клиент (обычное приложение).
  2. Если у общего модуля стоит только флаг Клиент (управляемое приложение), платформа считает, что этот модуль нужен только для Тонкого клиента или Веб-клиента. В сеансе обычного приложения этот модуль просто отсутствует в глобальном контексте.
  3. Управляемая форма, открытая внутри обычного приложения, «живет» внутри процесса толстого клиента. Хотя логика формы (директивы &НаКлиенте) исполняется по правилам управляемого приложения, доступ к глобальным объектам (общим модулям) ограничивается тем, что загружено в текущий процесс.

Таким образом, переменная не найдена не потому, что форма «не видит» модуль, а потому что модуль физически не скомпилирован в текущем сеансе работы пользователя.

Решение проблемы: Настройка свойств общего модуля

Чтобы исправить эту ошибку, нам необходимо явно указать платформе, что данный общий модуль должен быть доступен в контексте обычного приложения. Выполним следующие действия в Конфигураторе:

  1. Найдем в дереве метаданных нужный Общий модуль (в нашем примере это нКлиент).
  2. Откроем палитру свойств этого модуля (нажав Alt+Enter или через контекстное меню).
  3. Найдем группу свойств, отвечающих за контекст компиляции.
  4. Установим флажок Клиент (обычное приложение).

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

Правильная комбинация флагов для гибридных конфигураций

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

Рекомендуется устанавливать следующую комбинацию для чисто клиентских модулей:

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

Использование инструкций препроцессора

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

Для разделения кода используем инструкции препроцессора. Разберем пример безопасного оформления кода:


Процедура ПоказатьСообщениеПользователю(Текст) Экспорт
    
#Если ТонкийКлиент Или ТолстыйКлиентУправляемоеПриложение Тогда
    // Код для управляемого режима
    ПоказатьОповещениеПользователя("Информация", , Текст);
#ИначеЕсли ТолстыйКлиентОбычноеПриложение Тогда
    // Код для обычного режима (если нужен специфичный функционал)
    Сообщить(Текст);
#КонецЕсли

КонецПроцедуры

Однако в контексте рассматриваемой проблемы (вызов из управляемой формы, открытой в обычном приложении) код, написанный для управляемого приложения, как правило, отрабатывает корректно, так как форма сама по себе является управляемой. Главное — обеспечить видимость самого модуля («контейнера» процедур).

Особенности режима совместимости

В теме также упоминался старый режим совместимости (Версия 8.2.13). Это важный нюанс. В старых режимах совместимости (ниже 8.3.x) механизмы изоляции кода работают более жестко.

Если вы работаете в режиме совместимости с версией 8.2, убедитесь, что:

  1. В модуле формы корректно используются директивы компиляции: &НаКлиенте, &НаСервере.
  2. В общем модуле флаг Клиент (обычное приложение) установлен обязательно.

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

Резюме

Если при вызове общего модуля из управляемой формы вы получаете ошибку о том, что переменная не найдена, в 99% случаев проблема кроется в настройках компиляции общего модуля. Убедитесь, что для текущего режима запуска (Толстый клиент) разрешена компиляция этого модуля, установив флаг Клиент (обычное приложение).

← На главную