При переходе с файлового режима работы на клиент-серверный или при переносе кода из клиентского контекста в серверный разработчики часто сталкиваются с ошибкой: «Передача мутабельного значения допускается только между локальными контекстами». Особенно остро эта проблема проявляется при работе со старыми конфигурациями, такими как «Управление торговлей, ред. 10.3», при попытке подключить внешнюю компоненту печати штрихкодов.
В этой статье мы подробно разберем, почему возникает данная ошибка, как устроена работа с внешними компонентами в контексте клиент-серверной архитектуры 1С, и рассмотрим практические варианты решения проблемы с готовыми примерами кода.
Для начала проанализируем природу самой ошибки. В терминологии платформы «1С:Предприятие» все типы данных делятся на две категории:
Число, Строка, Булево, Дата, а также ДвоичныеДанные и ссылки на объекты базы данных (СправочникСсылка, ДокументСсылка).СправочникОбъект, ТаблицаЗначений, ТабличныйДокумент и, самое главное в нашем случае, объекты внешних компонент и COM-объекты.Когда мы пишем код вида:
ВнешняяКомпонента = глМодуль.ПодключитьВнешнююКомпонентуПечатиШтрихкода();
и этот вызов происходит из модуля документа (который выполняется на сервере), а результат мы пытаемся вернуть на клиент (или наоборот), платформа пытается передать мутабельный объект внешней компоненты через границу контекстов. В этот момент происходит аварийное завершение операции с ошибкой.
Как совершенно справедливо заметили участники обсуждения, сам вызов подключения внутри общего модуля возвращает созданный экземпляр компоненты (тип AddIn...), который физически не может пересечь границу «клиент-сервер».
---
Если печатная форма документа формируется на сервере, то правильным архитектурным решением будет локализовать всю работу с внешней компонентой внутри серверного контекста. Компонента должна быть подключена на сервере, там же должна быть сгенерирована картинка штрихкода, а на клиент должны быть переданы только готовые двоичные данные этой картинки. Двоичные данные не являются мутабельными и прекрасно передаются между контекстами.
Рассмотрим по шагам, как реализовать этот механизм:
Шаг 1. Создаем экспортную функцию на сервере для получения картинки
В серверном общем модуле (например, глМодуль) создаем функцию, которая подключает компоненту, формирует штрихкод и возвращает его двоичные данные:
Функция ПолучитьДвоичныеДанныеШтрихкода(ЗначениеШтрихкода, Ширина, Высота) Экспорт
// 1. Подключаем внешнюю компоненту
ИмяМакета = "ОбщийМакет.КомпонентаПечатиШтрихкодовWindows32";
Если Не ПодключитьВнешнююКомпоненту(ИмяМакета, "КартинкаШтрихкода", ТипВнешнейКомпоненты.Native) Тогда
ВызватьИсключение "Не удалось подключить внешнюю компоненту печати штрихкодов!";
КонецЕсли;
// 2. Создаем объект компоненты
Попытка
ВнешняяКомпонента = Новый("AddIn.КартинкаШтрихкода.Barcode");
Исключение
ВызватьИсключение "Не удалось создать объект внешней компоненты!";
КонецПопытки;
// 3. Настраиваем параметры штрихкода
ВнешняяКомпонента.Сообщение = СокрЛП(ЗначениеШтрихкода);
ВнешняяКомпонента.Ширина = Ширина;
ВнешняяКомпонента.Высота = Высота;
ВнешняяКомпонента.ТипКода = 1; // Например, EAN13
// 4. Получаем картинку штрихкода.
// Предположим, компонента умеет возвращать макет или картинку.
// Извлекаем двоичные данные полученной картинки:
ОбъектКартинка = ВнешняяКомпонента.ПолучитьКартинку();
ДвоичныеДанныеКартинки = ОбъектКартинка.ПолучитьДвоичныеДанные();
// Возвращаем немутабельный тип данных
Возврат ДвоичныеДанныеКартинки;
КонецФункции
Шаг 2. Получаем и отображаем картинку на клиенте
В модуле формы (на клиенте) или в процедуре печати мы вызываем эту функцию и преобразуем двоичные данные обратно в объект Картинка для вывода в табличный документ:
Процедура ВывестиШтрихкодНаПечать(ОбластьМакета, ЗначениеШтрихкода)
// Вызываем серверный метод, получаем немутабельные двоичные данные
ДвоичныеДанныеКартинки = глМодуль.ПолучитьДвоичныеДанныеШтрихкода(ЗначениеШтрихкода, 300, 100);
// Создаем объект Картинка из двоичных данных прямо на клиенте
КартинкаШтрихкода = Новый Картинка(ДвоичныеДанныеКартинки);
// Вставляем картинку в рисунок табличного документа
Рисунок = ОбластьМакета.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Картинка);
Рисунок.Картинка = КартинкаШтрихкода;
КонецПроцедуры
---
Если ваша конфигурация «Управление торговлей 10.3» работает исключительно в режиме обычного приложения (где тонкий клиент не используется, а весь код по сути выполняется на клиенте в рамках одного процесса), то ошибка передачи мутабельных значений часто возникает из-за путаницы в свойствах общих модулей.
Проанализируем свойства общего модуля глМодуль. Скорее всего, для него установлены флаги «Сервер» и «Вызов сервера», но снят флаг «Клиент (обычное приложение)». При вызове функций такого модуля происходит неявный переход контекста на сервер.
Чтобы решить проблему без переписывания логики формирования картинок, выполним следующие шаги:
глМодуль (или того модуля, где объявлена функция подключения компоненты).ВнешняяКомпонента будет успешно создан и использован локально в памяти клиентского приложения.---
При переносе генерации штрихкодов на сервер в клиент-серверном варианте (SQL) вы можете столкнуться с еще одной классической проблемой: несовместимость разрядностей.
Старая компонента печати штрихкодов 1С (1CBarCode) поставлялась как 32-разрядное приложение (ActiveX/COM). Если сервер «1С:Предприятия» у вас установлен в 64-разрядной версии (что сейчас является стандартом), попытка выполнить метод ПодключитьВнешнююКомпоненту() на сервере завершится ошибкой, так как 64-битный рабочий процесс сервера (rphost.exe) не сможет загрузить 32-битный код библиотеки.
Как решить проблему с разрядностью:
ПодключитьВнешнююКомпоненту() автоматически распознает операционную систему и разрядность текущего процесса и загрузит нужный бинарный файл без участия разработчика.Пример подключения Native API компоненты из макета:
// Подключение Native-компоненты, сохраненной в общем макете как двоичные данные
РезультатПодключения = ПодключитьВнешнююКомпоненту("ОбщийМакет.КомпонентаПечатиШтрихкодов", "Barcode", ТипВнешнейКомпоненты.Native);
Таким образом, соблюдая правила разделения контекстов и используя современные кроссплатформенные компоненты, мы полностью исключаем появление ошибок мутабельности и обеспечиваем стабильную и быструю печать этикеток и документов со штрихкодами в любых режимах работы системы.