Как передать сообщение пользователю в 1С:Предприятие 7.7?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

В платформе 1С:Предприятие 7.7 отсутствует современный встроенный механизм мгновенных push-уведомлений, к которому привыкли разработчики на платформе 1С 8.3. Тем не менее, задача оперативного информирования пользователей (например, о необходимости выйти из базы для проведения монопольного обновления или о получении нового заказа) возникает регулярно.

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

---

Решение 1. Проверка сообщений при запуске системы (Файловый метод)

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

Рассмотрим алгоритм реализации по шагам. Отправитель записывает текстовый файл, имя которого соответствует имени получателя, в специальный сетевой каталог. При запуске программы система проверяет наличие файла для текущего пользователя, считывает его, выводит на экран и удаляет.

Разберем пример кода для отправки сообщения:


Процедура ОтправитьФайловоеСообщение(ИмяПолучателя, ТекстСообщения)
    // Задаем каталог для хранения временных файлов сообщений
    КаталогСообщений = КаталогИБ() + "ExtFiles\Messages\";
    
    // Проверяем существование каталога, если его нет — создаем
    Если ФС.СуществуетФайл(КаталогСообщений) = 0 Тогда
        ФС.СоздатьКаталог(КаталогСообщений);
    КонецЕсли;
    
    // Имя файла будет соответствовать имени пользователя в системе
    ИмяФайла = КаталогСообщений + СокрЛП(ИмяПолучателя) + ".txt";
    
    Текст = СоздатьОбъект("Текст");
    Текст.ДобавитьСтроку(ТекстСообщения);
    
    Попытка
        Текст.Записать(ИмяФайла);
        Сообщить("Сообщение для пользователя " + ИмяПолучателя + " успешно отправлено.");
    Исключение
        Предупреждение("Не удалось отправить сообщение! Возможно, файл заблокирован.");
    КонецПопытки;
КонецПроцедуры

Теперь проанализируем код, который необходимо разместить в глобальном модуле в предопределенной процедуре ПриНачалеРаботыСистемы() для приема сообщения:


Процедура ПриНачалеРаботыСистемы()
    // ... существующий код начала работы ...
    
    // Проверяем наличие сообщений для текущего пользователя
    КаталогСообщений = КаталогИБ() + "ExtFiles\Messages\";
    ИмяФайла = КаталогСообщений + СокрЛП(ИмяПользователя()) + ".txt";
    
    Если ФС.СуществуетФайл(ИмяФайла) = 1 Тогда
        Текст = СоздатьОбъект("Текст");
        Попытка
            Текст.Открыть(ИмяФайла);
            КолСтрок = Текст.КоличествоСтрок();
            Если КолСтрок > 0 Тогда
                СтрокаСообщения = "";
                Для Ном = 1 По КолСтрок Цикл
                    СтрокаСообщения = СтрокаСообщения + Текст.ПолучитьСтроку(Ном) + РазделительСтрок;
                КонецЦикла;
                
                // Выводим сообщение пользователю
                Предупреждение("Вам оставлено системное сообщение:" + РазделительСтрок + СтрокаСообщения);
            КонецЕсли;
            
            // После прочтения обязательно удаляем файл, чтобы сообщение не выводилось повторно
            ФС.УдалитьФайл(ИмяФайла);
        Исключение
            // Обработка возможных ошибок блокировки файла при чтении/удалении
            ЗаписьЖурналаРегистрации("Ошибка чтения файла сообщения: " + ИмяФайла, "Система", "Ошибка", 3);
        КонецПопытки;
    КонецЕсли;
КонецПроцедуры

---

Решение 2. Использование служебного справочника и глобального таймера

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

Выясним, как это реализовать:

  1. Создадим в конфигураторе новый справочник с именем СообщенияПользователям.
  2. Добавим в него реквизиты:
    • Получатель (тип: Строка, длина 50) — для хранения имени адресата.
    • Отправитель (тип: Строка, длина 50) — имя того, кто отправил сообщение.
    • ТекстСообщения (тип: Строка, неограниченной длины).
    • Прочитано (тип: Число, длина 1, для флага прочтения).

В глобальном модуле настроим периодический запуск процедуры проверки новых записей. В процедуру ПриНачалеРаботыСистемы() добавим вызов обработчика ожидания:


Процедура ПриНачалеРаботыСистемы()
    // Запускаем проверку каждые 60 секунд (интервал можно регулировать)
    ОбработкаОжидания("глПроверитьНовыеСообщения", 60);
КонецПроцедуры

Затем в самом Глобальном модуле опишем процедуру проверки сообщений. Обратите внимание на директиву Экспорт, она обязательна для процедур, вызываемых через обработку ожидания:


Процедура глПроверитьНовыеСообщения() Экспорт
    // Создаем объект справочника для поиска непрочитанных сообщений
    Спр = СоздатьОбъект("Справочник.СообщенияПользователям");
    
    // Настраиваем выборку по реквизитам. 
    // Поскольку в 7.7 нет полноценных SQL-запросов "на лету" без сторонних ВК, 
    // выполним перебор элементов (или можно использовать метод НайтиПоРеквизиту)
    Спр.ВыбратьЭлементы();
    Пока Спр.ПолучитьЭлемент() = 1 Цикл
        Если (ВРег(СокрЛП(Спр.Получатель)) = ВРег(СокрЛП(ИмяПользователя()))) И (Спр.Прочитано = 0) Тогда
            
            // Получаем текст сообщения
            ТекстУведомления = "Сообщение от " + СокрЛП(Спр.Отправитель) + ":" + РазделительСтрок + Спр.ТекстСообщения;
            
            // Помечаем как прочитанное перед выводом окна, чтобы избежать зацикливания
            Спр.Прочитано = 1;
            Спр.Записать();
            
            // Показываем сообщение пользователю
            Предупреждение(ТекстУведомления);
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Важное предупреждение: Использование стандартного метода Предупреждение() имеет существенный недостаток. Это модальное окно. Если пользователь отошел от компьютера, а ему пришло сообщение, модальное окно заблокирует выполнение кода 1С. В результате программа не сможет выполнять другие фоновые задачи, а при необходимости административного завершения работы сессия этого пользователя зависнет.

---

Решение 3. Использование недокументированного метода Форма.ОбработкаОжидания()

Мало кто знает, что помимо глобального метода ОбработкаОжидания(), в 1С 7.7 существует локальный недокументированный метод контекста формы — Форма.ОбработкаОжидания().

Давайте проанализируем его особенности и преимущества перед глобальным аналогом:

Посмотрим на пример использования в модуле конкретной формы:


Процедура ПриОткрытии()
    // Запуск локального обработчика ожидания
    // Первый параметр — имя процедуры модуля данной формы, второй — интервал в секундах
    Форма.ОбработкаОжидания("ПроверитьЛокальныеУведомления", 30);
КонецПроцедуры

Процедура ПроверитьЛокальныеУведомления()
    // Код проверки входящих сообщений конкретно для этого рабочего места
    // ...
    // Если нужно отключить таймер программно, передаем интервал 0:
    // Форма.ОбработкаОжидания("ПроверитьЛокальныеУведомления", 0);
КонецПроцедуры

---

Решение 4. Использование внешней компоненты FormEx (Асинхронные события)

Для создания профессиональных решений обмена сообщениями без перегрузки сети и базы данных постоянными запросами разработчики часто используют внешнюю компоненту FormEx.

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

Рассмотрим, как это работает на практике:

  1. В процедуре запуска системы загружается внешняя компонента FormEx.dll.
  2. Взводится таймер через объект компоненты.
  3. При срабатывании таймера управление передается в процедуру глОбработкаВнешнегоСобытия() глобального модуля.

Пример реализации в Глобальном модуле:


Процедура ПриНачалеРаботыСистемы()
    Если ЗагрузитьВнешнююКомпоненту("FormEx.dll") = 1 Тогда
        Сервис = СоздатьОбъект("Сервис");
        // Взводим таймер с идентификатором "MessageTimer" на 60000 миллисекунд (1 минута)
        Сервис.ВзвестиТаймер("MessageTimer", 60000);
    Иначе
        Сообщить("Не удалось загрузить FormEx! Быстрые сообщения недоступны.", "!");
    EndIf;
КонецПроцедуры

Процедура глОбработкаВнешнегоСобытия(Источник, Событие, Данные) Экспорт
    Если (Источник = "Таймер") И (Событие = "MessageTimer") Тогда
        // Здесь мы пишем код быстрой проверки файлов сообщений или справочника
        // Так как это внешнее событие, оно не прерывает активный ввод пользователя
        
        КаталогСообщений = КаталогИБ() + "ExtFiles\Messages\";
        ИмяФайла = КаталогСообщений + СокрЛП(ИмяПользователя()) + ".txt";
        
        Если ФС.СуществуетФайл(ИмяФайла) = 1 Тогда
            // Найдено новое сообщение!
            // Для неблокирующего показа можно применить альтернативный вывод (см. Решение 5)
            // ... код обработки сообщения ...
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

---

Решение 5. Автозакрывающиеся окна через WScript.Shell

Чтобы решить проблему модальности стандартного окна Предупреждение(), о которой предупреждали опытные разработчики в обсуждении, мы можем использовать системный 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, которая никогда не заблокирует работу базы данных при монопольных операциях администратора.

← На главную