В платформе 1С:Предприятие 7.7 отсутствует современный встроенный механизм мгновенных push-уведомлений, к которому привыкли разработчики на платформе 1С 8.3. Тем не менее, задача оперативного информирования пользователей (например, о необходимости выйти из базы для проведения монопольного обновления или о получении нового заказа) возникает регулярно.
В данной статье мы подробно разберем, как спроектировать и реализовать систему обмена сообщениями в «семерке». Мы проанализируем различные подходы — от самых простых файловых флагов при запуске системы до использования справочников, периодических таймеров, недокументированных функций платформы и внешних компонент.
---
Если вам не требуется мгновенная доставка сообщений в режиме реального времени, а достаточно лишь показать важное уведомление в момент, когда пользователь открывает программу, можно использовать простой файловый метод. Этот способ не создает никакой нагрузки на базу данных в процессе работы.
Рассмотрим алгоритм реализации по шагам. Отправитель записывает текстовый файл, имя которого соответствует имени получателя, в специальный сетевой каталог. При запуске программы система проверяет наличие файла для текущего пользователя, считывает его, выводит на экран и удаляет.
Разберем пример кода для отправки сообщения:
Процедура ОтправитьФайловоеСообщение(ИмяПолучателя, ТекстСообщения)
// Задаем каталог для хранения временных файлов сообщений
КаталогСообщений = КаталогИБ() + "ExtFiles\Messages\";
// Проверяем существование каталога, если его нет — создаем
Если ФС.СуществуетФайл(КаталогСообщений) = 0 Тогда
ФС.СоздатьКаталог(КаталогСообщений);
КонецЕсли;
// Имя файла будет соответствовать имени пользователя в системе
ИмяФайла = КаталогСообщений + СокрЛП(ИмяПолучателя) + ".txt";
Текст = СоздатьОбъект("Текст");
Текст.ДобавитьСтроку(ТекстСообщения);
Попытка
Текст.Записать(ИмяФайла);
Сообщить("Сообщение для пользователя " + ИмяПолучателя + " успешно отправлено.");
Исключение
Предупреждение("Не удалось отправить сообщение! Возможно, файл заблокирован.");
КонецПопытки;
КонецПроцедуры
Теперь проанализируем код, который необходимо разместить в глобальном модуле в предопределенной процедуре ПриНачалеРаботыСистемы() для приема сообщения:
Процедура ПриНачалеРаботыСистемы()
// ... существующий код начала работы ...
// Проверяем наличие сообщений для текущего пользователя
КаталогСообщений = КаталогИБ() + "ExtFiles\Messages\";
ИмяФайла = КаталогСообщений + СокрЛП(ИмяПользователя()) + ".txt";
Если ФС.СуществуетФайл(ИмяФайла) = 1 Тогда
Текст = СоздатьОбъект("Текст");
Попытка
Текст.Открыть(ИмяФайла);
КолСтрок = Текст.КоличествоСтрок();
Если КолСтрок > 0 Тогда
СтрокаСообщения = "";
Для Ном = 1 По КолСтрок Цикл
СтрокаСообщения = СтрокаСообщения + Текст.ПолучитьСтроку(Ном) + РазделительСтрок;
КонецЦикла;
// Выводим сообщение пользователю
Предупреждение("Вам оставлено системное сообщение:" + РазделительСтрок + СтрокаСообщения);
КонецЕсли;
// После прочтения обязательно удаляем файл, чтобы сообщение не выводилось повторно
ФС.УдалитьФайл(ИмяФайла);
Исключение
// Обработка возможных ошибок блокировки файла при чтении/удалении
ЗаписьЖурналаРегистрации("Ошибка чтения файла сообщения: " + ИмяФайла, "Система", "Ошибка", 3);
КонецПопытки;
КонецЕсли;
КонецПроцедуры
---
Если сообщения должны приходить пользователям непосредственно во время их работы в программе, нам понадобится периодический опрос базы данных. Для этого отлично подойдет связка из служебного справочника и штатного метода ОбработкаОжидания().
Выясним, как это реализовать:
СообщенияПользователям.Получатель (тип: Строка, длина 50) — для хранения имени адресата.Отправитель (тип: Строка, длина 50) — имя того, кто отправил сообщение.ТекстСообщения (тип: Строка, неограниченной длины).Прочитано (тип: Число, длина 1, для флага прочтения).В глобальном модуле настроим периодический запуск процедуры проверки новых записей. В процедуру ПриНачалеРаботыСистемы() добавим вызов обработчика ожидания:
Процедура ПриНачалеРаботыСистемы()
// Запускаем проверку каждые 60 секунд (интервал можно регулировать)
ОбработкаОжидания("глПроверитьНовыеСообщения", 60);
КонецПроцедуры
Затем в самом Глобальном модуле опишем процедуру проверки сообщений. Обратите внимание на директиву Экспорт, она обязательна для процедур, вызываемых через обработку ожидания:
Процедура глПроверитьНовыеСообщения() Экспорт
// Создаем объект справочника для поиска непрочитанных сообщений
Спр = СоздатьОбъект("Справочник.СообщенияПользователям");
// Настраиваем выборку по реквизитам.
// Поскольку в 7.7 нет полноценных SQL-запросов "на лету" без сторонних ВК,
// выполним перебор элементов (или можно использовать метод НайтиПоРеквизиту)
Спр.ВыбратьЭлементы();
Пока Спр.ПолучитьЭлемент() = 1 Цикл
Если (ВРег(СокрЛП(Спр.Получатель)) = ВРег(СокрЛП(ИмяПользователя()))) И (Спр.Прочитано = 0) Тогда
// Получаем текст сообщения
ТекстУведомления = "Сообщение от " + СокрЛП(Спр.Отправитель) + ":" + РазделительСтрок + Спр.ТекстСообщения;
// Помечаем как прочитанное перед выводом окна, чтобы избежать зацикливания
Спр.Прочитано = 1;
Спр.Записать();
// Показываем сообщение пользователю
Предупреждение(ТекстУведомления);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Важное предупреждение: Использование стандартного метода Предупреждение() имеет существенный недостаток. Это модальное окно. Если пользователь отошел от компьютера, а ему пришло сообщение, модальное окно заблокирует выполнение кода 1С. В результате программа не сможет выполнять другие фоновые задачи, а при необходимости административного завершения работы сессия этого пользователя зависнет.
---
Мало кто знает, что помимо глобального метода ОбработкаОжидания(), в 1С 7.7 существует локальный недокументированный метод контекста формы — Форма.ОбработкаОжидания().
Давайте проанализируем его особенности и преимущества перед глобальным аналогом:
Посмотрим на пример использования в модуле конкретной формы:
Процедура ПриОткрытии()
// Запуск локального обработчика ожидания
// Первый параметр — имя процедуры модуля данной формы, второй — интервал в секундах
Форма.ОбработкаОжидания("ПроверитьЛокальныеУведомления", 30);
КонецПроцедуры
Процедура ПроверитьЛокальныеУведомления()
// Код проверки входящих сообщений конкретно для этого рабочего места
// ...
// Если нужно отключить таймер программно, передаем интервал 0:
// Форма.ОбработкаОжидания("ПроверитьЛокальныеУведомления", 0);
КонецПроцедуры
---
Для создания профессиональных решений обмена сообщениями без перегрузки сети и базы данных постоянными запросами разработчики часто используют внешнюю компоненту FormEx.
FormEx позволяет взводить системные таймеры Windows, которые по истечении времени не замораживают интерфейс программы, а генерируют штатное событие 1С ОбработкаВнешнегоСобытия(). Это полностью решает проблему «зависания» интерфейса.
Рассмотрим, как это работает на практике:
FormEx.dll.глОбработкаВнешнегоСобытия() глобального модуля.Пример реализации в Глобальном модуле:
Процедура ПриНачалеРаботыСистемы()
Если ЗагрузитьВнешнююКомпоненту("FormEx.dll") = 1 Тогда
Сервис = СоздатьОбъект("Сервис");
// Взводим таймер с идентификатором "MessageTimer" на 60000 миллисекунд (1 минута)
Сервис.ВзвестиТаймер("MessageTimer", 60000);
Иначе
Сообщить("Не удалось загрузить FormEx! Быстрые сообщения недоступны.", "!");
EndIf;
КонецПроцедуры
Процедура глОбработкаВнешнегоСобытия(Источник, Событие, Данные) Экспорт
Если (Источник = "Таймер") И (Событие = "MessageTimer") Тогда
// Здесь мы пишем код быстрой проверки файлов сообщений или справочника
// Так как это внешнее событие, оно не прерывает активный ввод пользователя
КаталогСообщений = КаталогИБ() + "ExtFiles\Messages\";
ИмяФайла = КаталогСообщений + СокрЛП(ИмяПользователя()) + ".txt";
Если ФС.СуществуетФайл(ИмяФайла) = 1 Тогда
// Найдено новое сообщение!
// Для неблокирующего показа можно применить альтернативный вывод (см. Решение 5)
// ... код обработки сообщения ...
КонецЕсли;
КонецЕсли;
КонецПроцедуры
---
Чтобы решить проблему модальности стандартного окна Предупреждение(), о которой предупреждали опытные разработчики в обсуждении, мы можем использовать системный COM-объект операционной системы Windows — WScript.Shell и его метод Popup.
Метод Popup позволяет выводить на экран стандартное диалоговое окно Windows, но с жестко заданным таймаутом отображения. Если пользователь отошел от компьютера и не нажал кнопку «ОК», окно автоматически закроется через указанное количество секунд, разблокировав сессию 1С.
Посмотрим на пример универсальной процедуры показа неблокирующего сообщения:
Процедура ПоказатьБезопасноеСообщение(ТекстСообщения, ВремяОжиданияВСекундах = 15, ЗаголовокОкна = "Оповещение системы")
Попытка
Шелл = СоздатьОбъект("WScript.Shell");
// Параметры метода Popup:
// 1. Текст сообщения
// 2. Время автозакрытия в секундах
// 3. Заголовок окна
// 4. Тип иконки и кнопок (например, 48 — восклицательный знак, 0 — только кнопка ОК)
Шелл.Popup(ТекстСообщения, ВремяОжиданияВСекундах, ЗаголовокОкна, 48);
Исключение
// Резервный вариант, если COM-объект заблокирован политиками безопасности
Предупреждение(ТекстСообщения, ВремяОжиданияВСекундах);
КонецПопытки;
КонецПроцедуры
Используя этот метод в сочетании с фоновым опросом по таймеру (через ОбработкаОжидания() или FormEx), вы получите надежную, стабильную и безопасную систему отправки уведомлений пользователям 1С 7.7, которая никогда не заблокирует работу базы данных при монопольных операциях администратора.