Как открыть несколько файлов по умолчанию в цикле 1С без потери данных и зависания интерфейса?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При разработке в среде 1С программисты часто сталкиваются с необходимостью автоматического открытия группы файлов внешними приложениями. Типичный сценарий: выгрузить из базы данных пакет изображений (например, сертификаты номенклатуры в формате JPG) или документов (в формате PDF) во временный каталог, после чего последовательно запустить их просмотр для пользователя.

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

Выясняем причину: почему операционная система игнорирует быстрые вызовы?

Проблема кроется не в платформе 1С, а в особенностях архитектуры Windows Shell (интерфейса запуска приложений) и логике работы современных программ просмотра графики и документов. Проанализируем ситуацию по шагам:

  1. Многопоточность и режим Single Instance (Один экземпляр). Большинство современных программ просмотра изображений (например, стандартное приложение «Фотографии» в Windows 10/11) или документов PDF запускаются по умолчанию в режиме одного процесса. При первой команде операционная система создает новый процесс приложения и загружает в него файл.
  2. Инициализация очереди сообщений. Когда код 1С мгновенно отправляет вторую, третью и последующие команды запуска в цикле (со скоростью работы процессора, то есть за миллисекунды), первое вызванное приложение еще физически не успело инициализировать свою внутреннюю очередь сообщений (Message Queue) и зарегистрировать свои системные интерфейсы (IPC, DDE или COM).
  3. Потеря системных вызовов. Операционная система пытается передать файлы уже «запущенному» процессу, но поскольку тот занят собственной инициализацией, эти вызовы попросту отбрасываются. В результате пользователь видит на экране только тот файл, который пробился сквозь системный шум первым или последним.

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

Способ 1. Синхронное ожидание (Простой метод с критическими минусами)

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


Для Каждого ПутьКФайлу Из МассивПутей Цикл
    // Третий параметр "Истина" заставляет 1С ждать закрытия файла
    ЗапуститьПриложение(ПутьКФайлу, , Истина);
КонецЦикла;

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

Этот способ гарантирует открытие абсолютно всех файлов без пропусков, однако он обладает критическими недостатками для интерфейса и удобства пользователя:

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

Способ 2. Очередь открытия через обработчик ожидания (Лучший выбор для обычных форм)

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

Во-первых, на уровне модуля нашей формы объявим переменную, в которой будем хранить список файлов, подлежащих открытию:

Перем МассивФайловДляОткрытия;

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


Процедура НачатьОткрытиеФайлов()
    
    // Заполняем массив путей к файлам, которые нужно открыть
    МассивФайловДляОткрытия = Новый Массив;
    МассивФайловДляОткрытия.Добавить("C:\Temp\image1.jpg");
    МассивФайловДляОткрытия.Добавить("C:\Temp\image2.jpg");
    МассивФайловДляОткрытия.Добавить("C:\Temp\image3.jpg");
    
    // Подключаем однократный обработчик ожидания с микропаузой (например, 0.4 секунды)
    ПодключитьОбработчикОжидания("ОткрытьОчереднойФайлИзОчереди", 0.4, Истина);
    
КонецПроцедуры

В-третьих, реализуем саму процедуру обработчика ожидания. Обратите внимание, что она должна быть объявлена с ключевым словом Экспорт:


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

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

Способ 3. Переход на асинхронные методы платформы 1С (Для управляемых форм)

При переходе конфигураций на управляемый интерфейс и веб-клиент использование синхронных вызовов становится невозможным. При попытке запустить код с параметром ожидания в режиме управляемого приложения платформа выдаст ошибку о запрете синхронных вызовов на клиенте. В современных версиях 1С (начиная с релиза 8.3.15) для решения этой проблемы были добавлены асинхронные аналоги.

Рассмотрим, как запустить приложение асинхронно с помощью метода НачатьЗапускПриложения. Этот метод выполняет работу в фоновом режиме, не замораживая интерфейс:


&НаКлиенте
Процедура ЗапуститьФайлыАсинхронно(МассивПутей)
    
    Для Каждого ПутьКФайлу Из МассивПутей Цикл
        
        // Создаем описание оповещения о завершении работы внешней программы
        ОписаниеОповещения = Новый ОписаниеОповещения("ПослеЗапускаПриложения", ЭтотОбъект, ПутьКФайлу);
        
        // Метод выполняет асинхронный запуск без ожидания завершения
        НачатьЗапускПриложения(ОписаниеОповещения, ПутьКФайлу);
        
    КонецЦикла;
    
КонецПроцедуры

&НаКлиенте
Процедура ПослеЗапускаПриложения(КодВозврата, ДополнительныеПараметры) Экспорт
    
    // В параметре "ДополнительныеПараметры" к нам вернется путь к файлу
    // Здесь можно обработать факт успешного или неуспешного открытия файла
    Если КодВозврата <> 0 Тогда
        ЗаписьЖурналаРегистрации("ЗапускПриложения", УровеньЖурналаРегистрации.Предупреждение, , , 
            "Не удалось запустить файл: " + ДополнительныеПараметры);
    КонецЕсли;
    
КонецПроцедуры

Использование этого подхода позволяет писать качественный код в стандартах современной разработки 1С, полностью готовый к работе в тонком клиенте и веб-интерфейсе.

Способ 4. Использование механизмов БСП (Универсальный и безопасный подход)

Если ваша конфигурация разработана с использованием Библиотеки стандартных подсистем (БСП), то ручной вызов методов вроде ЗапуститьПриложение напрямую из кода считается нарушением стандартов разработки. В БСП предусмотрен готовый, кроссплатформенный и безопасный механизм для запуска ассоциированных файлов. Для быстрой навигации по доступным клиентским процедурам подсистем пригодится справочник по методам БСП с примерами кода.

Рассмотрим пример открытия файлов с использованием общего модуля БСП:


Для Каждого ПутьКФайлу Из МассивПутей Цикл
    // Вызов безопасного метода БСП для открытия файла по умолчанию
    ФайловаяСистемаКлиент.ОткрытьФайл(ПутьКФайлу);
КонецЦикла;

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

  1. Кроссплатформенность. Метод автоматически определяет операционную систему клиента (Windows, Linux, macOS) и применяет соответствующий системный вызов без необходимости прописывать это в коде вручную.
  2. Безопасность. БСП осуществляет внутреннюю проверку расширений запускаемых файлов. Программа заблокирует попытку запуска вредоносных скриптов или исполняемых исполняемых модулей (таких как EXE, BAT, CMD, VBS), защищая компьютер пользователя.
  3. Оптимизация очередей. Механизмы БСП содержат встроенные алгоритмы по обработке системных ошибок инициализации просмотрщиков документов, что существенно снижает риск пропуска файлов при групповом открытии.

Способ 5. Передача файлов единым списком параметров запуска

Если на компьютерах пользователей установлены продвинутые сторонние программы для просмотра графики или PDF (например, IrfanView, FastStone Image Viewer, Adobe Acrobat Reader или Foxit Reader), мы можем воспользоваться возможностью передачи списка файлов через аргументы командной строки.

При таком подходе вместо запуска цикла мы формируем одну общую команду, которая запускает просмотрщик один раз и передает ему пути ко всем файлам одновременно. Программа откроет их во внутренних вкладках. Разберем пример реализации:


Процедура ОткрытьПакетКартинокЧерезПрограмму()
    
    // Путь к исполняемому файлу программы просмотра
    ПутьКПрограмме = """C:\Program Files\FastStone Image Viewer\FSViewer.exe""";
    
    // Формируем список параметров, где каждый путь обернут в двойные кавычки
    ПараметрыЗапуска = "";
    ПараметрыЗапуска = ПараметрыЗапуска + " ""C:\Temp\photo1.jpg""";
    ПараметрыЗапуска = ПараметрыЗапуска + " ""C:\Temp\photo2.jpg""";
    ПараметрыЗапуска = ПараметрыЗапуска + " ""C:\Temp\photo3.jpg""";
    
    // Полная строка команды для запуска
    СтрокаКоманды = ПутьКПрограмме + ПараметрыЗапуска;
    
    // Запускаем приложение один раз с набором параметров
    ЗапуститьПриложение(СтрокаКоманды);
    
КонецПроцедуры

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

Подводя итог, отметим: если вам необходимо быстро решить проблему в старой конфигурации на обычных формах, наиболее стабильным выбором будет Способ 2 (с обработчиком ожидания). Для современных конфигураций на управляемых формах всегда следует отдавать предпочтение Способу 4 (БСП) или асинхронным вызовам платформы.

← На главную