Как в 1С 7.7 программно нажать кнопку на форме документа, дождаться выполнения и закрыть его

Программист 1С v7.7
← На главную

При автоматизации массовых операций в 1С 7.7 программисты часто сталкиваются с архитектурной особенностью этой платформы: значительная часть бизнес-логики (например, формирование сообщений для МДЛП, заполнение сложных табличных частей или создание связанных справочников) может быть прописана непосредственно в модуле формы документа. Когда требуется выполнить такие действия в цикле для сотен документов, обычный программный вызов методов объекта не срабатывает, так как эти методы "видны" только внутри самой формы.

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

Почему стандартные методы часто не работают?

Проанализируем типичную ситуацию: программист пытается использовать WScript.Shell для эмуляции нажатия клавиш (например, SendKeys("{F12}")). Рассмотрим, почему это плохой путь:

  1. Отсутствие синхронизации: Команда SendKeys отправляет нажатие в активное окно Windows. Если форма документа открывается долго или фокус успел переключиться на другое приложение, нажатие уйдет "в никуда".
  2. Асинхронность открытия: В 1С 7.7 выполнение кода в цикле не прерывается открытием немодальной формы. Программа открывает окно и тут же переходит к следующей итерации цикла, не дожидаясь, пока в форме отработает какой-либо код.
  3. Блокировка объекта: Если форма открыта, объект считается заблокированным. Любая попытка вызвать Записать() из внешнего кода приведет к ошибке "Объект заблокирован".

Выясним причину ошибки "Поле агрегатного объекта не обнаружено". Она возникает при попытке вызвать процедуру модуля формы напрямую через объект документа (например, Док.МояПроцедура()). В 1С 7.7 процедуры модуля формы являются локальными и не доступны для вызова "через точку" извне, если не используются специальные расширения типа 1CPP.

Решение: Использование модального открытия с параметром

Наиболее стабильный способ без использования внешних компонент — это использование метода ОткрытьФормуМодально() с передачей специального контекста в качестве параметра. Разберем этот алгоритм по шагам.

Шаг 1. Подготовка вызывающего кода

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


// В цикле обработки документов
ДокУведомлениеМДЛП.Записать(); // Предварительно записываем документ
Конт = "ВыполнитьДействиеИЗакрыть";
// Открываем форму модально, передавая строку в качестве параметра
ОткрытьФормуМодально(ДокУведомлениеМДЛП.ТекущийДокумент(), Конт);

// Важно: после закрытия формы объект в переменной ДокУведомлениеМДЛП может стать неактуальным
// Если нужно продолжать работу с этим же документом, его нужно перечитать
ДокУведомлениеМДЛП.НайтиДокумент(ДокУведомлениеМДЛП.ТекущийДокумент());

Шаг 2. Модификация модуля формы документа

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


Процедура ПриОткрытии()
    // Проверяем, передан ли параметр
    Парам = Форма.Параметр;
    
    Если Парам = "ВыполнитьДействиеИЗакрыть" Тогда
        // 1. Вызываем нужную процедуру (ту, что висит на кнопке)
        СоздатьСообщениеПротоколаКОтправке();
        
        // 2. Записываем изменения, если процедура их внесла
        Записать();
        
        // 3. Отменяем открытие формы
        // СтатусВозврата(0) завершает работу формы, она даже не отобразится на экране
        СтатусВозврата(0);
        Возврат;
    КонецЕсли;
    
    // Обычная логика открытия формы для пользователя...
КонецПроцедуры

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

Как избежать блокировки объекта (ошибка "Объект заблокирован")

Типичная ошибка, которую совершают разработчики — попытка вызвать Док.Записать() в цикле сразу после ОткрытьФормуМодально(). Запомните: если внутри формы вы уже вызвали Записать(), то объект в основной обработке нужно обновить.

Рассмотрим ситуацию: при выполнении кода в форме создаются новые записи в справочниках и ссылка на одну из них записывается в реквизит документа. Если вы не выполните НайтиДокумент() после закрытия формы, ваша переменная ДокУведомлениеМДЛП будет содержать старые данные (состояние до открытия формы). Попытка записи такого объекта приведет либо к потере данных, либо к конфликту блокировок.

Профессиональный подход: использование FormEx или 1CPP

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

С помощью FormEx можно программно нажать кнопку на форме по её идентификатору, используя метод ВыполнитьКнопку(). Однако более элегантный способ предоставляет 1CPP. Если процедура в модуле формы объявлена с ключевым словом Экспорт, то при использовании расширения формы её можно вызвать напрямую.

Пример вызова через 1CPP (при условии Экспорта процедуры):


// Создаем расширение формы для доступа к её контексту
Сервис = СоздатьОбъект("Сервис");
КонтФормы = "";
ОткрытьФорму(Док.ТекущийДокумент(), КонтФормы);
// Получаем доступ к процедурам формы
Расширение = СоздатьОбъект("РасширениеФормы");
Расширение.УстановитьФорму(КонтФормы);
// Вызываем экспортную процедуру модуля формы
КонтФормы.СоздатьСообщениеПротоколаКОтправке();
КонтФормы.Форма.Закрыть(0);

Этот метод сложнее в реализации и требует наличия установленных DLL в системе, но он позволяет избежать модификации метода ПриОткрытии().

Рекомендации по проектированию

Проанализировав проблему, стоит отметить, что самый правильный путь с точки зрения архитектуры 1С — это вынос бизнес-логики из модуля формы в модуль объекта или в общую процедуру. Если код создания сообщения протокола будет находиться в модуле документа, вы сможете вызвать его простой командой Док.СоздатьСообщение() без всяких манипуляций с формами, окнами и эмуляцией нажатий.

Подведем итоги:

Следуя этим правилам, вы обеспечите надежную работу ваших алгоритмов массовой обработки документов в среде 1С:Предприятие 7.7.

← На главную