Работа с торговым оборудованием, таким как считыватели магнитных или бесконтактных карт (RFID), часто требует использования внешних компонент (DLL). В среде 1С:Предприятие 8.3 при переходе на управляемые формы программисты часто сталкиваются с ситуацией, когда код, успешно работавший в обычном приложении, перестает вызывать процедуру ВнешнееСобытие. Рассмотрим подробно, почему это происходит и как правильно организовать работу со считывателем в современном интерфейсе.
Проанализируем типичную ошибку начинающего разработчика. В процедуре ПриСозданииНаСервере или ПриОткрытии создается объект внешней компоненты и помещается в локальную переменную. Как только выполнение процедуры завершается, локальная переменная выходит из области видимости, и система 1С (а точнее, Garbage Collector) уничтожает объект. Если объект уничтожен, он не может «слушать» COM-порт и генерировать события для платформы.
Выясним причину, по которой нельзя использовать стандартные реквизиты формы. При попытке записать объект внешней компоненты в реквизит формы с типом Произвольный, система выдаст ошибку: «Тип не может использоваться в данных формы». Это связано с тем, что данные управляемой формы должны быть сериализуемыми для передачи между клиентом и сервером, а живой объект COM или Native API компоненты передать таким образом невозможно.
Для того чтобы объект компоненты жил в течение всего времени работы с формой, мы должны объявить переменную в самом верху модуля формы, обязательно указав директиву &НаКлиенте. Это создаст клиентскую переменную модуля, которая будет доступна всем процедурам формы на стороне клиента и не будет уничтожена до закрытия окна.
Рассмотрим пример правильного объявления:
&НаКлиенте
Перем ДемоКомп; // Переменная модуля, сохраняющая ссылку на объект
Ранее компоненты регистрировались в системе через regsvr32 или загружались напрямую с диска по жесткому пути (например, C:\ZR1C.dll). В современных версиях 1С 8.3 рекомендуется хранить компоненты в макетах конфигурации (в виде ZIP-архива с манифестом) и использовать асинхронные методы подключения. Это избавляет от проблем с правами доступа к локальным дискам и автоматизирует установку драйвера у пользователя.
Разберем по шагам реализацию подключения в событии ПриОткрытии:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Подготавливаем оповещение о завершении установки/подключения
Оповещение = Новый ОписаниеОповещения("ПослеПодключенияКомпоненты", ЭтаФорма);
// Пытаемся установить компоненту из макета конфигурации
НачатьУстановкуВнешнейКомпоненты(Оповещение, "ОбщийМакет.ДрайверСчитывателя");
КонецПроцедуры
Проанализируем процедуру обратного вызова, где происходит непосредственное создание объекта и инициализация оборудования:
&НаКлиенте
Процедура ПослеПодключенияКомпоненты(Результат, ДополнительныеПараметры) Экспорт
Если Результат = РезультатУстановкиВнешнейКомпоненты.Установлено Тогда
// Подключаем саму библиотеку под программным псевдонимом
Если ПодключитьВнешнююКомпоненту("ОбщийМакет.ДрайверСчитывателя", "ScanerRFID", ТипВнешнейКомпоненты.Native) Тогда
// Создаем экземпляр объекта в переменную модуля
ДемоКомп = Новый("AddIn.ScanerRFID.ZR1CExtension");
// Настройка параметров порта
ДемоКомп.Порт = "Com3";
DevID = Неопределено;
// Активация порта
Если ДемоКомп.Подключить(DevID) Тогда
Сообщить("Считыватель успешно подключен на порту " + ДемоКомп.Порт);
КонецЕсли;
Иначе
Сообщить("Не удалось подключить внешнюю компоненту.");
КонецЕсли;
КонецЕсли;
КонецПроцедуры
После того как мы обеспечили «выживаемость» объекта ДемоКомп, внешнее событие начнет поступать в форму. Однако важно убедиться, что в свойствах самой управляемой формы (в палитре свойств) в строке «Внешнее событие» указано имя нашей процедуры-обработчика.
Посмотрим на пример обработки полученных данных:
&НаКлиенте
Процедура ВнешнееСобытие(Источник, Событие, Данные)
// Источник — обычно имя компоненты (ScanerRFID)
// Событие — тип действия (например, "CardRead")
// Данные — считанный код карты
Сообщить("Получены данные от оборудования!");
Сообщить("Источник: " + Источник);
Сообщить("Код карты: " + Данные);
// Здесь можно вызвать серверную процедуру для поиска сотрудника по коду карты
НайтиСотрудникаПоКарте(Данные);
КонецПроцедуры
Ситуация, когда тонкий клиент 1С аварийно завершает работу при обращении к DLL, — не редкость. Рассмотрим основные причины:
ZR1C.dll скомпилирована только под 32 бита (x86), произойдет конфликт. Необходимо либо использовать 32-битный клиент 1С, либо найти 64-битную версию компоненты.Подключить() может привести к ошибке доступа к памяти (Access Violation), что «уронит» платформу.Поскольку мы создали объект, который монопольно захватывает COM-порт, крайне важно освобождать его при закрытии формы. Если этого не сделать, порт может остаться в состоянии «занят» даже после закрытия окна 1С, и повторное открытие формы выдаст ошибку подключения.
Рекомендуем добавить следующий код:
&НаКлиенте
Процедура ПередЗакрытием(Отказ, ЗавершениеРаботы, ТекстПредупреждения, СтандартнаяОбработка)
Если ДемоКомп <> Неопределено Тогда
ДемоКомп.Отключить(); // Метод зависит от конкретной DLL
ДемоКомп = Неопределено;
КонецЕсли;
КонецПроцедуры
Подводя итог, отметим: секрет стабильной работы с внешними событиями в управляемых формах заключается в правильном управлении областью видимости переменной и использовании асинхронной загрузки. Следуя этим правилам, вы обеспечите надежную интеграцию любого торгового оборудования в ваши решения на базе 1С.